//
// Created by xajhu on 2021/7/2 0002.
//
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <openssl/aes.h>
#include <openssl/evp.h>

#include "crypto.h"
#include "misc.h"
#include "user_errno.h"
#include "zlog_module.h"

/**
 * 计算文件MD5值
 * @param pFileName
 * @param md5
 * @return
 */
int hash_digest_file(HASH_TYPE hashType, const char *pFileName, char **pHashValue) {
    unsigned int rdSize = 0;
    int          fd;
    uint8_t      hashValue[EVP_MAX_MD_SIZE];
    uint8_t      buf[1024];
    EVP_MD_CTX  *pCtx;

    if (pHashValue == NULL) {
        return (-ERR_INPUT_PARAMS);
    }

    memset(hashValue, 0, EVP_MAX_MD_SIZE);

    pCtx = EVP_MD_CTX_create();

    if (!pCtx) {
        return -ERR_EVP_CREATE_CTX;
    }

    EVP_MD_CTX_init(pCtx);

    switch (hashType) {
        case HASH_TYPE_MD5:
            EVP_DigestInit_ex(pCtx, EVP_md5(), NULL);
            break;
        case HASH_TYPE_SHA1:
            EVP_DigestInit_ex(pCtx, EVP_sha1(), NULL);
            break;
        case HASH_TYPE_SHA256:
            EVP_DigestInit_ex(pCtx, EVP_sha256(), NULL);
            break;
        default:
            EVP_MD_CTX_destroy(pCtx);
            return (-ERR_INPUT_PARAMS);
    }

    fd = open(pFileName, O_RDONLY);

    if (fd == -1) {
        LOG_MOD(error, ZLOG_MOD_CRYPTO, "Open File %s error\n", pFileName);
        EVP_MD_CTX_destroy(pCtx);
        return (-ERR_OPEN_FILE);
    }

    do {
        rdSize = read(fd, buf, 1024);
        EVP_DigestUpdate(pCtx, buf, rdSize);
    } while (rdSize > 0);

    close(fd);

    EVP_DigestFinal_ex(pCtx, hashValue, &rdSize);
    EVP_MD_CTX_destroy(pCtx);

    *pHashValue = (char *)malloc(EVP_MAX_MD_SIZE * 2 + 1);

    if (*pHashValue == NULL) {
        return (-ERR_MALLOC_MEMORY);
    }

    memset(*pHashValue, 0, EVP_MAX_MD_SIZE * 2 + 1);

    bin2hex(*pHashValue, hashValue, rdSize);

    return ERR_SUCCESS;
}

/**
 * 计算缓存中的数据的 Hash 值
 * @param pBuf
 * @param iBufLen
 * @param pHashValue
 * @return
 */
int hash_digest_mem(HASH_TYPE            hashType,
                    const unsigned char *pBuf,
                    unsigned int         iBufLen,
                    unsigned char      **pHashValue,
                    unsigned int        *pOutSize) {
    EVP_MD_CTX *pCtx;

    if (pHashValue == NULL || pBuf == NULL || pOutSize == NULL) {
        return (-ERR_INPUT_PARAMS);
    }

    *pHashValue = (unsigned char *)malloc(EVP_MAX_MD_SIZE);

    if (*pHashValue == NULL) {
        *pOutSize = 0;
        return -ERR_MALLOC_MEMORY;
    }

    memset(*pHashValue, 0, EVP_MAX_MD_SIZE);

    pCtx = EVP_MD_CTX_create();
    if (!pCtx) {
        *pOutSize = 0;
        return -ERR_EVP_CREATE_CTX;
    }

    EVP_MD_CTX_init(pCtx);

    switch (hashType) {
        case HASH_TYPE_MD5:
            EVP_DigestInit_ex(pCtx, EVP_md5(), NULL);
            break;
        case HASH_TYPE_SHA1:
            EVP_DigestInit_ex(pCtx, EVP_sha1(), NULL);
            break;
        case HASH_TYPE_SHA256:
            EVP_DigestInit_ex(pCtx, EVP_sha256(), NULL);
            break;
        default:
            EVP_MD_CTX_destroy(pCtx);
            return (-ERR_INPUT_PARAMS);
    }
    EVP_DigestUpdate(pCtx, pBuf, iBufLen);
    EVP_DigestFinal_ex(pCtx, *pHashValue, pOutSize);

    EVP_MD_CTX_destroy(pCtx);

    return ERR_SUCCESS;
}