> 文档中心 > OpenHarmony安全模块之AES加密学习

OpenHarmony安全模块之AES加密学习

OpenHarmony初分析

security_huks/frameworks/crypto_lite/cipher/src/cipher_aes

在上一次的学习中,我们了解了OpenHarmony的三大模块的特点,今天我们来学习第三个模块——安全模块。我们知道,鸿蒙通用密钥库系统主要是为了向应用提供密钥库的功能,包括密钥管理以及生成密钥的密码学操作等功能。

OpenHarmony操作系统是一个开放的系统,开发者可以通过OpenHarmony开发灵活的服务和应用,为开发者和使用者带来便利和价值。为了达到这一目的,OpenHarmony提供了一个可以有效保护应用和用户数据的执行环境。

在这里插入图片描述
安全机制由HUKS提供功能
在这里插入图片描述
frameworks文件是框架代码,其目录下的crypto_lite提供了加解密实现的功能。

今天我们主要学习AES文件加密,AES-GCM加密算法:AES是一种对称加密算法,GCM是对该对称加密采用Counter模式,并带有GMAC消息认证码。AES-GCM算法是带认证和加密的算法,同时可以对给定的原文,生成加密数据和认证码。现在开始对代码进行简要分析

在这里插入图片描述
这里首先简述两个定义:
明文:没有经过加密的数据

密钥:用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。

数据明文由PaddingPkcs5给定字符进行填充,UnpaddingPkcs5用于去除明文中填充完毕后的填充字符。

MallocDecodeData代码可以分为两个模块,一个是内存填充模块,主要是对文件明文进行符号填充;另一个是明文解码模块,将填充的文件进行解码

SetIv是初始化向量函数,因为OpenHarmony模块采用的加密方式为密码分组链接模式,可将一块又一块的分组加密模块进行连接,而SetIv则作为第0块明文字符块的干扰项,防止被解析攻击,

代码模块如下:

static int32_t PaddingPkcs5(char *data, size_t inSize){    if (inSize % AES_BLOCK_SIZE == 0) { return strlen((const char *)(uintptr_t)data); //判断数据信息是否整齐    }    int32_t paddingLen = AES_BLOCK_SIZE - inSize % AES_BLOCK_SIZE; //paddingLen包括了填充的数据值和长度    int32_t needLen = paddingLen + inSize;    for (int32_t i = 0; i < paddingLen; i++) { //采用循环填充数据的方式进行填充 data[inSize + i] = paddingLen;    }    return needLen;}static int32_t UnpaddingPkcs5(char *data, size_t dataLen) //用于去掉解密后的包含填充字符的明文中的填充字符{   //得到填充数据的长度    int32_t padLen = data[dataLen - 1];    //数据不合理时,退出函数    if (padLen <= 0 || padLen >= AES_BLOCK_SIZE) { return ERROR_CODE_GENERAL;    }    //循环删除填充数据    for (int32_t i = 0; i < padLen; i++) { if (data[dataLen - 1 - i] != padLen) {     return ERROR_CODE_GENERAL; } data[dataLen - 1 - i] = '\0';    }    return (dataLen - padLen);}static char *MallocDecodeData(const char *text, size_t *olen) //内存填充模块{    size_t decodeLen = 0; //初始化    int32_t ret = mbedtls_base64_decode(NULL, 0, &decodeLen, (const unsigned char *)(text), strlen(text));//加密text    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) { //判断BUFFER的值,若缓存空间太小,不适用于解码 return NULL;    }    //申请内存空间    if ((decodeLen + 1) <= 0) { return NULL; //检查decodeLen的大小,若为负,程序无法继续运行,则报错    }    char *decData = (char *)malloc(decodeLen + 1);    if (decData == NULL) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "malloc failed, length:%{public}d.", (int32_t)(decodeLen + 1)); return NULL; //当数据超出内存大小时,程序无法继续进行,则报错    }    //清零操作,将申请到的地址空间填满0    memset_s(decData,  decodeLen + 1, 0, decodeLen + 1); //对decData进行填充    //基于mbedtls的base64解码,第一个参数为申请到的地址空间,将解码后的数据存入地址空间    if (mbedtls_base64_decode((unsigned char *)decData, decodeLen + 1, olen, (const unsigned char *)text, strlen(text)) != 0) {  //解码数据失败,清空内存空间,释放资源 free(decData); //释放内存 HILOG_ERROR(HILOG_MODULE_HIVIEW, "decode data failed, text:%s.", text); return NULL; //操作失败则报错    }    return decData;}static char *MallocEncodeData(const unsigned char *text, size_t *olen) //明文解码模块{    size_t dataLen = 0; //初始化    int32_t ret = mbedtls_base64_encode(NULL, 0, &dataLen, text, *olen); //解密text    if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) { //判断BUFFER的值,若缓存空间太小,不适用于编码 return NULL;    }    if ((dataLen + 1) <= 0) { return NULL; //检查decodeLen的大小,若为负,程序无法继续运行,则报错    }    //申请内存空间    char *encData = (char *)malloc(dataLen + 1);    if (encData == NULL) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "malloc data failed, expect len:%{public}zu.", dataLen); return NULL; //当内存中不存在数据明文时,程序无法继续进行,则报错    }    //清零操作,将申请到的地址空间填满0    memset_s(encData, dataLen, 0, dataLen); //明文解码    //基于mbedtls的base64编码,第一个参数为申请到的地址空间    if (mbedtls_base64_encode((unsigned char *)(encData), dataLen, olen, text, *olen) != 0) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "encode data failed."); //程序错误,解码失败 free(encData); //释放内存 return NULL;    }    return encData;}static int32_t SetIv(const char *ivBuf, int32_t ivBufLen, AesCryptContext *ctx) //初始化向量函数{    if ((ivBuf == NULL) || (ctx == NULL)) { return ERROR_CODE_GENERAL; //ivBuf和ctx不能为空    }    if ((ivBufLen < (ctx->iv.ivOffset + ctx->iv.ivLen)) || (ctx->iv.ivOffset < 0) || (ctx->iv.ivLen <= 0)) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "ivLen or ivOffset err."); //判断加密块长度是否满足加密条件 return ERROR_CODE_GENERAL;    }    //申请内存空间    ctx->iv.ivBuf = malloc(ctx->iv.ivLen);    if (ctx->iv.ivBuf == NULL) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "malloc failed."); return ERROR_CODE_GENERAL;    }    //清零操作,将申请到的地址空间填满0    (void)memset_s(ctx->iv.ivBuf, ctx->iv.ivLen, 0, ctx->iv.ivLen);    //然后把缓冲区中的数据拷贝到申请的内存中    int32_t ret = memcpy_s(ctx->iv.ivBuf, ctx->iv.ivLen, ivBuf + ctx->iv.ivOffset, ctx->iv.ivLen);    if (ret) {  //判断拷贝是否成功,未成功则释放资源 HILOG_ERROR(HILOG_MODULE_HIVIEW, "memcpy failed, ret:%{public}d.", ret); free(ctx->iv.ivBuf); ctx->iv.ivBuf = NULL; return ERROR_CODE_GENERAL;    }    return ERROR_SUCCESS;}static int32_t InitAesCryptContext(const char *key, const AesIvMode *iv, AesCryptContext *ctx){    int32_t ret;    //判断传入参数的合法性    if (iv == NULL || ctx == NULL || key == NULL) { return ERROR_CODE_GENERAL;    }    if ((iv->transformation != NULL) && (strcmp(iv->transformation, "AES/CBC/PKCS5Padding"))) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "transformation err."); return ERROR_CODE_GENERAL;    }    //采用AES、CBC加密模式    ctx->mode = CIPHER_AES_CBC;    ctx->iv.ivOffset = iv->ivOffset;    //初始化ctx中偏移量    if ((iv->ivLen >= 0) && (iv->ivLen != AES_BLOCK_SIZE)) {    //如果向量长度大于块大小,退出函数 HILOG_ERROR(HILOG_MODULE_HIVIEW, "ivLen:%{public}d error, need be %{public}d Bytes.",     iv->ivLen, AES_BLOCK_SIZE); return ERROR_CODE_GENERAL;    }    ctx->iv.ivLen = AES_BLOCK_SIZE; //将块大小赋值给向量长度    if (iv->ivBuf != NULL) { size_t ivBufLen = strlen((const char *)(uintptr_t)iv->ivBuf);   //得到解码后的数据 char* ivBuf = MallocDecodeData(iv->ivBuf, &ivBufLen); if (ivBuf == NULL) {     HILOG_ERROR(HILOG_MODULE_HIVIEW, "base64 decode failed.");     return ERROR_CODE_GENERAL; } //将解码后的数据存入上下文语境中 ret = SetIv((const char *)ivBuf, strlen((const char *)(uintptr_t)ivBuf), ctx); if (ret == ERROR_CODE_GENERAL) {     free(ivBuf);     HILOG_ERROR(HILOG_MODULE_HIVIEW, "SetIv failed.");     return ERROR_CODE_GENERAL; } free(ivBuf);    } else { //将密钥存入上下文语境中 ret = SetIv(ctx->data.key, strlen((const char *)(uintptr_t)ctx->data.key), ctx); if (ret == ERROR_CODE_GENERAL) {     HILOG_ERROR(HILOG_MODULE_HIVIEW, "SetIv failed.");     return ERROR_CODE_GENERAL; }    }    return ERROR_SUCCESS;}static int32_t InitAesData(const char *action, const char *key, const char *text, CryptData *data){    if (action == NULL || text == 0 || data == NULL || key == NULL) {   //判断传入相关参数的合法性 return ERROR_CODE_GENERAL;    }    if (!strcmp(action, "encrypt")) { data->action = MBEDTLS_AES_ENCRYPT; //设置当前为加密 if (strlen(text) % AES_BLOCK_SIZE) {    //设置数据的长度     data->textLen =  (strlen(text) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + AES_BLOCK_SIZE; } else {     data->textLen = strlen(text); } if ((data->textLen + 1) <= 0) {     return ERROR_CODE_GENERAL; } data->text = malloc(data->textLen + 1); //为文本内容申请内存空间 if (data->text == NULL) {     return ERROR_CODE_GENERAL; } //将内存空间清零 (void)memset_s(data->text, data->textLen + 1, 0, data->textLen + 1); if (memcpy_s(data->text, data->textLen + 1, text, strlen(text))) {  //将文本内容复制到刚申请的地址空间     goto ERROR; } data->textLen = PaddingPkcs5(data->text, strlen(text));    } else if (!strcmp(action, "decrypt")) { data->action = MBEDTLS_AES_DECRYPT; //设置当前为解密 data->text = MallocDecodeData(text, (size_t *)&data->textLen);  //为文本内容申请内存空间 if (data->text == NULL) {     return ERROR_CODE_GENERAL; } data->textLen -= data->textLen % AES_BLOCK_SIZE;    } else { return ERROR_CODE_GENERAL;    }    data->key = MallocDecodeData(key, (size_t *)&data->keyLen); //为密钥申请内存空间    if (data->key == NULL) { goto ERROR;    }    if (data->keyLen != KEY_LEN) {   //检验密钥的合法性 HILOG_ERROR(HILOG_MODULE_HIVIEW, "key length:%{public}d error, need be %{public}d Bytes.",     data->keyLen, KEY_LEN); memset_s(data->key, data->keyLen, 0, data->keyLen); //如不合法,内存空间清零,释放资源 free(data->key); data->key = NULL; goto ERROR;    }    return ERROR_SUCCESS;ERROR:    free(data->text);    data->text = NULL;    return ERROR_CODE_GENERAL;}void DeinitAesCryptData(AesCryptContext *ctx){    if (ctx == NULL) {  //判断参数合法性 return;    }    if (ctx->iv.ivBuf != NULL) {    //清空初始向量缓冲区 free(ctx->iv.ivBuf); ctx->iv.ivBuf = NULL;    }    if (ctx->data.key != NULL) {    //密钥地址空间置零并释放,上下文中密钥清空 memset_s(ctx->data.key, ctx->data.keyLen, 0, ctx->data.keyLen); free(ctx->data.key); ctx->data.key = NULL;    }    if (ctx->data.text != NULL) {   //释放文本内容地址空间,上下文中文本清空 free(ctx->data.text); ctx->data.text = NULL;    }}static int32_t DoAesCbcEncrypt(mbedtls_aes_context *aesCtx, AesCryptContext *ctx){    int32_t ret;    if (ctx->data.action == MBEDTLS_AES_ENCRYPT) {  //设置相应密钥 ret = mbedtls_aes_setkey_enc(aesCtx, (const unsigned char *)ctx->data.key, AES_BYTE_SIZE);    } else { ret = mbedtls_aes_setkey_dec(aesCtx, (const unsigned char *)ctx->data.key, AES_BYTE_SIZE);    }    if (ret != 0) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "aes setkey error."); return ERROR_CODE_GENERAL;    }    //对数据进行加密或解密    ret = mbedtls_aes_crypt_cbc(aesCtx, ctx->data.action, ctx->data.textLen, (unsigned char *)ctx->iv.ivBuf, (const unsigned char *)ctx->data.text, (unsigned char *)ctx->data.text);    if (ret != 0) { //判断加密或解密的成功与否 HILOG_ERROR(HILOG_MODULE_HIVIEW, "aes crypt cbc error, ret:%{public}d.", ret); return ERROR_CODE_GENERAL;    }    if (ctx->data.action == MBEDTLS_AES_ENCRYPT) {  //判断如果当前是加密状态 //为加密后的数据申请地址空间 char *out = MallocEncodeData((const unsigned char *)ctx->data.text, (size_t *)&ctx->data.textLen); free(ctx->data.text);    //释放明文内存空间 ctx->data.text = out;    //上下文中文本数据设置为密文 if (out == NULL) {     return ERROR_CODE_GENERAL; }    } else { ctx->data.textLen = UnpaddingPkcs5(ctx->data.text, ctx->data.textLen);  //如果当前是解密状态,则去除填充位 if (ctx->data.textLen < 0) {     return ERROR_CODE_GENERAL; }    }    return ERROR_SUCCESS;}int32_t InitAesCryptData(const char *action, const char *text, const char *key, const AesIvMode *iv,    AesCryptContext *aesCryptCxt){    if (action == NULL || text == NULL || key == NULL || iv == NULL || aesCryptCxt == NULL) {   //判断传入参数的合法性 return ERROR_CODE_GENERAL;    }    int32_t ret = InitAesData(action, key, text, &(aesCryptCxt->data)); //初始化AES所需数据,并且初始化时失败时,释放Aes相关数据    if (ret != 0) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "fill aes crypt data failed."); DeinitAesCryptData(aesCryptCxt); return ERROR_CODE_GENERAL;    }    ret = InitAesCryptContext(key, iv, aesCryptCxt);    //初始化Aes加解密的上下文语境    if (ret != 0) { HILOG_ERROR(HILOG_MODULE_HIVIEW, "fill aes crypt context failed."); return ERROR_CODE_GENERAL;    }    return ERROR_SUCCESS;}int32_t AesCrypt(AesCryptContext* aesCryptCxt){    if (aesCryptCxt == NULL) { return ERROR_CODE_GENERAL;    }    if (aesCryptCxt->mode == CIPHER_AES_CBC) {  //判断是否为CBC模式 mbedtls_aes_context aes; mbedtls_aes_init(&aes); int32_t ret = DoAesCbcEncrypt(&aes, aesCryptCxt);   //进行加解密 if (ret != ERROR_SUCCESS) { //判断加解密是否成功,未成功时释放资源     HILOG_ERROR(HILOG_MODULE_HIVIEW, "Aes cbc encrypt failed.");     mbedtls_aes_free(&aes);     return ERROR_CODE_GENERAL; } mbedtls_aes_free(&aes); return ERROR_SUCCESS;    } else { HILOG_ERROR(HILOG_MODULE_HIVIEW, "crypt mode not support."); return ERROR_CODE_GENERAL;    }}

老江饲料商城