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

#include "crypto.h"
#include "zlog_module.h"

#if 0
/**
 * Base64 字符串编码, 输出的Base64编码字符串使用换行对齐方式
 * @param pSrc
 * @return
 */
const char *base64_encode(unsigned char *pSrc, unsigned int sLen) {
    int            enSize   = 0;
    size_t         size;
    char           *pEncode = NULL;
    EVP_ENCODE_CTX *pCtx    = EVP_ENCODE_CTX_new();

    if (pCtx == NULL || pSrc == NULL || sLen == 0) {
        return (NULL);
    }

    size = ((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64;

    pEncode = (char *)malloc(size);
    memset(pEncode, 0, size);

    EVP_EncodeInit(pCtx);
    EVP_EncodeUpdate(pCtx, (unsigned char *)pEncode, &enSize, (const unsigned char *)pSrc, (int)strlen(pSrc));
    EVP_EncodeFinal(pCtx, (unsigned char *)(pEncode + enSize), &enSize);

//    fprintf(stdout, "Src: \n[%s]\n", pSrc);
//    fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode);

    EVP_ENCODE_CTX_free(pCtx);
    return pEncode;
}

/**
 * Base64 字符串解码, 输入的Base64编码字符串使用换行对齐方式
 * @param pBase64
 * @return
 */
unsigned char *base64_decode(const char *pBase64) {
    int            enSize   = 0;
    size_t         size     = 0;
    unsigned char  *pDecode = NULL;
    EVP_ENCODE_CTX *pCtx    = EVP_ENCODE_CTX_new();

    if (pCtx == NULL || pBase64 == NULL || strlen(pBase64) == 0) {
        return (NULL);
    }

    size    = strlen(pBase64);
    pDecode = (unsigned char *)malloc(size);
    memset(pDecode, 0, size);

    EVP_DecodeInit(pCtx);
    EVP_DecodeUpdate(pCtx, (unsigned char *)pDecode, &enSize, (const unsigned char *)pBase64, (int)strlen(pBase64));
    EVP_DecodeFinal(pCtx, (unsigned char *)(pDecode + enSize), &enSize);

//    fprintf(stdout, "Decode(%d --> %d) Bytes: \n[%s]\n", size, strlen(pDecode), pDecode);

    EVP_ENCODE_CTX_free(pCtx);
    return pDecode;
}
#endif

/**
 * Base64 字符串编码, 输出的Base64编码字符串未使用换行对齐方式
 * @param pSrc
 * @param sLen
 * @return
 */
const char *base64_encode(unsigned char *pSrc, unsigned int sLen) {
    int   size;
    char *pEncode = NULL;

    if (pSrc == NULL || sLen <= 0) {
        return (NULL);
    }

    size = (int)(((sLen / 3) * 4) + 4 + (sLen / 64) + sLen % 64);

    pEncode = (char *)malloc(size);
    memset(pEncode, 0, size);

    EVP_EncodeBlock((unsigned char *)pEncode, (const unsigned char *)pSrc, (int)sLen);
    //    fprintf(stdout, "Src: \n[%s]\n", pSrc);
    //    fprintf(stdout, "Base64(%d --> %d | %d) Bytes: \n[%s]\n", sLen, size, strlen(pEncode), pEncode);

    return pEncode;
}

/**
 * Base64 字符串解码, 输入的Base64编码字符串未使用换行对齐方式
 * @param pBase64
 * @param pOutSize
 * @return
 */
unsigned char *base64_decode(const char *pBase64, unsigned int *pOutSize) {
#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
    EVP_ENCODE_CTX ctx;
#else
    EVP_ENCODE_CTX *pCtx = EVP_ENCODE_CTX_new();
#endif
    int            enSize = 0;
    int            size;
    unsigned char *pDecode = NULL;

    if (pBase64 == NULL || strlen(pBase64) == 0) {
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
        EVP_ENCODE_CTX_free(pCtx);
#endif
        return (NULL);
    }

    size    = (int)strlen(pBase64);
    pDecode = (unsigned char *)malloc(size);
    memset(pDecode, 0, size);

#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
    EVP_DecodeInit(&ctx);
    EVP_DecodeUpdate(&ctx, pDecode, &enSize, (const unsigned char *)pBase64, strlen(pBase64));
#else
    EVP_DecodeInit(pCtx);
    if (EVP_DecodeUpdate(pCtx, pDecode, &enSize, (const unsigned char *)pBase64, size) == -1) {
        LOG_MOD(error, ZLOG_MOD_CRYPTO, "Decode [%s] error\n", pBase64);
        free(pDecode);
        return NULL;
    }
#endif
    if (pOutSize) {
        *pOutSize = enSize;
    }

#if !defined(OPENSSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
    EVP_DecodeFinal(&ctx, pDecode + enSize, &size);
#else
    if (EVP_DecodeFinal(pCtx, pDecode, &enSize) == -1) {
        LOG_MOD(error, ZLOG_MOD_CRYPTO, "Finish decode [%s] error\n", pBase64);
        free(pDecode);
        return NULL;
    }

    EVP_ENCODE_CTX_free(pCtx);
#endif

    return pDecode;
}