OpenSSL之AES用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenSSL之AES用法相关的知识,希望对你有一定的参考价值。

参考技术A 密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种分组加密标准。这个标准用来替代原先的DES(Data Encryption Standard),已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一 。

本文假设你已经安装好了OpenSSL,并且持有一份1.1.1的源码。
AES相关的头文件在aes.h中、源文件在crypto/aes目录中。

这里定义了加密和解密的类型。

这里定义了分组最大轮数和块大小。

这个结构定义了AES的密钥上下文。相关字段含义:
rd_key —— 每轮的子密钥。
rounds —— 加解密轮数。

在1.1.1中,大多数的数据结构已经不再向使用者开放,从封装的角度来看,这是更合理的。如果你在头文件中找不到结构定义,不妨去源码中搜一搜。

int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
设置加密密钥,bits必须是128、192、256,否则会失败。
成功返回0,失败返回负数。

int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
设置解密密钥,bits必须是128、192、256,否则会失败。
成功返回0,失败返回负数。

void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
执行AES ECB分组加密。

void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
执行AES ECB分组解密。

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);
执行AES ECB分组加解密。其实是AES_encrypt()和AES_decrypt()的简单封装。
其内部实现为:

void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length,
const AES_KEY *key, unsigned char *ivec, const int enc);
执行AES CBC分组加解密。
ivec为16字节的向量,每次加解密都需要,首次为初使向量,后续为前一次的密文分组。
其内部实现为:

下面这个例子演示了AES ECB分组加解密的基本用法。在实际项目中,需要程序员加以封装,并充分考虑数据填充问题。

输出:
AES_set_encrypt_key ret:0
AES_set_decrypt_key ret:0
6dac1c56e747fae03acf8c6891e428e0
31323334353637383132333435363738

OpenSSL之内存用法

参考技术A

用户在使用内存时,容易犯的错误就是内存泄露。当用户调用内存分配和释放函数时,查找内存泄露比较麻烦。OpenSSL提供了内置的内存分配/释放函数。如果用户完全调用OpenSSL的内存分配和释放函数,可以方便的找到内存泄露点。OpenSSL分配内存时,在其内部维护一个内存分配哈希表,用于存放已经分配但未释放的内存信息。当用户申请内存分配时,在哈希表中添加此项信息,内存释放时删除该信息。当用户通过OpenSSL函数查找内存泄露点时,只需查询该哈希表即可。用户通过OpenSSL回调函数还能处理那些泄露的内存。

本文假设你已经安装好了OpenSSL,并且持有一份1.1.1的源码。
内存相关的头文件为crypto.h、源文件在crypto目录中,文件名模式为mem*.c。

这个结构定义了内存块的分配信息。主要字段含义:
addr —— 分配的内存地址。
num —— 分配的内存大小。
file —— 分配内存的文件名。
file —— 分配内存的行号。
threadid —— 分配内存的线程ID。

在1.1.1中,大多数的数据结构已经不再向使用者开放,从封装的角度来看,这是更合理的。如果你在头文件中找不到结构定义,不妨去源码中搜一搜。

int CRYPTO_set_mem_functions(
void ( m) (size_t, const char *, int),
void ( r) (void *, size_t, const char , int),
void (
f) (void *, const char , int));
成功返回1,失败返回0。
void CRYPTO_get_mem_functions(
void (
m) (size_t, const char , int),
void (
r) (void , size_t, const char , int),
void (
f) (void *, const char *, int));
这两个函数用于设置和读取与内存分配和释放相关的三个函数,这三个函数默认分别为:
static void ( malloc_impl)(size_t, const char *, int) = CRYPTO_malloc;
static void ( realloc_impl)(void *, size_t, const char , int) = CRYPTO_realloc;
static void (
free_impl)(void *, const char *, int) = CRYPTO_free;
这两个函数只允许在内存分配前即初使化时调用。

int CRYPTO_set_mem_debug(int flag);
设置是否开启内存调试。取值1或0,1表示打开。
成功返回1,失败返回0。
只允许在内存分配前即初使化时调用。

void *CRYPTO_malloc(size_t num, const char *file, int line);
void *CRYPTO_zalloc(size_t num, const char *file, int line);
void *CRYPTO_realloc(void *addr, size_t num, const char *file, int line);
CRYPTO_free(void *ptr, const char *file, int line);
这几个函数用于分配和释放内存。
是否记录内存与CRYPTO_set_mem_debug()的开关有关。

int CRYPTO_mem_ctrl(int mode);
这个函数用于设置是否开启内存记录模式,参数取值为:
# define CRYPTO_MEM_CHECK_OFF 0x0
# define CRYPTO_MEM_CHECK_ON 0x1
返回旧模式。
注:我没有在头文件中看到像老版函数CRYPTO_is_mem_check_on()一样可以查询当前开关状态的用法,但是通过查看源码,发现可以对CRYPTO_mem_ctrl()传递一个不存在的类型(比如-1)使其返回当前状态。

int CRYPTO_mem_leaks_cb(int (*cb) (const char *str, size_t len, void *u), void *u);
遍历记录的内存,用于打印内存泄露信息。
返回是否有内存汇露。分别取值1和0。

int CRYPTO_mem_leaks(BIO *bio);
打印内存泄露信息,输出到BIO中。
返回是否有内存汇露。分别取值1和0。
int CRYPTO_mem_leaks_fp(FILE *);
CRYPTO_mem_leaks()的FILE版本。

由于OpenSSL内部涉及地数据结构众多,如果采用原始的内存操作函数,因为涉及到文件名和行号会比较麻烦。因此,OpenSSL定义了一组宏进行包装,方便使用者进行调用。定义如下:

下面这个例子演示了使用OpenSSl内存分配API进行操作。同时还用到了placement new()的用法,演示如何在openssl的内存分配串上创建c++对象。

如果在编译过程中出现下面这个错误:
testmem.cpp:40:42: 错误:‘CRYPTO_mem_leaks_cb’在此作用域中尚未声明
CRYPTO_mem_leaks_cb(memleak_cb, "aaa");
解决办法是开启debug调试编译,命令如下:
./config --prefix=/usr/local/openssl enable-crypto-mdebug enable-crypto-mdebug-backtrace

输出:
old switch:0
@SNode::SNode name:[abc] age:[18]
@SNode::~SNode name:[abc] age:[0]
leak info:[[02:21:40] 1 file=testmem.cpp, line=46, thread=140607514695488, number=36, address=0x204f090
]
##> ./testmem() [0x4044e3]
##> ./testmem(CRYPTO_malloc+0xa3) [0x4035e3]
##> ./testmem() [0x40329c]
##> /lib64/libc.so.6(__libc_start_main+0xf5) [0x7fe1bbb77555]
##> ./testmem() [0x4030f3]
leak info:[36 bytes leaked in 1 chunks
]

以上是关于OpenSSL之AES用法的主要内容,如果未能解决你的问题,请参考以下文章

openSSL实现AES加密

openssl命令详解

OpenSSL之内存用法

如何使用 OpenSSL 进行 AES 解密

php openssl aes-256-cbc key长度自动匹配了128的长度,为啥

在 Mac 上找不到 openssl/aes.h' 文件