文章目录
- openssl3.2 - exp - aes-128-cbc
- 概述
- 笔记
- openssl 命令行实现
- 简单直白的实现
- 简单直白的实现 - 测试效果
- 简单直白的实现 - 测试工程
- 周全灵活的实现
- 周全灵活的实现 - 测试效果
- 周全灵活的实现 - 测试工程
- END
openssl3.2 - exp - aes-128-cbc
概述
想将工程中用到的字符串明文用openssl的对称加密算法加密一下, 防止逆向静态分析, 只作为字符串编码/解码的作用.
只是为了防止逆向静态分析, 起到一个编码/解码作用, 不介意别人知道密钥是啥.
看了一下openssl性能(AES性能大概是2000MB/秒, AES256比AES128稍低)
D:\my_dev\my_local_git_prj\study\openSSL\exp\exp029_enc\aes-128-cbc\doc>openssl speed -mlock -seconds 1 -bytes 4096 aes-128-cbc
Doing aes-128-cbc ops for 1s on 4096 size blocks: 567655 aes-128-cbc ops in 1.02s
version: 3.2.0
built on: Sun Feb 25 02:20:27 2024 UTC
options: bn(64,64)
compiler: cl /Zi /Fdossl_static.pdb /Gs0 /GF /Gy /MDd /W3 /wd4090 /nologo /Od -DLIBZ=".\\\\my_zlib_1d3.dll" -DL_ENDIAN -DOPENSSL_PIC -D"OPENSSL_BUILDING_OPENSSL" -D"ZLIB" -D"ZLIB_SHARED" -D"OPENSSL_SYS_WIN32" -D"WIN32_LEAN_AND_MEAN" -D"UNICODE" -D"_UNICODE" -D"_CRT_SECURE_NO_DEPRECATE" -D"_WINSOCK_DEPRECATED_NO_WARNINGS" -D"DEBUG" -D"_DEBUG" -I"D:\\my_dev\\lib\\zlib_1d3"
CPUINFO: OPENSSL_ia32cap=0x7ffaf3ffffebffff:0x18c07fcef3bfa7eb
The 'numbers' are in 1000s of bytes per second processed. // 处理的“数字”以每秒1000字节为单位
type 4096 bytes
aes-128-cbc 2289343.88k => 2289343.88 * 1000 / 1024 / 1024 = 2183 MB/秒D:\my_dev\my_local_git_prj\study\openSSL\exp\exp029_enc\aes-128-cbc\doc>openssl speed -mlock -seconds 1 -bytes 4096 aes-256-cbc
Doing aes-256-cbc ops for 1s on 4096 size blocks: 414597 aes-256-cbc ops in 1.02s
version: 3.2.0
built on: Sun Feb 25 02:20:27 2024 UTC
options: bn(64,64)
compiler: cl /Zi /Fdossl_static.pdb /Gs0 /GF /Gy /MDd /W3 /wd4090 /nologo /Od -DLIBZ=".\\\\my_zlib_1d3.dll" -DL_ENDIAN -DOPENSSL_PIC -D"OPENSSL_BUILDING_OPENSSL" -D"ZLIB" -D"ZLIB_SHARED" -D"OPENSSL_SYS_WIN32" -D"WIN32_LEAN_AND_MEAN" -D"UNICODE" -D"_UNICODE" -D"_CRT_SECURE_NO_DEPRECATE" -D"_WINSOCK_DEPRECATED_NO_WARNINGS" -D"DEBUG" -D"_DEBUG" -I"D:\\my_dev\\lib\\zlib_1d3"
CPUINFO: OPENSSL_ia32cap=0x7ffaf3ffffebffff:0x18c07fcef3bfa7eb
The 'numbers' are in 1000s of bytes per second processed.
type 4096 bytes
aes-256-cbc 1672063.32k
用openssl speed 列出的算法(openssl3.2 - exp - openssl speed test), 想选其他强度更低(速度更快)的其他对称加密算法, 好像没有啊. 非主流的算法, 用openssl speed都不能测试
那就拿AES128来弄吧.
笔记
openssl 命令行实现
// enc
openssl enc -aes-128-cbc -e -in pt.txt -out pt.txt.enc -k my_pwd_for_enc -pbkdf2// dec
openssl enc -aes-128-cbc -d -in pt.txt.enc -out pt.txt.enc.dec -k my_pwd_for_enc -pbkdf2
将命令行作为参数代进入, 跟一下openssl命令行工程, 就可以得到C实现(基于openssl API)
简单直白的实现
在查资料过程中, 发现官方测试代码中有一个直白的实现, 自己先弄一个工程试试. 然后再跟官方命令行的实现.
在openssl源码中, 看到了 D:\3rd_prj\crypt\openssl-3.2.0\test\afalgtest.c, 测试了aes-128-cbc, 实现特别简单.
简单直白的实现 - 测试效果
before enc:
0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f ................
0010 - 10 11 12 13 14 15 16 17-18 19 1a 1b 1c 1d 1e 1f ................
0020 - 20 21 22 23 24 25 26 27-28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
0030 - 30 31 32 33 34 35 36 37-38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
0040 - 40 41 42 43 44 45 46 47-48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
0050 - 50 51 52 53 54 55 56 57-58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
0060 - 60 61 62 63 64 65 66 67-68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
0070 - 70 71 72 73 74 75 76 77-78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.
0080 - 80 81 82 83 84 85 86 87-88 89 8a 8b 8c 8d 8e 8f ................
0090 - 90 91 92 93 94 95 96 97-98 99 9a 9b 9c 9d 9e 9f ................
00a0 - a0 a1 a2 a3 a4 a5 a6 a7-a8 a9 aa ab ac ad ae af ................
00b0 - b0 b1 b2 b3 b4 b5 b6 b7-b8 b9 ba bb bc bd be bf ................
00c0 - c0 c1 c2 c3 c4 c5 c6 c7-c8 c9 ca cb cc cd ce cf ................
00d0 - d0 d1 d2 d3 d4 d5 d6 d7-d8 d9 da db dc dd de df ................
00e0 - e0 e1 e2 e3 e4 e5 e6 e7-e8 e9 ea eb ec ed ee ef ................
00f0 - f0 f1 f2 f3 f4 f5 f6 f7-f8 f9 fa fb fc .............
after enc:
0000 - c6 a1 3b 37 87 8f 5b 82-6f 4f 81 62 a1 c8 d8 79 ..;7..[.oO.b...y
0010 - 35 d9 dc db 82 9f ec 33-52 e7 bf 10 b8 4b e4 a5 5......3R....K..
0020 - 7b 30 46 46 05 f0 2a 09-4c 0a f7 ad 98 4f 61 fc {0FF..*.L....Oa.
0030 - d8 84 34 a5 59 1d bc 8f-d9 63 08 12 d3 a2 7b 87 ..4.Y....c....{.
0040 - 25 cc 26 ee 46 93 13 40-c1 a9 f1 0d 82 2e aa e3 %.&.F..@........
0050 - 69 f3 ff d0 fc b1 a1 5e-a0 dc d6 c1 75 07 9d 45 i......^....u..E
0060 - 37 d1 e1 58 ec 3d 2f 67-07 de 48 12 5f c4 a4 cb 7..X.=/g..H._...
0070 - 22 62 2b 9d d6 ea 3d 1e-ec c9 c1 5e 53 ea 33 8b "b+...=....^S.3.
0080 - 92 3a b9 cc 0f cc 8d 8d-da 45 57 a7 09 e5 3e e1 .:.......EW...>.
0090 - 24 0d fb bb 4e 93 18 85-7e 4b 84 2a 9d ae 3c 2d $...N...~K.*..<-
00a0 - 72 7a 39 39 db 64 24 ed-ba 80 e6 f8 98 d8 35 a7 rz99.d$.......5.
00b0 - 43 13 b6 bd aa ca e7 03-11 e9 97 63 c6 f2 36 7f C..........c..6.
00c0 - ab 39 b5 fd 1b 4c 34 1f-49 99 b3 06 ff 3e 77 2a .9...L4.I....>w*
00d0 - df 3f e7 db 00 43 48 99-6f bc b9 43 34 66 50 8e .?...CH.o..C4fP.
00e0 - f6 0a 2d d3 1a cc 9e d1-36 98 89 40 60 40 3a 48 ..-.....6..@`@:H
00f0 - c6 f1 c5 38 48 65 68 06-b5 df ac ed 84 74 d7 be ...8Heh......t..
after dec:
0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f ................
0010 - 10 11 12 13 14 15 16 17-18 19 1a 1b 1c 1d 1e 1f ................
0020 - 20 21 22 23 24 25 26 27-28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
0030 - 30 31 32 33 34 35 36 37-38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
0040 - 40 41 42 43 44 45 46 47-48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
0050 - 50 51 52 53 54 55 56 57-58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
0060 - 60 61 62 63 64 65 66 67-68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
0070 - 70 71 72 73 74 75 76 77-78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.
0080 - 80 81 82 83 84 85 86 87-88 89 8a 8b 8c 8d 8e 8f ................
0090 - 90 91 92 93 94 95 96 97-98 99 9a 9b 9c 9d 9e 9f ................
00a0 - a0 a1 a2 a3 a4 a5 a6 a7-a8 a9 aa ab ac ad ae af ................
00b0 - b0 b1 b2 b3 b4 b5 b6 b7-b8 b9 ba bb bc bd be bf ................
00c0 - c0 c1 c2 c3 c4 c5 c6 c7-c8 c9 ca cb cc cd ce cf ................
00d0 - d0 d1 d2 d3 d4 d5 d6 d7-d8 d9 da db dc dd de df ................
00e0 - e0 e1 e2 e3 e4 e5 e6 e7-e8 e9 ea eb ec ed ee ef ................
00f0 - f0 f1 f2 f3 f4 f5 f6 f7-f8 f9 fa fb fc .............
enc / dec all ok
free map, g_mem_hook_map.size() = 0D:\my_dev\my_local_git_prj\study\openSSL\exp\exp029_enc\aes-128-cbc\prj-aes-128-cbc-simple\x64\Debug\prj-aes-128-cbc-simple.exe (进程 276104)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
简单直白的实现 - 测试工程
/*!
* \file prj-aes-128-cbc-simple
*/#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>#include <stdlib.h>
#include <stdio.h>
#include <assert.h>#include "CMemHookRec.h"#include <openssl/evp.h>void my_openssl_app();bool aes_128_cbc_EncDec(bool isEnc,IN const UCHAR* pszBufIn, IN int lenBufIn, IN const UCHAR* key, IN int lenKey,IN const UCHAR* iv, IN int lenIv,OUT UCHAR*& pOutBuf, OUT int& lenOutBuf);int main(int argc, char** argv)
{setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞mem_hook();my_openssl_app();mem_unhook();return 0;
}void my_openssl_app()
{UCHAR ucBuf[0x100 - 3];int lenBuf = sizeof(ucBuf);int i = 0;UCHAR* pEncBuf = NULL;int lenEncBuf = 0;UCHAR* pDecBuf = NULL;int lenDecBuf = 0;// 可以在EVP_CipherInit_ex()之后, 用EVP_CIPHER_CTX_get_key_length()/EVP_CIPHER_CTX_get_iv_length()看长度UCHAR key[0x10]; // aes-128-cbc's key len = 0x10UCHAR iv[0x10]; // aes-128-cbc's iv len = 0x10for (i = 0; i < 0x10; i++){key[i] = (UCHAR)i;iv[i] = (UCHAR)i;}for (i = 0; i < lenBuf; i++){ucBuf[i] = (UCHAR)i;}do {printf("before enc:\n");BIO_dump_fp(stdout, ucBuf, lenBuf);// enc// // 如果输入不是0x10对齐, 加密后, 就会自动0x10对齐(多出几个字节)// 所以要自己记录加密前的长度, 且加密时, 要将输出(加密后)buffer 16对齐(或直接比输入的长度多16字节)// 且加密后, 要自己记录加密后的长度if (!aes_128_cbc_EncDec(true, ucBuf, lenBuf, (UCHAR*)key, sizeof(key), (UCHAR*)iv, sizeof(iv), pEncBuf, lenEncBuf)){assert(false);break;}// printf("enc before lenBuf = %d, enc after lenEncBuf = %d\n", lenBuf, lenEncBuf);// enc before lenBuf = 253, enc after lenEncBuf = 256printf("after enc:\n");BIO_dump_fp(stdout, pEncBuf, lenEncBuf);// decif (!aes_128_cbc_EncDec(false, pEncBuf, lenEncBuf, (UCHAR*)key, sizeof(key), (UCHAR*)iv, sizeof(iv), pDecBuf, lenDecBuf)){assert(false);break;}// 解密后的数据长度和解密前一样了printf("after dec:\n");BIO_dump_fp(stdout, pDecBuf, lenDecBuf);// 比较明文和解密后的明文是否相同if ((lenDecBuf != lenBuf) || (0 != memcmp(ucBuf, pDecBuf, lenBuf))){assert(false);break;}printf("enc / dec all ok\n");} while (false);if (NULL != pEncBuf){OPENSSL_free(pEncBuf);pEncBuf = NULL;}if (NULL != pDecBuf){OPENSSL_free(pDecBuf);pDecBuf = NULL;}
}bool aes_128_cbc_EncDec(bool isEnc,IN const UCHAR* pszBufIn, IN int lenBufIn,IN const UCHAR* key, IN int lenKey,IN const UCHAR* iv, IN int lenIv,OUT UCHAR*& pOutBuf, OUT int& lenOutBuf)
{bool b_rc = false;int i_rc = 0;int i_tmp = 0;const EVP_CIPHER* _evp_chipher = NULL;EVP_CIPHER_CTX* _evp_cipher_ctx = NULL;do {if ((NULL == pszBufIn) || (lenBufIn <= 0) || (NULL == key) || (lenKey <= 0) ||(NULL == iv) || (lenIv <= 0)){break;}_evp_chipher = EVP_aes_128_cbc();_evp_cipher_ctx = EVP_CIPHER_CTX_new();if (NULL == _evp_cipher_ctx){break;}i_rc = EVP_CipherInit_ex(_evp_cipher_ctx, _evp_chipher, NULL, key, iv, (isEnc ? 1 : 0));if (1 != i_rc){break;}i_tmp = EVP_CIPHER_CTX_get_key_length(_evp_cipher_ctx);if (i_tmp != lenKey){break;}i_tmp = EVP_CIPHER_CTX_get_iv_length(_evp_cipher_ctx);if (i_tmp != lenIv){break;}lenOutBuf = 0;pOutBuf = (UCHAR*)OPENSSL_malloc(lenBufIn + 0x10); // 输出必须比输入大0x10if (NULL == pOutBuf){break;}i_tmp = 0;lenOutBuf = 0;// 如果lenBufIn不是16整除, update 还剩下一个尾巴的数据(len < 0x10)i_rc = EVP_CipherUpdate(_evp_cipher_ctx, pOutBuf, &i_tmp, pszBufIn, lenBufIn);if (1 != i_rc){break;}lenOutBuf += i_tmp;i_tmp = 0;i_rc = EVP_CipherFinal_ex(_evp_cipher_ctx, pOutBuf + lenOutBuf, &i_tmp);if (1 != i_rc){break;}lenOutBuf += i_tmp;b_rc = true;} while (false);if (NULL != _evp_cipher_ctx){EVP_CIPHER_CTX_free(_evp_cipher_ctx);_evp_cipher_ctx = NULL;}return b_rc;
}
周全灵活的实现
单步openssl 命令行(openssl enc -aes-128-cbc …)的实现, 如果口令给的强度不够, 会加沙.
用BIO链的方式加密, 不用自己分别调用具体的加密API, 用起来简单.
不过, 这个实现的前提是知道上一个简单直白的方法(最直接的调用openssl API), 知道对应算法的key/iv的数据长度
跟了一下官方实现, 没全用.
官方考虑了弱密码的情况, 会根据参数加沙和用pbkdf2(KDF是基于弱密码生成新密码), 然后再用BIO链条完成加密.
我自己用时, 知道每种算法的key, iv长度, 会自己用随机数填满, 就没必要基于KDF来从输入的弱口令生成新的实际加密的密码.
我只用了BIO链的方式加密.
BIO链干活的好处:
- 算法都是针对BIO链头操作, e.g. 加密时, 只需要向BIO链头写输入数据, 等全部写完(执行BIO_flush(BIO链头)), 只需要再从BIO链头读东西, 就是加密完成的内容. 用起来方便.
- 如果对输入数据的操作不是一个加密操作, 而是很多操作(e.g. 对称加密, 做hash…), 只需要加入新的BIO节点(通过BIO_push()来控制BIO链中的BIO对象执行顺序), 其他代码不用动, 对于维护友好.
如果只是干一个简单的活(e.g. 针对一块数据加密), 那就用第一种那样直白的方法.
等以后有机会找找官方实现中, 是否有BIO链条大于2个节点的实现, 也继续学习一下.
官方实现中, 是文件到文件的加/解密, 我改成了针对buffer的加/解密.
周全灵活的实现 - 测试效果
before enc:
0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f ................
0010 - 10 11 12 13 14 15 16 17-18 19 1a 1b 1c 1d 1e 1f ................
0020 - 20 21 22 23 24 25 26 27-28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
0030 - 30 31 32 33 34 35 36 37-38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
0040 - 40 41 42 43 44 45 46 47-48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
0050 - 50 51 52 53 54 55 56 57-58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
0060 - 60 61 62 63 64 65 66 67-68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
0070 - 70 71 72 73 74 75 76 77-78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.
0080 - 80 81 82 83 84 85 86 87-88 89 8a 8b 8c 8d 8e 8f ................
0090 - 90 91 92 93 94 95 96 97-98 99 9a 9b 9c 9d 9e 9f ................
00a0 - a0 a1 a2 a3 a4 a5 a6 a7-a8 a9 aa ab ac ad ae af ................
00b0 - b0 b1 b2 b3 b4 b5 b6 b7-b8 b9 ba bb bc bd be bf ................
00c0 - c0 c1 c2 c3 c4 c5 c6 c7-c8 c9 ca cb cc cd ce cf ................
00d0 - d0 d1 d2 d3 d4 d5 d6 d7-d8 d9 da db dc dd de df ................
00e0 - e0 e1 e2 e3 e4 e5 e6 e7-e8 e9 ea eb ec ed ee ef ................
00f0 - f0 f1 f2 f3 f4 f5 f6 f7-f8 f9 fa fb fc .............
after enc:
0000 - c6 a1 3b 37 87 8f 5b 82-6f 4f 81 62 a1 c8 d8 79 ..;7..[.oO.b...y
0010 - 35 d9 dc db 82 9f ec 33-52 e7 bf 10 b8 4b e4 a5 5......3R....K..
0020 - 7b 30 46 46 05 f0 2a 09-4c 0a f7 ad 98 4f 61 fc {0FF..*.L....Oa.
0030 - d8 84 34 a5 59 1d bc 8f-d9 63 08 12 d3 a2 7b 87 ..4.Y....c....{.
0040 - 25 cc 26 ee 46 93 13 40-c1 a9 f1 0d 82 2e aa e3 %.&.F..@........
0050 - 69 f3 ff d0 fc b1 a1 5e-a0 dc d6 c1 75 07 9d 45 i......^....u..E
0060 - 37 d1 e1 58 ec 3d 2f 67-07 de 48 12 5f c4 a4 cb 7..X.=/g..H._...
0070 - 22 62 2b 9d d6 ea 3d 1e-ec c9 c1 5e 53 ea 33 8b "b+...=....^S.3.
0080 - 92 3a b9 cc 0f cc 8d 8d-da 45 57 a7 09 e5 3e e1 .:.......EW...>.
0090 - 24 0d fb bb 4e 93 18 85-7e 4b 84 2a 9d ae 3c 2d $...N...~K.*..<-
00a0 - 72 7a 39 39 db 64 24 ed-ba 80 e6 f8 98 d8 35 a7 rz99.d$.......5.
00b0 - 43 13 b6 bd aa ca e7 03-11 e9 97 63 c6 f2 36 7f C..........c..6.
00c0 - ab 39 b5 fd 1b 4c 34 1f-49 99 b3 06 ff 3e 77 2a .9...L4.I....>w*
00d0 - df 3f e7 db 00 43 48 99-6f bc b9 43 34 66 50 8e .?...CH.o..C4fP.
00e0 - f6 0a 2d d3 1a cc 9e d1-36 98 89 40 60 40 3a 48 ..-.....6..@`@:H
00f0 - c6 f1 c5 38 48 65 68 06-b5 df ac ed 84 74 d7 be ...8Heh......t..
after dec:
0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f ................
0010 - 10 11 12 13 14 15 16 17-18 19 1a 1b 1c 1d 1e 1f ................
0020 - 20 21 22 23 24 25 26 27-28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./
0030 - 30 31 32 33 34 35 36 37-38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>?
0040 - 40 41 42 43 44 45 46 47-48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
0050 - 50 51 52 53 54 55 56 57-58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
0060 - 60 61 62 63 64 65 66 67-68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno
0070 - 70 71 72 73 74 75 76 77-78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~.
0080 - 80 81 82 83 84 85 86 87-88 89 8a 8b 8c 8d 8e 8f ................
0090 - 90 91 92 93 94 95 96 97-98 99 9a 9b 9c 9d 9e 9f ................
00a0 - a0 a1 a2 a3 a4 a5 a6 a7-a8 a9 aa ab ac ad ae af ................
00b0 - b0 b1 b2 b3 b4 b5 b6 b7-b8 b9 ba bb bc bd be bf ................
00c0 - c0 c1 c2 c3 c4 c5 c6 c7-c8 c9 ca cb cc cd ce cf ................
00d0 - d0 d1 d2 d3 d4 d5 d6 d7-d8 d9 da db dc dd de df ................
00e0 - e0 e1 e2 e3 e4 e5 e6 e7-e8 e9 ea eb ec ed ee ef ................
00f0 - f0 f1 f2 f3 f4 f5 f6 f7-f8 f9 fa fb fc .............
enc / dec all ok
free map, g_mem_hook_map.size() = 0D:\my_dev\my_local_git_prj\study\openSSL\exp\exp029_enc\aes-128-cbc\prj-aes-128-cbc\x64\Debug\prj-aes-128-cbc.exe (进程 413000)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
周全灵活的实现 - 测试工程
/*!
* \file prj-aes-128-cbc.cpp
*/#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>#include <stdlib.h>
#include <stdio.h>
#include <assert.h>#include "CMemHookRec.h"#include <openssl/evp.h>
#include <openssl/bioerr.h>
#include <openssl/err.h>void my_openssl_app();
bool aes_128_cbc_EncDec_v1(bool isEnc,IN const UCHAR* pszBufIn, IN int lenBufIn,IN const UCHAR* key, IN int lenKey,IN const UCHAR* iv, IN int lenIv,OUT UCHAR*& pOutBuf, OUT int& lenOutBuf);int main(int argc, char** argv)
{setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞mem_hook();my_openssl_app();mem_unhook();return 0;
}void my_openssl_app()
{UCHAR ucBuf[0x100 - 3];int lenBuf = sizeof(ucBuf);int i = 0;UCHAR* pEncBuf = NULL;int lenEncBuf = 0;UCHAR* pDecBuf = NULL;int lenDecBuf = 0;// 可以在EVP_CipherInit_ex()之后, 用EVP_CIPHER_CTX_get_key_length()/EVP_CIPHER_CTX_get_iv_length()看长度UCHAR key[0x10]; // aes-128-cbc's key len = 0x10UCHAR iv[0x10]; // aes-128-cbc's iv len = 0x10for (i = 0; i < 0x10; i++){key[i] = (UCHAR)i;iv[i] = (UCHAR)i;}for (i = 0; i < lenBuf; i++){ucBuf[i] = (UCHAR)i;}do {printf("before enc:\n");BIO_dump_fp(stdout, ucBuf, lenBuf);// enc// // 如果输入不是0x10对齐, 加密后, 就会自动0x10对齐(多出几个字节)// 所以要自己记录加密前的长度, 且加密时, 要将输出(加密后)buffer 16对齐(或直接比输入的长度多16字节)// 且加密后, 要自己记录加密后的长度if (!aes_128_cbc_EncDec_v1(true, ucBuf, lenBuf, (UCHAR*)key, sizeof(key), (UCHAR*)iv, sizeof(iv), pEncBuf, lenEncBuf)){assert(false);break;}// printf("enc before lenBuf = %d, enc after lenEncBuf = %d\n", lenBuf, lenEncBuf);// enc before lenBuf = 253, enc after lenEncBuf = 256printf("after enc:\n");BIO_dump_fp(stdout, pEncBuf, lenEncBuf);// decif (!aes_128_cbc_EncDec_v1(false, pEncBuf, lenEncBuf, (UCHAR*)key, sizeof(key), (UCHAR*)iv, sizeof(iv), pDecBuf, lenDecBuf)){assert(false);break;}// 解密后的数据长度和解密前一样了printf("after dec:\n");BIO_dump_fp(stdout, pDecBuf, lenDecBuf);// 比较明文和解密后的明文是否相同if ((lenDecBuf != lenBuf) || (0 != memcmp(ucBuf, pDecBuf, lenBuf))){assert(false);break;}printf("enc / dec all ok\n");} while (false);if (NULL != pEncBuf){OPENSSL_free(pEncBuf);pEncBuf = NULL;}if (NULL != pDecBuf){OPENSSL_free(pDecBuf);pDecBuf = NULL;}
}bool aes_128_cbc_EncDec_v1(bool isEnc,IN const UCHAR* pszBufIn, IN int lenBufIn,IN const UCHAR* key, IN int lenKey,IN const UCHAR* iv, IN int lenIv,OUT UCHAR*& pOutBuf, OUT int& lenOutBuf)
{bool b_rc = false;const EVP_CIPHER* c = NULL;const EVP_MD* dgst = NULL;BIO* bio_in = NULL;BIO* bio_out = NULL;BIO* bio_filter = NULL;int i_tmp = 0;int i_rc = 0;int i_out_len_all = 0;size_t sz_rd = 0;size_t sz_wt = 0;const char* psz = NULL;EVP_CIPHER_CTX* _evp_cipher_ctx = NULL;UCHAR ucBufRd[1024];do {lenOutBuf = 0;if ((NULL == pszBufIn) || (lenBufIn <= 0) ||(NULL == key) || (lenKey <= 0) ||(NULL == iv) || (lenIv <= 0)){break;}c = EVP_aes_128_cbc(); // 这是最初的加密, 没有任何保护的代码, 不用EVP_CIPHER_fetch()来暴露算法名称字符串// 可以从算法对象得到算法名称//psz = EVP_CIPHER_get0_name(c);//printf("EVP_aes_128_cbc()'s alg name is : %s\n", psz);// EVP_aes_128_cbc()'s alg name is : AES-128-CBCi_tmp = EVP_CIPHER_get_key_length(c);if (i_tmp != lenKey){break;}i_tmp = EVP_CIPHER_get_iv_length(c);if (i_tmp != lenIv){break;}dgst = EVP_sha256(); // 这是最初的加密, 没有任何保护的代码, 不用EVP_MD_fetch()来暴露算法名称字符串bio_in = BIO_new_mem_buf(pszBufIn, lenBufIn);if (NULL == bio_in){break;}bio_filter = BIO_new(BIO_f_cipher());// BIO_set_cipher(bio_out, c, key, iv, (isEnc ? 1 : 0));// 由于要改变算法的上下文, 所以要调用BIO_get_cipher_ctx, 而不是调用BIO_set_cipher// 此时 _evp_cipher_ctx 是 NULL// !!! _evp_cipher_ctx 是从bio_filter取出来的, 不能自己新建ctx, 否则向bio_filter写东西时, 就不会加密了, 因为上下文不对BIO_get_cipher_ctx(bio_filter, &_evp_cipher_ctx); // 这里将bio和算法上下文关联了// 此时 _evp_cipher_ctx 不为空, 是bio_filter要用到的算法ctx地址// 向ctx中单独设置加密算法/key/iv// 官方原版实现是分成2步(先设置算法, 再设置key/iv, 有点脱裤子放屁的感觉)if (!EVP_CipherInit_ex(_evp_cipher_ctx, c, NULL, key, iv, (isEnc ? 1 : 0))) {// ERR_print_errors(bio_err);ERR_print_errors_fp(stderr);break;}bio_out = BIO_new(BIO_s_mem());if (NULL == bio_out){break;}// BIO_push返回的就是参数1 bio_out// 释放时, 只需要 BIO_free_all(bio_filter), 不用管bio_out, 因为 bio_out已经加入bio_filter链// !!! 必须向 bio_filter中显势写入从明文bio_in读到的内容, 而不能直接读取bio_filter或者bio_out, 否则报错BIO_push(bio_filter, bio_out); // BIO链, 将明文写入bio_filter, 等全部写完了, 再读biofilter, 就是加密好的密文了// bio_in = BIO_new_mem_buf(pszBufIn, lenBufIn);i_out_len_all = lenBufIn + 0x10; // 加密时, 如果明文长度不是0x10对齐, 那么加密后的长度可能比明文长最多0x10个字节pOutBuf = (UCHAR*)OPENSSL_malloc(i_out_len_all);if (NULL == pOutBuf){break;}lenOutBuf = 0;do {i_rc = BIO_read_ex(bio_in, ucBufRd, sizeof(ucBufRd), &sz_rd);if ((1 != i_rc) || (0 == sz_rd)){// 如果将东西读完了, 也是失败, 这里不错算.i_rc = BIO_flush(bio_filter); // 相当于EVP_CipherFinal_ex()if (1 != i_rc){ERR_print_errors_fp(stderr);goto END;}break;}// 必须向链条的顶部写(write to bio_filter)// 等全部写完(BIO_flush(bio_filter)), 再从链头(bio_filter)读取时, 就已经是加密完的密文了i_rc = BIO_write_ex(bio_filter, ucBufRd, sz_rd, &sz_wt); // 相当于 EVP_CipherUpdate()if (1 != i_rc){ERR_print_errors_fp(stderr);break;}} while (true);lenOutBuf = 0;do {i_rc = BIO_read_ex(bio_out, ucBufRd, sizeof(ucBufRd), &sz_rd);// 这里读最后一块的时候// 加密时, 已经是0x10对齐了// 解密时, 已经是实际的size了if (1 != i_rc){// 如果将东西读完了, 也是失败, 这里不错算.// ERR_print_errors_fp(stderr);break;}memcpy(pOutBuf + lenOutBuf, ucBufRd, sz_rd);lenOutBuf += sz_rd;} while (true);b_rc = true;} while (false);END:if (NULL != bio_in){BIO_free(bio_in);}if (NULL != bio_filter){BIO_free_all(bio_filter); // bio_filter是BIO链, 释放时要用 BIO_free_all()}// 不用释放 _evp_cipher_ctx, 因为 _evp_cipher_ctx属于 bio_filterif (!b_rc){if (NULL != pOutBuf){OPENSSL_free(pOutBuf);pOutBuf = NULL;}}return b_rc;
}