/*

 * This file is part of the openHiTLS project.

 *

 * openHiTLS is licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.

 * You may obtain a copy of Mulan PSL v2 at:

 *

 *     http://license.coscl.org.cn/MulanPSL2

 *

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,

 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,

 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.

 * See the Mulan PSL v2 for more details.

 */



#include "hitls_build.h"

#ifdef HITLS_CRYPTO_ENTROPY



#include <stdint.h>

#include <unistd.h>

#ifdef HITLS_CRYPTO_ENTROPY_DEVRANDOM

#include <fcntl.h>

#include <errno.h>

#endif

#ifdef HITLS_CRYPTO_ENTROPY_GETENTROPY

#include <sys/syscall.h>

#endif

#include <string.h>

#include "bsl_err_internal.h"

#include "crypt_errno.h"

#include "entropy_seed_pool.h"





uint32_t ENTROPY_SysEntropyGet(void *ctx, uint8_t *buf, uint32_t bufLen)

{

    (void)ctx;



#if defined(HITLS_CRYPTO_ENTROPY_GETENTROPY) || defined(HITLS_CRYPTO_ENTROPY_DEVRANDOM)

    uint32_t res = 0;

#if defined(HITLS_CRYPTO_ENTROPY_GETENTROPY)

    extern int getentropy (void *__buffer, size_t __length) __attribute__((weak));

    if (getentropy != NULL) {

        if (getentropy(buf, bufLen) == 0) {

            return bufLen;

        }

    }

#if defined(__NR_getrandom)

    long ret = syscall(__NR_getrandom, buf, bufLen, 0);

    if (ret > 0) {

        return (uint32_t)ret;

    }

#endif

#endif



#if defined(HITLS_CRYPTO_ENTROPY_DEVRANDOM)

    int32_t fd = open("/dev/random", O_RDONLY);

    if (fd == -1) {

        BSL_ERR_PUSH_ERROR(CRYPT_DRBG_FAIL_GET_ENTROPY);

        return 0;

    }

    uint32_t left = bufLen;

    uint8_t *tmp = buf;

    do {

        int32_t count = (int32_t)read(fd, tmp, left);

        if (count == -1 && errno == EINTR) {

            continue;

        } else if (count == -1) {

            break;

        }

        left -= (uint32_t)count;

        tmp += (uint32_t)count;

    } while (left > 0);

    close(fd);

    if (left > 0) {

        BSL_ERR_PUSH_ERROR(CRYPT_DRBG_FAIL_GET_ENTROPY);

    }

    res = bufLen - left;

#endif

    return res;

#else

    (void)buf;

    (void)bufLen;

    BSL_ERR_PUSH_ERROR(CRYPT_DRBG_FAIL_GET_ENTROPY);

    return 0;

#endif

}



#endif