IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 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;
    }
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-27 14:21:50  更:2021-09-27 14:23:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 12:12:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码