openssl3.2 - exp - aes-128-cbc

文章目录

    • 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() = 0

D:\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 = 0x10
	UCHAR iv[0x10]; // aes-128-cbc's iv len = 0x10

	for (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 = 256

		printf("after enc:\n");

		BIO_dump_fp(stdout, pEncBuf, lenEncBuf);

		// dec
		if (!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); // 输出必须比输入大0x10
		if (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() = 0

D:\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 = 0x10
	UCHAR iv[0x10]; // aes-128-cbc's iv len = 0x10

	for (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 = 256

		printf("after enc:\n");

		BIO_dump_fp(stdout, pEncBuf, lenEncBuf);

		// dec
		if (!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-CBC

		i_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_filter

	if (!b_rc)
	{
		if (NULL != pOutBuf)
		{
			OPENSSL_free(pOutBuf);
			pOutBuf = NULL;
		}
	}

	return b_rc;
}

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/274604.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【技巧】ChatGPT Prompt 提示语大全

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 主要来自&#xff1a;https://github.com/f/awesome-chatgpt-prompts ChatGPT SEO prompts ChatGPT SEO提示 Contributed by: StoryChief AI Reference: 7 Powerful ChatGPT Prompts to Create SEO Content Faste…

RabbitMQ问题

如何实现顺序消费&#xff1f; 消息放入到同一个队列中消费 如何解决消息不丢失&#xff1f; 方案&#xff1a; 如上图&#xff1a;消息丢失有三种情况&#xff0c;解决了以上三种情况就解决了丢失的问题 1、丢失1--->消息在到达交换机的时候&#xff1b;解决&#xff1…

RabbitMQ 安装保姆级教程

目录 1.MQ引言 1.1 什么是MQ 1.2 MQ有哪些 1.3 不同MQ特点 2.RabbitMQ 的引言 2.1 RabbitMQ 2.2 RabbitMQ 的安装 2.2.1 下载 2.2.2 下载的安装包 2.2.3 安装步骤 3. RabiitMQ 配置 3.1RabbitMQ 管理命令行 3.2 web管理界面介绍 3.2.1 overview概览 3.2.2 Admin用…

整型数组按个位值排序 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元素&#xf…

wireshark windows 抓包https

windows下 1.配置环境变量以生成ssl协商会话密钥日志记录 系统设置-》高级设置-》环境变量 新增环境变量 SSLKEYLOGFILE C:\Users\Public\Documents\SSLKEY\sslkey.log 打开公用共享文档创建SSLKEY文件夹用于后续系统存放协商密钥日志 2.配置Wireshark选项进行抓包 点击…

计算机二级(Python)真题讲解每日一题:《方菱形》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ 请写代码替换横线&#xff0…

【2024最新版,redis7】redis底层的10种数据结构

前言&#xff1a;本文redis版本&#xff1a;7.2.4 本文语雀原文地址&#xff08;首发更新&#xff09;&#xff1a;https://www.yuque.com/wzzz/redis/xg2cp37kx1s4726y 本文CSDN转载地址&#xff1a; https://blog.csdn.net/u013625306/article/details/136842107 1. 常见的数…

.htaccess全站设置SSL,wordpress全站设置SSL,网站重定向的次数过多”错误最佳解决方法教程

.htaccess全站设置SSL,wordpress全站设置SSL&#xff0c;网站重定向的次数过多”错误最佳解决方法教程 网上找了很多教程网无效**.htacces**设置&#xff0c;访问后台出现重定向次数过多&#xff0c;导致无法访问 找了好久&#xff0c;测试用AI机器人无法解决&#xff0c;参考…

【Linux】详谈进程优先级进程调度与切换

一、进程优先级 1.1、为什么要有优先级 进程要访问某种资源&#xff0c;进程通过一定的方式排队&#xff0c;确认享受资源的优先顺序。计算机中资源过少&#xff0c;所以进程访问某种资源时需要排队。 1.2、优先级的具体表示 进程的优先级其实就是PCB中的一个整形变量…

python失物招领系统-安卓-flask-django-nodejs-php

对于本失物招领 的设计来说&#xff0c; 它是应用mysql数据库、安卓等技术动态编程以及数据库进行努力学习和大量实践&#xff0c;并运用到了 建设中在整个系统的设计当中&#xff0c;具体根据网上失物招领的现状来进行开发的&#xff0c;具体根据用户需求实现网上失物招领网络…

产品推荐 | 基于XC7K325T的FMC接口万兆光纤网络验证平台

01、产品概述 TES307是一款基于XC7K325T FPGA的万兆光纤网络验证平台&#xff0c;板卡具有1个FMC&#xff08;HPC&#xff09;接口&#xff0c;4路SFP万兆光纤接口、4路SATA接口、1路USB3.0接口。 板载高性能的FPGA处理器可以实现光纤协议、SATA总线控制器、以及USB3.0高速串…

【Node.js从基础到高级运用】十五、单元测试与集成测试

引言 在Node.js开发过程中&#xff0c;测试是确保代码质量和功能正确性的关键步骤。单元测试和集成测试是最常见的测试类型。下面我们将使用Jest框架来进行测试。 单元测试 单元测试是指对软件中的最小可测试单元进行检查和验证。在Node.js中&#xff0c;这通常指的是函数或者…

ISIS接口明文认证实验简述

默认情况下&#xff0c;ISIS接口认证通过在ISIS协议数据单元&#xff08;PDU&#xff09;中添加认证字段&#xff0c;例如&#xff1a;一个密钥或密码&#xff0c;用于验证发送方的身份。 ISIS接口认证防止未经授权的设备加入到网络中&#xff0c;并确保邻居之间的通信是可信的…

智慧城市:提升城市治理能力的关键

目录 一、智慧城市的概念及特点 二、智慧城市在提升城市治理能力中的应用实践 1、智慧交通&#xff1a;提高交通治理效率 2、智慧政务&#xff1a;提升政府服务水平 3、智慧环保&#xff1a;加强环境监测与治理 4、智慧安防&#xff1a;提高城市安全水平 三、智慧城市在…

【计算机视觉】Gaussian Splatting源码解读补充

本文旨在补充gwpscut创作的博文学习笔记之——3D Gaussian Splatting源码解读。 Gaussian Splatting Github地址&#xff1a;https://github.com/graphdeco-inria/gaussian-splatting 论文地址&#xff1a;https://repo-sam.inria.fr/fungraph/3d-gaussian-splatting/3d_gauss…

基于nodejs+vue班级管理系统的设计与实现-flask-django-python-php

随着电子技术的普及和快速发展&#xff0c;线上管理系统被广泛的使用&#xff0c;有很多事业单位和商业机构都在实现电子信息化管理&#xff0c;班级管理系统也不例外&#xff0c;由比较传统的人工管理转向了电子化、信息化、系统化的管理。随着互联网技术的高速发展&#xff0…

STM32编写ADC功能,实现单路测量电压值(OLED显示)

先来看看本次实验的结果吧&#xff1a;stm32点电压测量范围为0-3.3V&#xff0c;数值为&#xff1a;0-4095 来看看这个工程的文件布局吧&#xff1a; 实现ADC功能总共分为六步&#xff1a; 第一步&#xff1a;开始RCC时钟&#xff0c;包括ADC和GPIO的时钟&#xff0c;ADCCLK的…

六、C#快速排序算法

简介 快速排序是一种常用的排序算法&#xff0c;它基于分治的思想&#xff0c;通过将一个无序的序列分割成两个子序列&#xff0c;并递归地对子序列进行排序&#xff0c;最终完成整个序列的排序。 其基本思路如下&#xff1a; 选择数组中的一个元素作为基准&#xff08;pivot…

SQL server服务连接失败,通过端口1433连接到主机 localhost的 TCP/IP 连接失败

SQL server服务连接失败&#xff0c;通过端口1433连接到主机 localhost的 TCP/IP 连接失败 出现这个错误的时候&#xff0c;首先确保sql的服务正常启动 通常来说正常安装的SQL server之后&#xff0c;会自带一个软件 打开&#xff1a;SQL server配置管理器 确认一下红框内的…

GitHub Copilot+ESP开发实战-串口

上篇文章讲了GitHub Copilot在应用中可能遇到的问题&#xff0c;接下来小启就简单介绍下GitHub Copilot在ESP32开发中C语言实现串口功能&#xff0c;感兴趣的可以看看。 一、向Copilot提问&#xff1a; 1. ESP32用C语言实现串口初始化&#xff1b; 2.配置uart为1&#xff0c…
最新文章