security
hmac_sha256.c
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
*
* @author 霍长裕
* @email huocy@midea.com
* @date 2021-01-01 10:30
* @des net work
*/
#include "hmac_sha256.h"
#include <stdlib.h>
#include <string.h>
#define SHA256_BLOCK_SIZE 64
static void* H(const void* x,
const size_t xlen,
const void* y,
const size_t ylen,
void* out,
const size_t outlen);
static void* sha256(const void* data,
const size_t datalen,
void* out,
const size_t outlen);
size_t midea_hmac_sha256(const void* key,
const size_t keylen,
const void* data,
const size_t datalen,
void* out,
const size_t outlen) {
uint8_t k[SHA256_BLOCK_SIZE];
uint8_t k_ipad[SHA256_BLOCK_SIZE];
uint8_t k_opad[SHA256_BLOCK_SIZE];
uint8_t ihash[SHA256_HASH_SIZE];
uint8_t ohash[SHA256_HASH_SIZE];
size_t sz;
int i;
memset(k, 0, sizeof(k));
memset(k_ipad, 0x36, SHA256_BLOCK_SIZE);
memset(k_opad, 0x5c, SHA256_BLOCK_SIZE);
if (keylen > SHA256_BLOCK_SIZE) {
// If the key is larger than the hash algorithm's
// block size, we must digest it first.
sha256(key, keylen, k, sizeof(k));
} else {
memcpy(k, key, keylen);
}
for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
k_ipad[i] ^= k[i];
k_opad[i] ^= k[i];
}
// Perform HMAC algorithm: ( https://tools.ietf.org/html/rfc2104 )
// `H(K XOR opad, H(K XOR ipad, data))`
H(k_ipad, sizeof(k_ipad), data, datalen, ihash, sizeof(ihash));
H(k_opad, sizeof(k_opad), ihash, sizeof(ihash), ohash, sizeof(ohash));
sz = (outlen > SHA256_HASH_SIZE) ? SHA256_HASH_SIZE : outlen;
memcpy(out, ohash, sz);
return sz;
}
static void* H(const void* x,
const size_t xlen,
const void* y,
const size_t ylen,
void* out,
const size_t outlen) {
void* result;
size_t buflen = (xlen + ylen);
uint8_t* buf = (uint8_t*)malloc(buflen);
memcpy(buf, x, xlen);
memcpy(buf + xlen, y, ylen);
result = sha256(buf, buflen, out, outlen);
free(buf);
return result;
}
static void* sha256(const void* data,
const size_t datalen,
void* out,
const size_t outlen) {
size_t sz;
Sha256Context ctx;
SHA256_HASH hash;
Sha256Initialise(&ctx);
Sha256Update(&ctx, data, datalen);
Sha256Finalise(&ctx, &hash);
sz = (outlen > SHA256_HASH_SIZE) ? SHA256_HASH_SIZE : outlen;
return memcpy(out, hash.bytes, sz);
}
hmac_sha256.h
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
*
* @author 霍长裕
* @email huocy@midea.com
* @date 2021-01-01 10:30
* @des hmac
*/
#ifndef _HMAC_SHA256_H_
#define _HMAC_SHA256_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <stddef.h>
#include "midea_sha256_1.h"
size_t // Returns the number of bytes written to `out`
midea_hmac_sha256(
const void* key,
const size_t keylen,
const void* data,
const size_t datalen,
void* out,
const size_t outlen);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _HMAC_SHA256_H_
midea_data_security.c
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
*
* @author 霍长裕
* @email huocy@midea.com
* @date 2021-01-06 10:30
* @des 加密类
*/
#include "midea_data_security.h"
#include "midea_hmac_sha256.h"
#include "mbedtls/md5.h"
#include "mbedtls/aes.h"
#include "mbedtls/sha256.h"
#include "mbedtls/md.h"
#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/ecp.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform.h"
#define AES128_BLOCK_SIZE 16
int mss_md5_encrypt_to_lc_hex(uint8_t data[], size_t data_size, char **out)
{
unsigned char decrypt[16];
mbedtls_md5_context md5_ctx;
mbedtls_md5_init(&md5_ctx);
mbedtls_md5_starts(&md5_ctx);
mbedtls_md5_update(&md5_ctx, data, data_size);
mbedtls_md5_finish(&md5_ctx, decrypt);
char *tmp = calloc(33, sizeof(char));
for (int i = 0; i < 16; i++)
{
char t[3] = {0};
sprintf(t, "%02x", decrypt[i]);
strcat(tmp, t);
}
mbedtls_md5_free(&md5_ctx);
*out = tmp;
return 0;
}
int mss_md5_encrypt(uint8_t data[], size_t data_size, uint8_t **out, size_t *out_size)
{
uint8_t *decrypt = calloc(16, sizeof(uint8_t));
mbedtls_md5_context md5_ctx;
mbedtls_md5_init(&md5_ctx);
mbedtls_md5_starts(&md5_ctx);
mbedtls_md5_update(&md5_ctx, data, data_size);
mbedtls_md5_finish(&md5_ctx, decrypt);
mbedtls_md5_free(&md5_ctx);
*out = decrypt;
*out_size = 16;
return 0;
}
mss_aes128_result mss_crypto_aes128_ecrypt(uint8_t *data, size_t *len, const uint8_t *key, const uint8_t encrypt_type)
{
int i, ret;
size_t blocks = *len / AES128_BLOCK_SIZE;
size_t rest_size = *len % AES128_BLOCK_SIZE;
uint8_t temp_data[AES128_BLOCK_SIZE];
uint8_t *data_offset_ptr = data;
mbedtls_aes_context aes_ctx;
unsigned char iv[16];
switch (encrypt_type)
{
case 0x00:
// Set AES128 key
if (mbedtls_aes_setkey_enc(&aes_ctx, key, 128) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Encrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = (uint16_t)AES128_BLOCK_SIZE - rest_size;
memset(data + *len, (uint8_t)rest_size, (size_t)rest_size);
if (mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
*len += rest_size;
ret = MS_AES128_RESULT_SUCCESS;
break;
case 0x01:
{
memset(iv, 0, 16);
mbedtls_aes_init(&aes_ctx);
// Set AES128 key
if (mbedtls_aes_setkey_enc(&aes_ctx, key, 128) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Encrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, AES128_BLOCK_SIZE, iv, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = (uint16_t)AES128_BLOCK_SIZE - rest_size;
memset(data + *len, (uint8_t)rest_size, (size_t)rest_size);
if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, AES128_BLOCK_SIZE, iv, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
*len += rest_size;
ret = MS_AES128_RESULT_SUCCESS;
}
break;
default:
ret = MS_AES128_RESULT_ERROR;
break;
}
mbedtls_aes_free(&aes_ctx);
return (mss_aes128_result)ret;
}
mss_aes128_result mss_crypto_aes128_ecrypt_h(uint8_t *data, size_t len, const uint8_t *key, const uint8_t encrypt_type,
uint8_t **output,size_t *output_size)
{
uint8_t *tmp_data=calloc(len+16,sizeof(uint8_t));
memcpy(tmp_data,data,len);
int i, ret;
size_t blocks = len / AES128_BLOCK_SIZE;
size_t rest_size = len % AES128_BLOCK_SIZE;
uint8_t temp_data[AES128_BLOCK_SIZE];
uint8_t *data_offset_ptr = tmp_data;
mbedtls_aes_context aes_ctx;
unsigned char iv[16];
switch (encrypt_type)
{
case 0x00:
// Set AES128 key
if (mbedtls_aes_setkey_enc(&aes_ctx, key, 128) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Encrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = (uint16_t)AES128_BLOCK_SIZE - rest_size;
memset(tmp_data + len, (uint8_t)rest_size, (size_t)rest_size);
if (mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
*output_size= len +rest_size;
*output=tmp_data;
ret = MS_AES128_RESULT_SUCCESS;
break;
case 0x01:
{
memset(iv, 0, 16);
mbedtls_aes_init(&aes_ctx);
// Set AES128 key
if (mbedtls_aes_setkey_enc(&aes_ctx, key, 128) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Encrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, AES128_BLOCK_SIZE, iv, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = (uint16_t)AES128_BLOCK_SIZE - rest_size;
memset(tmp_data + len, (uint8_t)rest_size, (size_t)rest_size);
if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, AES128_BLOCK_SIZE, iv, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
*output_size= len +rest_size;
*output=tmp_data;
ret = MS_AES128_RESULT_SUCCESS;
}
break;
default:
ret = MS_AES128_RESULT_ERROR;
break;
}
mbedtls_aes_free(&aes_ctx);
return (mss_aes128_result)ret;
}
mss_aes128_result mss_crypto_aes128_decrypt(uint8_t *data, size_t *len, const uint8_t *key, const uint8_t decrypt_type)
{
int i, ret;
size_t blocks = *len / AES128_BLOCK_SIZE;
size_t rest_size = *len % AES128_BLOCK_SIZE;
uint8_t temp_data[AES128_BLOCK_SIZE];
uint8_t *data_offset_ptr = data;
mbedtls_aes_context aes_ctx;
unsigned char iv[16];
if (rest_size != 0)
{
return MS_AES128_RESULT_ERROR;
}
switch (decrypt_type)
{
case 0x00:
// Set AES128 key
if (mbedtls_aes_setkey_dec(&aes_ctx, key, 128) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Decrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, data_offset_ptr, temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = data[(*len) - 1];
if (rest_size > 16 || rest_size == 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
*len -= rest_size;
memset(data + *len, 0, (size_t)rest_size);
ret = MS_AES128_RESULT_SUCCESS;
break;
case 0x01:
{
memset(iv, 0, 16);
mbedtls_aes_init(&aes_ctx);
// Set AES128 key
ret = mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
if (ret != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
// Decrypt AES128
for (i = 0; i < blocks; i++)
{
if (mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, AES128_BLOCK_SIZE, (uint8_t *)iv, (uint8_t *)data_offset_ptr, (uint8_t *)temp_data) != 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
memcpy(data_offset_ptr, temp_data, AES128_BLOCK_SIZE);
data_offset_ptr += AES128_BLOCK_SIZE;
}
// PKCS5_Padding
rest_size = data[(*len) - 1];
if (rest_size > 16 || rest_size == 0)
{
ret = MS_AES128_RESULT_ERROR;
break;
}
*len -= rest_size;
memset(data + *len, 0, (size_t)rest_size);
mbedtls_aes_free(&aes_ctx);
ret = MS_AES128_RESULT_SUCCESS;
}
break;
default:
ret = MS_AES128_RESULT_ERROR;
break;
}
mbedtls_aes_free(&aes_ctx);
return (mss_aes128_result)ret;
}
int mss_hmac_sha256_to_lc_hex(const void *key,const size_t key_size,const void *data,const size_t data_size,char **output)
{
uint8_t out[SHA256_HASH_SIZE];
char *out_str = calloc(SHA256_HASH_SIZE * 2 + 1, sizeof(char));
unsigned i;
midea_hmac_sha256(key, key_size, data, data_size, &out, sizeof(out));
for (i = 0; i < 32; i++)
{
char t[3] = {0};
sprintf(t, "%02x", out[i]);
strcat(out_str, t);
}
*output = out_str;
return 0;
}
int mss_sha256(uint8_t *input, size_t input_size, uint8_t **hash_value, size_t *hash_value_size)
{
int ret = 0;
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
do
{
/* SHA-256 */
if ((ret = mbedtls_sha256_starts_ret(&ctx, 0)) != 0)
{
mbedtls_sha256_free(&ctx);
break;
}
ret = mbedtls_sha256_update_ret(&ctx, input, input_size);
if (ret != 0)
{
mbedtls_sha256_free(&ctx);
break;
}
uint8_t *password_sha256_out = calloc(32, sizeof(uint8_t));
if (password_sha256_out == NULL)
{
return -1;
// return get_error_code(BC_OTHER, SRC_SDK, CODE_ALLOC_MEMORY_FAILED);
}
if ((ret = mbedtls_sha256_finish_ret(&ctx, password_sha256_out)) != 0)
{
mbedtls_sha256_free(&ctx);
break;
}
*hash_value = password_sha256_out;
*hash_value_size = 32;
mbedtls_sha256_free(&ctx);
} while (0);
return (ret);
}
int mss_sha256_to_lc_hex(uint8_t *input, size_t input_size, char **hex_hash_value)
{
uint8_t *hash_value;
size_t hash_value_size=0;
int ret=mss_sha256(input,input_size,&hash_value,&hash_value_size);
if(ret != 0){
return ret;
}
ret=midea_bytes_to_lc_hex_string(hash_value,hash_value_size,hex_hash_value);
if(ret != 0){
return ret;
}
free(hash_value);
return 0;
}
/**
* @brief ecdh 算法生成共享密钥(用于密钥协商)。类存储外设公钥
*
* @param device_publicKey 外设公钥
* @param finalKey 输出共享密钥buf。
* @return int
*/
int mss_ecdh_shared_finalKey(uint8_t * finalKey,uint8_t * device_publicKey,uint8_t * client_publicKey){
/** APP向模组请求ECDH公钥A ;模组返回ECDH公钥A;APP将公钥A与自身生成的ECDH私钥生成共享会话密钥,用该会话密钥加密验证密文。将APP的ECDH公钥B与验证密文一起用初始默认密钥加密,发送给模组*/
int ret = 0;
mbedtls_ecp_group grp;
mbedtls_mpi cli_secret;
mbedtls_mpi cli_pri;
mbedtls_ecp_point cli_pub, srv_pub;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
const char *pers = "simple_ecdh";
mbedtls_mpi_init(&cli_pri); //初始化客户端私钥
mbedtls_mpi_init(&cli_secret);//初始化云端公钥和客户端私钥生成的共享密钥
mbedtls_ecp_group_init(&grp); //初始化椭圆曲线群结构体
mbedtls_ecp_point_init(&cli_pub); //初始化椭圆曲线点结构体 客户端公钥
mbedtls_ecp_point_init(&srv_pub);//初始化椭圆曲线点结构体 设备端公钥
mbedtls_entropy_init(&entropy); //初始化熵结构体
mbedtls_ctr_drbg_init(&ctr_drbg);//初始化随机数结构体
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const uint8_t *) pers, strlen(pers));
//加载椭圆曲线,选择SECP256R1
ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
if(ret != 0){
return ret;
}
//客户端生成公开参数
ret = mbedtls_ecdh_gen_public(&grp, //椭圆曲线结构体
&cli_pri,//输出cli私密参数d
&cli_pub,//输出cli公开参数Q
mbedtls_ctr_drbg_random, &ctr_drbg);
if(ret != 0){
return ret;
}
unsigned char client_publicKey_buf[65];
size_t client_publicKey_olen;
//将客户端的公开参数(一个点Q)导出为(公钥)无符号二进制数据
mbedtls_ecp_point_write_binary(&grp, &cli_pub,
MBEDTLS_ECP_PF_UNCOMPRESSED, &client_publicKey_olen, client_publicKey_buf, sizeof(client_publicKey_buf));
//去掉首字节04,后面的64字节作为客户端ECDH公钥二进制传给设备
memcpy(client_publicKey, &client_publicKey_buf[1], 64);
//第一个字节手动设置为04
unsigned char device_pub_keys[65];
device_pub_keys[0] = 0x04;
//后面64个字节为设备传过来的ecdh公钥
memcpy(&device_pub_keys[1], device_publicKey, 64);
//从设备端的device_publicKey无符号二进制数据导入为公开参数(一个点 Q)
mbedtls_ecp_point_read_binary(&grp, &srv_pub, device_pub_keys, 65);
//根据客户端的私钥d和设备端的Q 客户端计算共享密钥
ret = mbedtls_ecdh_compute_shared(&grp, //椭圆曲线结构体
&cli_secret, //客户端计算出的共享密钥
&srv_pub, //输入设备端公开参数Q
&cli_pri, //输入客户端本身的私密参数d
mbedtls_ctr_drbg_random, &ctr_drbg);
if(ret != 0){
return ret;
}
//把客户端计算出的共享密钥导出buf中
unsigned char client_secret_buf[65];
ret = mbedtls_mpi_write_binary(&cli_secret, client_secret_buf, mbedtls_mpi_size(&cli_secret));
if(ret != 0){
return ret;
}
memcpy(finalKey, &client_secret_buf[0], 16);
cleanup:
mbedtls_mpi_free(&cli_pri);
mbedtls_mpi_free(&cli_secret);
mbedtls_ecp_group_free(&grp);
mbedtls_ecp_point_free(&cli_pub);
mbedtls_ecp_point_free(&srv_pub);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
return 0;
}
midea_data_security.h
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
*
* @author 霍长裕
* @email huocy@midea.com
* @date 2021-01-06 10:30
* @des 加密类
*/
#ifndef ms_data_security_h
#define ms_data_security_h
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "midea_hmac_sha256.h"
#include "mbedtls/aes.h"
#include "mbedtls/md5.h"
#include "mbedtls/sha256.h"
#include "mbedtls/md.h"
#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
typedef enum
{
MS_AES128_RESULT_SUCCESS = 0,
MS_AES128_RESULT_ERROR = 1,
}mss_aes128_result;
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
/**
* @brief 使用md5加密,返回16进制字符串,需要释放。
*
* @param data 输入子节
* @param out 输出 ,需要释放。
* @return int
*/
int mss_md5_encrypt_to_lc_hex(uint8_t data[], size_t data_size, char **out);
int mss_md5_encrypt(uint8_t data[], size_t data_size, uint8_t **out ,size_t *out_size);
///AES加解密
///data:The address of the source data will decrypt and after decrypted sucessful,the decrypted data will store in the same address
///len:The length of the data will be decrypted and after decrypted sucessful,it will be the decrypted sucessful data length
///key:the key used to decrypted
///decrypt_type:0:ECB, 1:CBC
mss_aes128_result mss_crypto_aes128_ecrypt(uint8_t *data, size_t *len, const uint8_t *key, const uint8_t encrypt_type);
mss_aes128_result mss_crypto_aes128_decrypt(uint8_t *data, size_t *len, const uint8_t *key, const uint8_t decrypt_type);
/**
* @brief AES128加密
*
* @param data 加密数据
* @param len 长度
* @param key 加密key
* @param encrypt_type 加密类型
* @param output 输出加密后的结果 需要自己管理释放
* @param output_size 加密后数据长度
* @return int
*/
mss_aes128_result mss_crypto_aes128_ecrypt_h(uint8_t *data, size_t len, const uint8_t *key, const uint8_t encrypt_type,
uint8_t **output,size_t *output_size);
/**
* @brief HMAC-SHA256,输出小写16进制字符串,需要释放内存
*
* @param key 密钥
* @param key_size 密钥长度
* @param data 数据
* @param data_size 数据长度
* @param output 输出小写16进制字符串
* @return int
*/
int mss_hmac_sha256_to_lc_hex(const void *key,const size_t key_size,const void *data,const size_t data_size,char **output);
/**
* @brief sha256 ,返回子节数组,需要释放内存
*
* @param input 输入子节
* @param len 输入子节长度
* @param hash_value hash值
* @param hash_value_size hash值长度
* @return int 0:成功
*/
int mss_sha256(uint8_t *input, size_t input_size, uint8_t **hash_value, size_t *hash_value_size);
/**
* @brief sha256 ,返回小写16进制字符串,需要释放内存
*
* @param input 输入子节
* @param input_size 输入子节长度
* @param hex_hash_value 小写16进制字符串
* @return int
*/
int mss_sha256_to_lc_hex(uint8_t *input, size_t input_size, char **hex_hash_value);
/**
* @brief ecdh 算法生成共享密钥(用于密钥协商)。类存储外设公钥
*
* @param device_publicKey 外设公钥
* @param finalKey 输出共享密钥buf。
* @return int
*/
int mss_ecdh_shared_finalKey(uint8_t * finalKey,uint8_t * device_publicKey,uint8_t * client_publicKey);
#endif
midea_hmac_sha256.c
/*
hmac_sha256.c
Originally written by https://github.com/h5p9sl
*/
#include "hmac_sha256.h"
#include <stdlib.h>
#include <string.h>
#define SHA256_BLOCK_SIZE 64
/* LOCAL FUNCTIONS */
// Concatenate X & Y, return hash.
static void* H(const void* x,
const size_t xlen,
const void* y,
const size_t ylen,
void* out,
const size_t outlen);
// Wrapper for sha256
static void* sha256(const void* data,
const size_t datalen,
void* out,
const size_t outlen);
// Declared in hmac_sha256.h
size_t hmac_sha256(const void* key,
const size_t keylen,
const void* data,
const size_t datalen,
void* out,
const size_t outlen) {
uint8_t k[SHA256_BLOCK_SIZE];
uint8_t k_ipad[SHA256_BLOCK_SIZE];
uint8_t k_opad[SHA256_BLOCK_SIZE];
uint8_t ihash[SHA256_HASH_SIZE];
uint8_t ohash[SHA256_HASH_SIZE];
size_t sz;
int i;
memset(k, 0, sizeof(k));
memset(k_ipad, 0x36, SHA256_BLOCK_SIZE);
memset(k_opad, 0x5c, SHA256_BLOCK_SIZE);
if (keylen > SHA256_BLOCK_SIZE) {
// If the key is larger than the hash algorithm's
// block size, we must digest it first.
sha256(key, keylen, k, sizeof(k));
} else {
memcpy(k, key, keylen);
}
for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
k_ipad[i] ^= k[i];
k_opad[i] ^= k[i];
}
// Perform HMAC algorithm: ( https://tools.ietf.org/html/rfc2104 )
// `H(K XOR opad, H(K XOR ipad, data))`
H(k_ipad, sizeof(k_ipad), data, datalen, ihash, sizeof(ihash));
H(k_opad, sizeof(k_opad), ihash, sizeof(ihash), ohash, sizeof(ohash));
sz = (outlen > SHA256_HASH_SIZE) ? SHA256_HASH_SIZE : outlen;
memcpy(out, ohash, sz);
return sz;
}
static void* H(const void* x,
const size_t xlen,
const void* y,
const size_t ylen,
void* out,
const size_t outlen) {
void* result;
size_t buflen = (xlen + ylen);
uint8_t* buf = (uint8_t*)malloc(buflen);
memcpy(buf, x, xlen);
memcpy(buf + xlen, y, ylen);
result = sha256(buf, buflen, out, outlen);
free(buf);
return result;
}
static void* sha256(const void* data,
const size_t datalen,
void* out,
const size_t outlen) {
size_t sz;
Sha256Context ctx;
SHA256_HASH hash;
Sha256Initialise(&ctx);
Sha256Update(&ctx, data, datalen);
Sha256Finalise(&ctx, &hash);
sz = (outlen > SHA256_HASH_SIZE) ? SHA256_HASH_SIZE : outlen;
return memcpy(out, hash.bytes, sz);
}
midea_hmac_sha256.h
/*
hmac_sha256.h
Originally written by https://github.com/h5p9sl
*/
#ifndef _HMAC_SHA256_H_
#define _HMAC_SHA256_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <stddef.h>
#include "midea_sha256_1.h"
size_t // Returns the number of bytes written to `out`
hmac_sha256(
// [in]: The key and its length.
// Should be at least 32 bytes long for optimal security.
const void* key,
const size_t keylen,
// [in]: The data to hash alongside the key.
const void* data,
const size_t datalen,
// [out]: The output hash.
// Should be 32 bytes long. If it's less than 32 bytes,
// the resulting hash will be truncated to the specified length.
void* out,
const size_t outlen);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _HMAC_SHA256_H_
midea_security_utils.c
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
*
* @author 张笔峰
* @email bifeng.zhang@midea.com
* @data 2022-03-14 18:23
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "midea_common/midea_data_center.h"
#include "midea_data_security.h"
#include "midea_common/midea_utils.h"
/**
* @brief 需要释放
* 国内:md5(app_key),然后取16个字符。
* 海内:sha256(app_key),然后取16个字符。
* @param app_key
* @param out encode后的数据
* @return int
*/
static int encode_data_key(char *app_key, char **out)
{
char *encode_data;
int ret = 0;
// if (mss_data_center_is_overseas() == 1)
// {
// ret = mss_sha256_to_lc_hex(app_key, strlen(app_key), &encode_data);
// }
// else
// {
ret = mss_md5_encrypt_to_lc_hex((uint8_t *)app_key, strlen(app_key), &encode_data);
// }
if (ret != 0)
{
return ret;
}
ret = midea_str_substring(encode_data, 0, 16, out);
return ret;
}
/**
* @brief 海外接口CBC加密需要IV, 需要释放。
*
* @param app_key
* @param out
* @return int
*/
static int encode_data_iv(char *app_key, char **out)
{
// if (mss_data_center_is_overseas() == 1)
// {
// char *encode_data;
// int ret = mss_sha256_to_lc_hex(app_key, strlen(app_key), &encode_data);
// if (ret != 0)
// {
// return ret;
// }
// ret = str_substring(encode_data, 16, 32, out);
// return ret;
// }
return 0;
}
int mss_decode_aes128_with_app_key(char *encrypt_hex_str, uint8_t **out, size_t *out_size)
{
char *app_key = mss_share_instance()->ms_config->app_key;
if (app_key == NULL)
{
// todo 后续可以增加一个错误码,处理未设置配置参数的问题
return -1;
}
if (encrypt_hex_str == NULL)
{
return -1;
}
char *data_key_out = NULL; //需要释放
int ret = encode_data_key(app_key, &data_key_out);
if (ret != 0)
{
return ret;
}
//海外
// char *data_iv_out = NULL; //需要释放
// ret = encode_data_iv(app_key, &data_iv_out);
// if (ret != 0)
// {
// return ret;
// }
uint8_t *encrypt_data; //需要释放
size_t encrypt_data_size;
ret = midea_hex_string_to_bytes(encrypt_hex_str, &encrypt_data, &encrypt_data_size);
if (ret != 0)
{
return ret;
}
printf("The decrypt data size :%d", encrypt_data_size);
ret = mss_crypto_aes128_decrypt(encrypt_data, &encrypt_data_size, (uint8_t *)data_key_out, 0);
if (ret != 0)
{
free(encrypt_data);
return ret;
}
*out = encrypt_data;
*out_size = encrypt_data_size;
return 0;
}
int mss_decode_aes128_with_data_key(char *encrypt_hex_str, uint8_t **out, size_t *out_size)
{
char *data_key = mss_share_instance()->login_info->data_key;
if (data_key == NULL)
{
// todo 后续可以增加一个错误码,处理未设置配置参数的问题
return -1;
}
if (encrypt_hex_str == NULL)
{
return -1;
}
uint8_t *data; //需要释放
size_t data_size;
int ret = midea_hex_string_to_bytes(encrypt_hex_str, &data, &data_size);
if (ret != 0)
{
return ret;
}
ret = mss_crypto_aes128_decrypt(data, &data_size, data_key, 0);
if (ret != 0)
{
return ret;
}
*out = data;
*out_size = data_size;
return 0;
}
int mss_encode_aes128_with_data_key(char *encrypt_str, char **out)
{
uint8_t *encrypt_data = (uint8_t *)encrypt_str;
size_t encrypt_data_len = strlen(encrypt_str);
printf("开始加密");
// if (mss_data_center_is_overseas() == 1)
// {
// // todo 海外加密方式
// return -1;
// }
// else
// {
uint8_t *out_put;
size_t len;
int ret = mss_crypto_aes128_ecrypt_h(encrypt_data, encrypt_data_len, mss_share_instance()->login_info->data_key, 0, &out_put, &len);
if (ret != 0)
{
return ret;
}
char *hex_str = NULL;
ret = midea_bytes_to_lc_hex_string(out_put, len, &hex_str);
if (ret != 0)
{
return ret;
}
*out = hex_str;
// }
return 0;
}
///设置登录信息
int mss_set_login_info(char *access_token, char *encode_data_key, char *encode_data_iv)
{
MS_DATA_CENTER *data_center = mss_share_instance();
//复制AT
strcpy(data_center->login_info->access_token, access_token);
//解密data key
uint8_t *data_key_out;
size_t data_key_out_size;
int ret = mss_decode_aes128_with_app_key(encode_data_key, &data_key_out, &data_key_out_size);
if(ret != 0){
return ret;
}
data_center->login_info->data_key_size=data_key_out_size;
//复制data key
memcpy(data_center->login_info->data_key, data_key_out, data_key_out_size);
if (encode_data_iv != NULL)
{
//解密data iv
uint8_t *data_iv_out;
size_t data_iv_out_size;
int ret = mss_decode_aes128_with_app_key(encode_data_iv, &data_iv_out, &data_iv_out_size);
if(ret != 0){
return ret;
}
data_center->login_info->data_iv_size=data_iv_out_size;
//复制data iv
memcpy(data_center->login_info->data_iv, data_iv_out, data_iv_out_size);
}
return 0;
}
midea_security_utils.h
/*
* Copyright (c) 2021 Midea Co., Ltd. All Rights Reserved.
* 加密/解密的逻辑过程封装工具
* @author 张笔峰
* @email bifeng.zhang@midea.com
* @data 2022-03-14 18:23
*/
#ifndef MS_SECURITY_UTIL_H
#define MS_SECURITY_UTIL_H
#include "midea_data_types.h"
/**
* @brief 使用app key解密数据,需要释放内存
*
* @param encrypt_hex_str 已加密的16进制字符串数据
* @param out 解密后的数据
* @param out_size 解密后的数据长度
* @return int
*/
int mss_decode_aes128_with_app_key(char *encrypt_hex_str, uint8_t **out, size_t *out_size);
/**
* @brief 使用data key解密数据,需要释放内存
*
* @param encrypt_hex_str 已加密的16进制字符串数据
* @param out 解密后的数据
* @param out_size 解密后的数据长度
* @return int
*/
int mss_decode_aes128_with_data_key(char *encrypt_hex_str, uint8_t **out, size_t *out_size);
/**
* @brief 使用data key加密数据,需要释放内存
*
* @param encrypt_str 待加密的字符串
* @param out 加密后的16进制字符串
* @return int 0:成功
*/
int mss_encode_aes128_with_data_key(char *encrypt_str, char **out);
///设置登录信息
int mss_set_login_info(char *access_token ,char *encode_data_key, char *encode_data_iv);
#endif
midea_sha256_1.c
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WjCryptLib_Sha256
//
// Implementation of SHA256 hash function.
// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
// Modified by WaterJuice retaining Public Domain license.
//
// This is free and unencumbered software released into the public domain -
// June 2013 waterjuice.org
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "midea_sha256_1.h"
#include <memory.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MACROS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define STORE32H(x, y) \
{ \
(y)[0] = (uint8_t)(((x) >> 24) & 255); \
(y)[1] = (uint8_t)(((x) >> 16) & 255); \
(y)[2] = (uint8_t)(((x) >> 8) & 255); \
(y)[3] = (uint8_t)((x)&255); \
}
#define LOAD32H(x, y) \
{ \
x = ((uint32_t)((y)[0] & 255) << 24) | ((uint32_t)((y)[1] & 255) << 16) | \
((uint32_t)((y)[2] & 255) << 8) | ((uint32_t)((y)[3] & 255)); \
}
#define STORE64H(x, y) \
{ \
(y)[0] = (uint8_t)(((x) >> 56) & 255); \
(y)[1] = (uint8_t)(((x) >> 48) & 255); \
(y)[2] = (uint8_t)(((x) >> 40) & 255); \
(y)[3] = (uint8_t)(((x) >> 32) & 255); \
(y)[4] = (uint8_t)(((x) >> 24) & 255); \
(y)[5] = (uint8_t)(((x) >> 16) & 255); \
(y)[6] = (uint8_t)(((x) >> 8) & 255); \
(y)[7] = (uint8_t)((x)&255); \
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The K array
static const uint32_t K[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL};
#define BLOCK_SIZE 64
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Various logical functions
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ror((x), (n))
#define R(x, n) (((x)&0xFFFFFFFFUL) >> (n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
#define Sha256Round(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TransformFunction
//
// Compress 512-bits
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void TransformFunction(Sha256Context* Context, uint8_t const* Buffer) {
uint32_t S[8];
uint32_t W[64];
uint32_t t0;
uint32_t t1;
uint32_t t;
int i;
// Copy state into S
for (i = 0; i < 8; i++) {
S[i] = Context->state[i];
}
// Copy the state into 512-bits into W[0..15]
for (i = 0; i < 16; i++) {
LOAD32H(W[i], Buffer + (4 * i));
}
// Fill W[16..63]
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
// Compress
for (i = 0; i < 64; i++) {
Sha256Round(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
t = S[7];
S[7] = S[6];
S[6] = S[5];
S[5] = S[4];
S[4] = S[3];
S[3] = S[2];
S[2] = S[1];
S[1] = S[0];
S[0] = t;
}
// Feedback
for (i = 0; i < 8; i++) {
Context->state[i] = Context->state[i] + S[i];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Initialise
//
// Initialises a SHA256 Context. Use this to initialise/reset a context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Initialise(Sha256Context* Context // [out]
) {
Context->curlen = 0;
Context->length = 0;
Context->state[0] = 0x6A09E667UL;
Context->state[1] = 0xBB67AE85UL;
Context->state[2] = 0x3C6EF372UL;
Context->state[3] = 0xA54FF53AUL;
Context->state[4] = 0x510E527FUL;
Context->state[5] = 0x9B05688CUL;
Context->state[6] = 0x1F83D9ABUL;
Context->state[7] = 0x5BE0CD19UL;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Update
//
// Adds data to the SHA256 context. This will process the data and update the
// internal state of the context. Keep on calling this function until all the
// data has been added. Then call Sha256Finalise to calculate the hash.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Update(Sha256Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
) {
uint32_t n;
if (Context->curlen > sizeof(Context->buf)) {
return;
}
while (BufferSize > 0) {
if (Context->curlen == 0 && BufferSize >= BLOCK_SIZE) {
TransformFunction(Context, (uint8_t*)Buffer);
Context->length += BLOCK_SIZE * 8;
Buffer = (uint8_t*)Buffer + BLOCK_SIZE;
BufferSize -= BLOCK_SIZE;
} else {
n = MIN(BufferSize, (BLOCK_SIZE - Context->curlen));
memcpy(Context->buf + Context->curlen, Buffer, (size_t)n);
Context->curlen += n;
Buffer = (uint8_t*)Buffer + n;
BufferSize -= n;
if (Context->curlen == BLOCK_SIZE) {
TransformFunction(Context, Context->buf);
Context->length += 8 * BLOCK_SIZE;
Context->curlen = 0;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Finalise
//
// Performs the final calculation of the hash and returns the digest (32 byte
// buffer containing 256bit hash). After calling this, Sha256Initialised must
// be used to reuse the context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Finalise(Sha256Context* Context, // [in out]
SHA256_HASH* Digest // [out]
) {
int i;
if (Context->curlen >= sizeof(Context->buf)) {
return;
}
// Increase the length of the message
Context->length += Context->curlen * 8;
// Append the '1' bit
Context->buf[Context->curlen++] = (uint8_t)0x80;
// if the length is currently above 56 bytes we append zeros
// then compress. Then we can fall back to padding zeros and length
// encoding like normal.
if (Context->curlen > 56) {
while (Context->curlen < 64) {
Context->buf[Context->curlen++] = (uint8_t)0;
}
TransformFunction(Context, Context->buf);
Context->curlen = 0;
}
// Pad up to 56 bytes of zeroes
while (Context->curlen < 56) {
Context->buf[Context->curlen++] = (uint8_t)0;
}
// Store length
STORE64H(Context->length, Context->buf + 56);
TransformFunction(Context, Context->buf);
// Copy output
for (i = 0; i < 8; i++) {
STORE32H(Context->state[i], Digest->bytes + (4 * i));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Calculate
//
// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one
// function. Calculates the SHA256 hash of the buffer.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Calculate(void const* Buffer, // [in]
uint32_t BufferSize, // [in]
SHA256_HASH* Digest // [in]
) {
Sha256Context context;
Sha256Initialise(&context);
Sha256Update(&context, Buffer, BufferSize);
Sha256Finalise(&context, Digest);
}
midea_sha256_1.h
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WjCryptLib_Sha256
//
// Implementation of SHA256 hash function.
// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org
// Modified by WaterJuice retaining Public Domain license.
//
// This is free and unencumbered software released into the public domain -
// June 2013 waterjuice.org
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdint.h>
#include <stdio.h>
typedef struct {
uint64_t length;
uint32_t state[8];
uint32_t curlen;
uint8_t buf[64];
} Sha256Context;
#define SHA256_HASH_SIZE (256 / 8)
typedef struct {
uint8_t bytes[SHA256_HASH_SIZE];
} SHA256_HASH;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Initialise
//
// Initialises a SHA256 Context. Use this to initialise/reset a context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Initialise(Sha256Context* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Update
//
// Adds data to the SHA256 context. This will process the data and update the
// internal state of the context. Keep on calling this function until all the
// data has been added. Then call Sha256Finalise to calculate the hash.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Update(Sha256Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Finalise
//
// Performs the final calculation of the hash and returns the digest (32 byte
// buffer containing 256bit hash). After calling this, Sha256Initialised must
// be used to reuse the context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Finalise(Sha256Context* Context, // [in out]
SHA256_HASH* Digest // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sha256Calculate
//
// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one
// function. Calculates the SHA256 hash of the buffer.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Calculate(void const* Buffer, // [in]
uint32_t BufferSize, // [in]
SHA256_HASH* Digest // [in]
);
浙公网安备 33010602011771号