openssl3.2 - exp - AES-256-GCM

2024-03-08 06:44
文章标签 aes 256 exp gcm openssl3.2

本文主要是介绍openssl3.2 - exp - AES-256-GCM,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • openssl3.2 - exp - AES-256-GCM
    • 概述
    • AES-256-GCM加密入参
    • AES-256-GCM加密出参
    • AES-256-GCM解密入参
    • AES-256-GCM解密出参
    • 笔记
    • END

openssl3.2 - exp - AES-256-GCM

概述

工程中要用到对称加密, 没得选, 要用AES256.
在openssl3.2中, AES256加解密的种类有好多种.
查了资料, 用AE-S256-GCM不错. 如果密文被修改, 就无法解密成功. 不用再另外传HASH给解密一方(让对方自己算是否密文被修改).
AES-256-GCM的明文可以为任意长度, 不需要进行填充对齐(padding).

AES-256-GCM加密入参

PT - 明文
KEY
IV
AAD - 认证数据(双方已经的确定数据), 我这里用的32字节, 等用到的时候, 再试试, 是否可以为不规则长度的数据, 是否有长度限制

AES-256-GCM加密出参

RC - 1为TRUE, 0为失败
CT - 密文
TAG - 16字节, 解密时要用

AES-256-GCM解密入参

CT - 密文
KEY
IV
AAD - 同加密时是一个东西
TAG - 加密出参返回的16个字节的TAG

AES-256-GCM解密出参

CT-PT 解密后的明文
如果密文被修改, 就不可能解密成功

笔记

/*!
* \file main.cpp
* \note openssl3.2 - exp - AES-256-GCM
* AES-256-GCM可以知道密文是否被修改, 而普通的AES-256直接无脑解密
*///! \note assert()只在debug版下生效
//! 如果是release版, 相当于没有assert()括号中的那些内容
//! 所以, 不要将逻辑代码放到断言中. 如果是要加断言, 也要判断逻辑代码执行完后的标记值.#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/core_names.h>#include <stdlib.h>
#include <stdio.h>
#include <assert.h>#include "CMemHookRec.h"void my_openssl_app();// ct means 密文输出
// pt means 明文
// add means 附加认证数据
bool enc_aes_256_gcm(OUT UCHAR* ct, OUT int& len_ct, UCHAR* pt, int len_pt, UCHAR* key, int len_key, UCHAR* iv, int len_iv, UCHAR* aad, int len_aad, OUT UCHAR* tag, IN int len_tag);
bool dec_aes_256_gcm(IN UCHAR* ct, IN int len_ct, OUT UCHAR* pt, OUT int& len_pt, UCHAR* key, int len_key, UCHAR* iv, int len_iv, UCHAR* aad, int len_aad, IN UCHAR* tag, IN int len_tag);int main(int argc, char** argv)
{setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞mem_hook();my_openssl_app();mem_unhook();return 0;
}char int2char(int i)
{char c_rc = '\0';i = i % 0x10;if ((i >= 0) && (i <= 9)){c_rc = '0' + i;}else if ((i >= 0x0A) && (i <= 0x0F)){c_rc = 'A' + (i - 0x0A);}else {assert(false);}return c_rc;
}// #define SIM_CT_MODIFY // 定义此宏, 模拟密文被修改后再解密的错误void my_openssl_app()
{	// 算法参数UCHAR gcm_key[32];size_t gcm_keylen = sizeof(gcm_key);UCHAR gcm_iv[32];size_t gcm_ivlen = sizeof(gcm_iv);// 附加认证数据(选择加解密双方都知道的确定数据就行)UCHAR gcm_aad[32];int gcm_addlen = sizeof(gcm_aad);int i_rc = 0;char gcm_pt[4 * 1024 - 3]; // GCM明文int i = 0;char gcm_ct[4 * 1024]; // CGM密文int len_ct = sizeof(gcm_ct);char gcm_ct_pt[4 * 1024]; // CGM密文解密后的明文int len_ct_pt = sizeof(gcm_ct_pt);// 加密时, 返回密文和TAG// 解密时, 要给加密返回的TAGUCHAR gcm_tag[16]; // 单步openssl实现, tag最多16个字节, 否则报错bool b_rc = false;do {// 准备GCM明文for (i = 0; i < sizeof(gcm_pt); i++){gcm_pt[i] = int2char(i);}// 准备gcm keyi_rc = RAND_bytes(gcm_key, sizeof(gcm_key));if (1 != i_rc){assert(false);break;}// 准备gcm ivi_rc = RAND_bytes(gcm_iv, sizeof(gcm_iv));if (1 != i_rc){assert(false);break;}// 初始化aad(实际应用中, 这个gcm_aad是双方都知道的确定数据)i_rc = RAND_bytes(gcm_aad, sizeof(gcm_aad));if (1 != i_rc){assert(false);break;}// 加解密时的入参(key, iv, aad)都是一样的// 加密后, 会返回密文和TAG, tag最多16个字节, tag解密时要用if (!enc_aes_256_gcm((UCHAR*)gcm_ct, len_ct, (UCHAR*)gcm_pt, sizeof(gcm_pt), gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), gcm_aad, sizeof(gcm_aad), gcm_tag, sizeof(gcm_tag))){assert(false);break;}// 解密时, 要给出密文和tag, 返回解密后的明文if (!dec_aes_256_gcm((UCHAR*)gcm_ct, len_ct, (UCHAR*)gcm_ct_pt, len_ct_pt, gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), gcm_aad, sizeof(gcm_aad), gcm_tag, sizeof(gcm_tag))){assert(false);break;}// 比较原始明文和解密后的明文是否一致if (len_ct_pt != sizeof(gcm_pt)){assert(false);break;}i_rc = memcmp(gcm_pt, gcm_ct_pt, sizeof(gcm_pt));if (0 != i_rc){assert(false);break;}#ifdef SIM_CT_MODIFY// 模拟密文被修改的情况, 这时用普通的AES256解密是验证不出来密文是否被修改(都是buffer), 而AES-256-GCM可以// 解密时, 要给出密文和tag, 返回解密后的明文gcm_ct[0] = gcm_ct[0] + 1;// 在dec_aes_256_gcm()中的 EVP_DecryptFinal_ex()处, 就执行失败if (!dec_aes_256_gcm((UCHAR*)gcm_ct, len_ct, (UCHAR*)gcm_ct_pt, len_ct_pt, gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), gcm_aad, sizeof(gcm_aad), gcm_tag, sizeof(gcm_tag))){assert(false);break;}// 比较原始明文和解密后的明文是否一致if (len_ct_pt != sizeof(gcm_pt)){assert(false);break;}i_rc = memcmp(gcm_pt, gcm_ct_pt, sizeof(gcm_pt));if (0 != i_rc){assert(false);break;}
#endif // #ifdef SIM_CT_MODIFYb_rc = true;} while (false);assert(true == b_rc);
}bool enc_aes_256_gcm(OUT UCHAR* ct, OUT int& len_ct, UCHAR* pt, int len_pt, UCHAR* key, int len_key, UCHAR* iv, int len_iv, UCHAR* aad, int len_aad, OUT UCHAR* tag, IN int len_tag)
{// openssl库上下文和属性OSSL_LIB_CTX* libctx = NULL;const char* propq = NULL;// 算法上下文和算法指针EVP_CIPHER_CTX* ctx = NULL;EVP_CIPHER* cipher = NULL;OSSL_PARAM gcm_params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };size_t gcm_ivlen = 0;bool b_rc = false;int i_rc = 0;int tmplen = 0;do {if ((NULL == ct) || (len_ct <= 0) || (NULL == pt) || (len_pt <= 0) || (len_ct < len_pt)){assert(false);break;}if ((NULL == key) || (len_key <= 0) || (NULL == iv) || (len_iv <= 0)){assert(false);break;}ctx = EVP_CIPHER_CTX_new();assert(NULL != ctx);if (NULL == ctx){break;}cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq);assert(NULL != cipher);if (NULL == cipher){break;}gcm_ivlen = len_iv;gcm_params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, &gcm_ivlen);i_rc = EVP_EncryptInit_ex2(ctx, cipher, key, iv, gcm_params);assert(1 == i_rc);if (1 != i_rc){break;}// set aad to ctxtmplen = 0;i_rc = EVP_EncryptUpdate(ctx, NULL, &tmplen, aad, len_aad);assert(1 == i_rc);if (1 != i_rc){break;}assert(tmplen == len_aad);if (tmplen != len_aad){break;}assert(len_pt <= len_ct);if (len_pt > len_ct){break;}i_rc = EVP_EncryptUpdate(ctx, ct, &len_ct, pt, len_pt);assert(1 == i_rc);if (1 != i_rc){break;}assert(len_ct == len_pt);if (len_ct != len_pt){break;}// get no output's enc texti_rc = EVP_EncryptFinal_ex(ctx, ct + len_ct, &tmplen);assert(1 == i_rc);if (tmplen > 0){len_ct += tmplen;}/* Get tag */// aes-256-gcm加密完, 除了输出密文, 还输出tag.// 输出的密文和tag给解密用gcm_params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, tag, len_tag);i_rc = EVP_CIPHER_CTX_get_params(ctx, gcm_params);assert(1 == i_rc);if (1 != i_rc){break;}b_rc = true;} while (false);if (NULL != cipher){EVP_CIPHER_free(cipher);}if (NULL != ctx){EVP_CIPHER_CTX_free(ctx);}return b_rc;
}bool dec_aes_256_gcm(IN UCHAR* ct, IN int len_ct, OUT UCHAR* pt, OUT int& len_pt, UCHAR* key, int len_key, UCHAR* iv, int len_iv, UCHAR* aad, int len_aad, IN UCHAR* tag, IN int len_tag)
{// openssl库上下文和属性OSSL_LIB_CTX* libctx = NULL;const char* propq = NULL;// 算法上下文和算法指针EVP_CIPHER_CTX* ctx = NULL;EVP_CIPHER* cipher = NULL;OSSL_PARAM gcm_params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };size_t gcm_ivlen = 0;bool b_rc = false;int i_rc = 0;int tmplen = 0;do {if ((NULL == ct) || (len_ct <= 0) || (NULL == pt) || (len_pt <= 0) || (len_ct > len_pt)){assert(false);break;}if ((NULL == key) || (len_key <= 0) || (NULL == iv) || (len_iv <= 0)){assert(false);break;}ctx = EVP_CIPHER_CTX_new();if (NULL == ctx){assert(false);break;}cipher = EVP_CIPHER_fetch(libctx, "AES-256-GCM", propq);if (NULL == cipher){assert(false);break;}gcm_ivlen = len_iv;gcm_params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, &gcm_ivlen);i_rc = EVP_DecryptInit_ex2(ctx, cipher, key, iv, gcm_params);if (1 != i_rc){assert(false);break;}// set aad to ctxtmplen = 0;i_rc = EVP_DecryptUpdate(ctx, NULL, &tmplen, aad, len_aad);if ((1 != i_rc) || (tmplen != len_aad)){assert(false);break;}i_rc = EVP_DecryptUpdate(ctx, pt, &len_pt, ct, len_ct);if (1 != i_rc){assert(false);break;}/* Set expected tag value. */gcm_params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, (void*)tag, len_tag);i_rc = EVP_CIPHER_CTX_set_params(ctx, gcm_params);if (1 != i_rc){assert(false);break;}/* Finalise: note get no output for GCM */i_rc = EVP_DecryptFinal_ex(ctx, pt + len_pt, &tmplen);if (1 != i_rc){// 如果密文被修改, 到这里就有断言assert(false);break;}if (tmplen > 0){len_pt += tmplen;}b_rc = true;} while (false);if (NULL != cipher){EVP_CIPHER_free(cipher);}if (NULL != ctx){EVP_CIPHER_CTX_free(ctx);}return b_rc;
}

END

这篇关于openssl3.2 - exp - AES-256-GCM的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/786337

相关文章

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

linux 内核提权总结(demo+exp分析) -- 任意读写(四)

hijack_modprobe_path篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     原理同hijack_prctl, 当用户执行错误格式的elf文件时内核调用call_usermod

linux 内核提权总结(demo+exp分析) -- 任意读写(三)

hijack_prctl篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   prctl函数: 用户态函数,可用于定制进程参数,非常适合和内核进行交互 用户态执行prctl函数后触发prctl系统

linux 内核提权总结(demo+exp分析) -- 任意读写(二)

hijack_vdso篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm     vdso: 内核实现的一个动态库,存在于内核,然后映射到用户态空间,可由用户态直接调用 内核中的vdso如果被修改

linux 内核提权总结(demo+exp分析) -- 任意读写(一)

cred篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   每个线程在内核中都对应一个线程结构块thread_infothread_info中存在task_struct类型结构体 struct t

linux 内核提权总结(demo+exp分析) -- ROP(二)

ret2usr CR4篇 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   smep: smep是内核的一种保护措施, 使得内核不可执行用户态代码 内核通过CR4寄存器的第20位来控制smep,

linux 内核提权总结(demo+exp分析) -- ROP(一)

基础ROP篇(linux 5.0.21) 本文转自网络文章,内容均为非盈利,版权归原作者所有。 转载此文章仅为个人收藏,分享知识,如有侵权,马上删除。 原文作者:jmpcall 专栏地址:https://zhuanlan.kanxue.com/user-815036.htm   内核提权与用户态攻击的区别 攻击流程 用户态攻击: 执行 system("/bin/sh") 获得shel

王立平--AES加密图片实现 SkImageDecoder::Factory return null

这个问题是在加密图片,存入sd卡,在解密出来展示,出现的。我个人研究了很久没解决。最后经过高人指点,终于解决了。 在此,拿出来分享,希望各位少走弯路。 我之前的设计思路是:(可以不看哦) 1.把图片从drawable读入成bitmap 2.bitmap-->byte 3.调用AES的byte加密算法。 4.加密成byte,在转化为string 5,把string存入sd卡。

AtCoder Beginner Contest 369 D - Bonus EXP 动态规划

原题链接: https://atcoder.jp/contests/abc369/tasks/abc369_d 思路:   这道题为什么要用动态规划呢,其实,对于第i个怪物,我们有打与不打两种处理方式,而对于打,我们是获得两倍的经验值,还是一倍的经验值,与我们打了奇数只怪物还是打了偶数只怪物有关了,因此我们定义dp[i][0] 为前i只怪物总共打了偶数次,dp[i][1] 为前i只怪物总

AES加密算法说明

首先,我们得了解AES加密算法的一些基本概念。AES是一种对称加密算法,所谓对称,是说它的加密、解密过程使用相同的密钥。还有非对称加密算法,例如RSA,加密解密使用的是公私钥对。 AES同时是一种分组加密算法,分组的长度一般是16字节(128bit)。分组是什么意思呢?假设我有一段很长的明文T,我没法用AES加密整个T,只能将T分成若干16byte的明文组,接着对这些明文组逐个进行加密,得到一堆密