hks_mbedtls_aes.c代码分析
一、背景知识
自己对代码的一些见解
这里主要是使用mbedtls库中aes对应的一些函数,该库中将功能基本封装好。鸿蒙这里进行了进一步的适配和封装。主要实现一些密钥的生成,加解密的实现。这里的加解密相比其他文件有一个特殊点:就是加解密都封装在一个函数内,在函数形参中传入逻辑变量来实现。相当于一个开关变量,开的时候实现加密,关闭的时候实现解密。真正的封装好各部分功能。
aes算法介绍链接:
二、代码分析
1.密钥的生成
实现最基础的密钥生成(基于随机数的生成实现密钥生成,填写随机数据进key中data)
//密钥的生成
int32_t HksMbedtlsAesGenerateKey(const struct HksKeySpec *spec, struct HksBlob *key)
{
const uint32_t keyByteLen = spec->keyLen / HKS_BITS_PER_BYTE;
uint8_t *outKey = (uint8_t *)HksMalloc(keyByteLen);
//先申请空间用来存放随机数据(密钥数据)
if (outKey == NULL) {
return HKS_ERROR_MALLOC_FAIL;
}
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctrDrbg;
int32_t ret = HksCtrDrbgSeed(&ctrDrbg, &entropy);
//随机数种子(熵源)
if (ret != HKS_SUCCESS) {
HKS_FREE_PTR(outKey);
return ret;
}
do {
ret = mbedtls_ctr_drbg_random(&ctrDrbg, outKey, keyByteLen);
//在对应空间outkey生成随机数
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls ctr drbg random failed! mbedtls ret = 0x%X", ret);
(void)memset_s(outKey, keyByteLen, 0, keyByteLen);
HKS_FREE_PTR(outKey);
break;
}
//将最后结果写进key的数据域和size
key->data = outKey;
key->size = keyByteLen;
} while (0);
mbedtls_ctr_drbg_free(&ctrDrbg);
mbedtls_entropy_free(&entropy);
//释放随机数空间和熵源
return ret;
}
2.aes/cbc在nopadding模式下的加密
第一种加密模式,其中参数最重要的个人认为是这个bool变量 encrypt。他象个开关控制是加密还是解密。
参数介绍:
- key:加解密的密钥
- cipherParam:密文参数信息
- message:加密的结果会生成一个消息
- encrypt:逻辑变量控制是加密还是解密
- ciphetext:密文信息
static int32_t AesCbcNoPaddingCrypt(const struct HksBlob *key, const struct HksCipherParam *cipherParam,
const struct HksBlob *message, const bool encrypt, struct HksBlob *cipherText)
{
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
int32_t ret;
do {
if (encrypt) {
ret = mbedtls_aes_setkey_enc(&ctx, key->data, key->size * HKS_BITS_PER_BYTE);
//根据传入的参数,如果为逻辑真就设置一套加密密钥
} else {
ret = mbedtls_aes_setkey_dec(&ctx, key->data, key->size * HKS_BITS_PER_BYTE);
}
//如果为逻辑假就设置一套解密密钥
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls aes set key failed! mbedtls ret = 0x%X", ret);
break;
}
/* mbedtls_aes_crypt_cbc will refresh iv, so need a temp iv */
uint8_t tmpIv[HKS_AES_CBC_NOPADDING_IV_SIZE];
//定义一组临时向量iv
if (memcpy_s(tmpIv, HKS_AES_CBC_NOPADDING_IV_SIZE, cipherParam->iv.data, cipherParam->iv.size) != EOK) {
HKS_LOG_E("Memcpy temp iv failed!");
break;
}
//初始化tmpiv的空间为cipherParam->iv.data
ret = mbedtls_aes_crypt_cbc(&ctx, (encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT),
message->size, tmpIv, message->data, cipherText->data);
//加解密的实现,根据逻辑值判断为加密还是解密
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtks aes cbc crypt failed! mbedtls ret = 0x%X", ret);
(void)memset_s(cipherText->data, cipherText->size, 0, cipherText->size);
break;
}
cipherText->size = message->size;
//将最后加密后的message内容写进密文
} while (0);
mbedtls_aes_free(&ctx);
//释放相关空间ctx
return ret;
}
3.aes/cbc在pkcs7下的加密
该函数也是一种加解密的方式,上一种是nopadding,着一种是okcs7的方法。参数功能基本相似。
参数介绍:
- key:加解密的密钥
- cipherParam:密文参数信息
- message:加密的结果会生成一个消息
- encrypt:逻辑变量控制是加密还是解密
- ciphetext:密文信息
//pkcs7的加解密
static int32_t AesCbcPkcs7Crypt(const struct HksBlob *key, const struct HksCipherParam *cipherParam,
const struct HksBlob *message, const bool encrypt, struct HksBlob *cipherText)
{
const uint32_t keyBitLen = key->size * HKS_BITS_PER_BYTE;
//密钥的位长度
const mbedtls_cipher_info_t *info =
mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, keyBitLen, MBEDTLS_MODE_CBC);
//村数组中获取密文信息
mbedtls_cipher_context_t ctx;
mbedtls_cipher_init(&ctx);
//cipher变量初始化
int32_t ret;
do {
ret = mbedtls_cipher_setup(&ctx, info);
//以指定信息设置ctx
if (ret != HKS_SUCCESS) {
HKS_LOG_E("Mbedtls cbc pkcs7 setup ctx failed! mbedtls ret = 0x%X", ret);
break;
}
ret = mbedtls_cipher_setkey(&ctx, key->data, keyBitLen, (encrypt ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT));
//根据encrypt传入的逻辑值来判断是要设置加密密文还是解密密文
if (ret != HKS_SUCCESS) {
HKS_LOG_E("Mbedtls cbc pkcs7 set key failed! mbedtls ret = 0x%X", ret);
break;
}
ret = mbedtls_cipher_crypt(&ctx, cipherParam->iv.data, cipherParam->iv.size,
message->data, message->size, cipherText->data, (size_t *)&(cipherText->size));
//加解密的实现。上一步密钥密文信息的设置结果,在ctx中的结果实现加解密。
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls cbc pkcs7 crypt failed! mbedtls ret = 0x%X", ret);
(void)memset_s(cipherText->data, cipherText->size, 0, cipherText->size);
}
} while (0);
mbedtls_cipher_free(&ctx);
return ret;
}
4.aes/cbc的普通加密
该函数主要也是调用之前的加密方法,将算法写进usageSpec进行判断选用不同的模式进行加解密。
//封装函数
#if defined(HKS_SUPPORT_AES_CBC_NOPADDING) || defined(HKS_SUPPORT_AES_CBC_PKCS7)
static int32_t AesCbcCrypt(const struct HksBlob *key, const struct HksUsageSpec *usageSpec,
const struct HksBlob *message, const bool encrypt, struct HksBlob *cipherText)
{
const struct HksCipherParam *cipherParam = (struct HksCipherParam *)(usageSpec->algParam);
switch (usageSpec->padding) {
//根据usageSpec中内容进行分支,里面是判断选用nopadding还是pkcs7算法
#ifdef HKS_SUPPORT_AES_CBC_NOPADDING
case HKS_PADDING_NONE:
return AesCbcNoPaddingCrypt(key, cipherParam, message, encrypt, cipherText);
#endif
#ifdef HKS_SUPPORT_AES_CBC_PKCS7
case HKS_PADDING_PKCS7:
return AesCbcPkcs7Crypt(key, cipherParam, message, encrypt, cipherText);
#endif
default:
HKS_LOG_E("Unsupport padding! mode = 0x%X", usageSpec->padding);
return HKS_ERROR_INVALID_PADDING;
}
}
5.aes和gcm的加密
aes和gcm的加密模式。
static int32_t AesEncryptGcm(const struct HksBlob *key, const struct HksUsageSpec *usageSpec,
const struct HksBlob *message, struct HksBlob *cipherText, struct HksBlob *tagAead)
{
mbedtls_gcm_context ctx;
mbedtls_gcm_init(&ctx);
//先定义及初始化一个gcm的密文信息ctx
int32_t ret;
do {
ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->data, key->size * HKS_BITS_PER_BYTE);
//设置一个密钥,写进key中
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls aes gcm set key failed! mbedtls ret = 0x%X", ret);
break;
}
const struct HksAeadParam *aeadParam = (struct HksAeadParam *)(usageSpec->algParam);
ret = mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_ENCRYPT, message->size,
aeadParam->nonce.data, aeadParam->nonce.size, aeadParam->aad.data, aeadParam->aad.size,
message->data, cipherText->data, tagAead->size, tagAead->data);
//调用mbedtls_gcm_crypt_and_tag实现加密和标记
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls aes gcm encryot failed! mbedtls ret = 0x%X", ret);
(void)memset_s(cipherText->data, cipherText->size, 0, cipherText->size);
(void)memset_s(tagAead->data, tagAead->size, 0, tagAead->size);
break;
//加密失败的处理
}
cipherText->size = message->size;
//将最后结果写进密文
} while (0);
mbedtls_gcm_free(&ctx);
return ret;
}
6.aes和gcm的解密
对应的解密函数,一般加密函数会对应一个唯一的解密函数。或者是将两个函数写在一起,用逻辑变量区分。
//aes/gcm的解密
static int32_t AesDecryptGcm(const struct HksBlob *key, const struct HksUsageSpec *usageSpec,
const struct HksBlob *message, struct HksBlob *cipherText)
{
mbedtls_gcm_context ctx;
mbedtls_gcm_init(&ctx);
int32_t ret;
do {
ret = mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key->data, key->size * HKS_BITS_PER_BYTE);
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls aes gcm set key failed! mbedtls ret = 0x%X", ret);
break;
}
const struct HksAeadParam *aeadParam = (struct HksAeadParam *)(usageSpec->algParam);
ret = mbedtls_gcm_auth_decrypt(&ctx, message->size, aeadParam->nonce.data, aeadParam->nonce.size,
aeadParam->aad.data, aeadParam->aad.size, aeadParam->tagDec.data, aeadParam->tagDec.size,
message->data, cipherText->data);
if (ret != HKS_MBEDTLS_SUCCESS) {
HKS_LOG_E("Mbedtls aes gcm decrypt failed! mbedtls ret = 0x%X", ret);
(void)memset_s(cipherText->data, cipherText->size, 0, cipherText->size);
break;
}
cipherText->size = message->size;
} while (0);
mbedtls_gcm_free(&ctx);
return ret;
}
7.密钥的检查
检查密钥的位长度size是否位128、192、256等。
//密钥的检查
static int32_t CheckKeySize(const struct HksBlob *key)
{
if ((key->size != HKS_KEY_BYTES(HKS_AES_KEY_SIZE_128)) && (key->size != HKS_KEY_BYTES(HKS_AES_KEY_SIZE_192)) &&
(key->size != HKS_KEY_BYTES(HKS_AES_KEY_SIZE_256))) {
//检查密钥字节长度是否为128或者是192或者是256
return HKS_ERROR_INVALID_KEY_SIZE;
}
return HKS_SUCCESS;
}
8.加密和解密功能的封装
总的函数功能封装,将会情况写进usagespec中,然后采用switch语句将不同函数封装进去,cbc将nopadding和pkcs7封装在了一起,整体叫做cbc加密,而相对应的另一种加解密方式就是gcm和aes的加解密模式,这里封装cbc和gcm的情况。同时实现了解密的封装。
//函数功能的封装,根据不同情况判断使用何种加解密方式
int32_t HksMbedtlsAesEncrypt(const struct HksBlob *key, const struct HksUsageSpec *usageSpec,
const struct HksBlob *message, struct HksBlob *cipherText, struct HksBlob *tagAead)
{
if (CheckKeySize(key) != HKS_SUCCESS) {
HKS_LOG_E("Invalid aes keySiz = 0x%X", key->size);
return HKS_ERROR_INVALID_KEY_SIZE;
}
switch (usageSpec->mode) {
//基于usageSpec->mode进行分支选择加解密算法
#if defined(HKS_SUPPORT_AES_CBC_NOPADDING) || defined(HKS_SUPPORT_AES_CBC_PKCS7)
case HKS_MODE_CBC:
return AesCbcCrypt(key, usageSpec, message, true, cipherText);
#endif
#ifdef HKS_SUPPORT_AES_GCM
case HKS_MODE_GCM:
return AesEncryptGcm(key, usageSpec, message, cipherText, tagAead);
#endif
#ifdef HKS_SUPPORT_AES_CCM
case HKS_MODE_CCM:
return AesEncryptCcm(key, usageSpec, message, cipherText, tagAead);
#endif
default:
HKS_LOG_E("Unsupport key alg! mode = 0x%X", usageSpec->mode);
return HKS_ERROR_INVALID_ARGUMENT;
}
}
解密的封装
//解密的封装
int32_t HksMbedtlsAesDecrypt(const struct HksBlob *key, const struct HksUsageSpec *usageSpec,
const struct HksBlob *message, struct HksBlob *cipherText)
{
if (CheckKeySize(key) != HKS_SUCCESS) {
HKS_LOG_E("Invalid aes keySize = 0x%X", key->size);
return HKS_ERROR_INVALID_KEY_SIZE;
}
switch (usageSpec->mode) {
#if defined(HKS_SUPPORT_AES_CBC_NOPADDING) || defined(HKS_SUPPORT_AES_CBC_PKCS7)
case HKS_MODE_CBC:
return AesCbcCrypt(key, usageSpec, message, false, cipherText);
#endif
#ifdef HKS_SUPPORT_AES_GCM
case HKS_MODE_GCM:
return AesDecryptGcm(key, usageSpec, message, cipherText);
#endif
#ifdef HKS_SUPPORT_AES_CCM
case HKS_MODE_CCM:
return AesDecryptCcm(key, usageSpec, message, cipherText);
#endif
default:
HKS_LOG_E("Unsupport key alg! mode = 0x%X", usageSpec->mode);
return HKS_ERROR_INVALID_ARGUMENT;
}
}