#include "stm32f10x.h"
#include "mbedtls_util.h"
#include <string.h>
#include "mbedtls/sha1.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "mbedtls/cipher.h"
#include "mbedtls/base64.h"
#include "sys.h"
#include <stdio.h>

#define KEY_IOPAD_SIZE 64

#define SHA1_DIGEST_SIZE 20

#define SHA256_DIGEST_SIZE 32

#define AES_LEN_SIZE 256

#define AES_BLOCK_SIZE 16


/**
* 填充源码,返回填充后的数据长度
*/
static int fillAESPKCS7Data(char* data)
{
	int left= 0;
	int len = strlen(data);
	if(len%AES_BLOCK_SIZE != 0)
	{
		left = AES_BLOCK_SIZE-strlen(data)%AES_BLOCK_SIZE;
		
	}
	else
	{
		left = AES_BLOCK_SIZE;
	}
	memset(data+strlen(data),left,left);
	len+=left;
	return len;
}

/**
* 去除源码无效数据
*/
static void cutAESPKCS7Data(char* data)
{
	int i= 0;
	int size = strlen(data);
	for(i=size-1;data[i]>0&&data[i]<AES_BLOCK_SIZE;i--)
	{
		data[i]=0;
	}

}

void utils_hmac_sha1_str(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
	//对函数参数判空
    if((NULL == msg) || (NULL == digest) || (NULL == key)) {
        return;
    }
	//限制密钥长度
    if(key_len > KEY_IOPAD_SIZE) {
        return;
    }
	//hmac sha1加密处理
    mbedtls_sha1_context context;
    unsigned char k_ipad[KEY_IOPAD_SIZE];    /* inner padding - key XORd with ipad  */
    unsigned char k_opad[KEY_IOPAD_SIZE];    /* outer padding - key XORd with opad */
    unsigned char out[SHA1_DIGEST_SIZE];
    int i;

    /* start out by storing key in pads */
    memset(k_ipad, 0, sizeof(k_ipad));
    memset(k_opad, 0, sizeof(k_opad));
    memcpy(k_ipad, key, key_len);
    memcpy(k_opad, key, key_len);

    /* XOR key with ipad and opad values */
    for (i = 0; i < KEY_IOPAD_SIZE; i++) {
        k_ipad[i] ^= 0x36;
        k_opad[i] ^= 0x5c;
    }

    /* perform inner MD5 */
    mbedtls_sha1_init(&context);                                      /* init context for 1st pass */
    mbedtls_sha1_starts(&context);                                    /* setup context for 1st pass */
    mbedtls_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE);            /* start with inner pad */
    mbedtls_sha1_update(&context, (unsigned char *) msg, msg_len);    /* then text of datagram */
    mbedtls_sha1_finish(&context, out);                               /* finish up 1st pass */

    /* perform outer MD5 */
    mbedtls_sha1_init(&context);                              /* init context for 2nd pass */
    mbedtls_sha1_starts(&context);                            /* setup context for 2nd pass */
    mbedtls_sha1_update(&context, k_opad, KEY_IOPAD_SIZE);    /* start with outer pad */
    mbedtls_sha1_update(&context, out, SHA1_DIGEST_SIZE);      /* then results of 1st hash */
    mbedtls_sha1_finish(&context, out);                       /* finish up 2nd pass */
    
	//加密后的数据16进制输出
		byteToHexStr(out,digest,SHA1_DIGEST_SIZE);
		
}

void utils_sha256(const char *msg, int msg_len, char *digest)
{

		//hmac sha1加密处理
    mbedtls_sha256_context context;

    /* perform inner MD5 */
    mbedtls_sha256_init(&context);                                      /* init context for 1st pass */
    mbedtls_sha256_starts(&context,0);                                    /* setup context for 1st pass */
    mbedtls_sha256_update(&context, (unsigned char *) msg, msg_len);    /* then text of datagram */
    mbedtls_sha256_finish(&context, digest);                               /* finish up 1st pass */
    
}

void utils_sha256_str(const char *msg, int msg_len, char *digest)
{

		//hmac sha1加密处理
    mbedtls_sha256_context context;
    unsigned char out[SHA256_DIGEST_SIZE];
	
		utils_sha256(msg,msg_len,out);
    
	//加密后的数据16进制输出
		byteToHexStr(out,digest,SHA256_DIGEST_SIZE);
		
}

/**
*AES CBC加密 ， plaintext:源数据,ciphertext:加密数据, 返回加密长度
*/
int utils_aes128_cbc_enc(char *aes_key, char *iv, char *plaintext, char *ciphertext)
{

		int i;
		char iv_use[16] = {0};
		char data[AES_LEN_SIZE]= {0};
		mbedtls_aes_context aes_ctx;
		if(strlen(plaintext)+16 > AES_LEN_SIZE) return 0;
		memcpy(iv_use,iv,16);
		memcpy(data,plaintext,strlen(plaintext));
    int len = fillAESPKCS7Data(data);
    
    mbedtls_aes_init(&aes_ctx);
    //setkey_dec
    mbedtls_aes_setkey_enc(&aes_ctx, aes_key, 128);
		mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, len, iv_use, data, ciphertext);
    
    mbedtls_aes_free(&aes_ctx);
    return len; //OK

}

/**
*AES CBC解密 ciphertext:加密数据， len:加密数据长度，plaintext:解密到的数据
*/
int utils_aes128_cbc_dec(char *aes_key, char *iv, char *ciphertext, int len, char *plaintext)
{

		int i;
		char iv_use[16] = {0};
		mbedtls_aes_context aes_ctx;
		if(len%16&&len>AES_LEN_SIZE) return 0;
		memcpy(iv_use,iv,16);
    mbedtls_aes_init(&aes_ctx);
    //setkey_dec
    mbedtls_aes_setkey_dec(&aes_ctx, aes_key, 128);
		mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, len, iv_use, ciphertext, plaintext);
    cutAESPKCS7Data(plaintext);
    mbedtls_aes_free(&aes_ctx);
    return strlen(plaintext); //OK

}

/**
*AES CBC加密 ， src:源数据,dataLen:数据长度,ciphertext:加密数据, 返回加密长度
*/
int utils_aes128_cbc_base64_enc(char *aes_key, char *iv, uint8_t *src,int dataLen, char *ciphertext)
{

		size_t len;
    unsigned char buffer[AES_LEN_SIZE*2]={0};
		
		if(dataLen+16 > AES_LEN_SIZE) return 0;
		
		int ret = mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, dataLen );
		printf("base64_encode:%s\r\n",buffer);
		if(ret)
		{
			printf("base64 encode err:%d",ret);
			return 0;
		}
		return utils_aes128_cbc_enc(aes_key,iv,buffer,ciphertext);
		
}

/**
*AES CBC解密 ciphertext:加密数据， len:加密数据长度，plaintext:解密到的数据
*/
int utils_aes128_cbc_base64_dec(char *aes_key, char *iv, char *ciphertext, int dataLen, char *plaintext,int plainLen)
{
		size_t len = 0;
    unsigned char buffer[AES_LEN_SIZE*2]={0};
		int retlen = utils_aes128_cbc_dec(aes_key,iv,ciphertext,dataLen,buffer);
		if(retlen)
		{
			printf("base64_encode2:%s\r\n",buffer);
			int ret = mbedtls_base64_decode( plaintext, plainLen, &len, buffer, retlen);
			if(ret)
			{
				printf("base64 decode err:%d,%d",ret,retlen);
				len = 0;
			}
		}
		return len;
}
