OpenSSL中AES加密的用法
《OpenSSL中AES加密的用法》
作者: 游蓝海
原文链接: http://blog.csdn.net/you_lan_hai/article/details/50992719
转载请注明出处
使用API的时候,需要特别小心数据长度,我在初次使用的时候简直被弄的晕头转向,遂作此文留个备忘。一般没有指定长度的参数,默认都是16(AES_BLOCK_SIZE
)个字节。输出数据的长度一般都是16字节的倍数,否则会出现数组越界访问。
以下API中,encrypt表示加密,decrypt表示解密。
1.生成加密/解密的Key
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
参数说明:
参数名称 | 描述 |
---|---|
userKey | 用户指定的密码。注意:只能是16、24、32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度。 |
bits | 密码位数。即userKey的长度 * 8,只能是128、192、256位。 |
key | 向外输出参数。 |
如果函数调用成功,返回0,否则是负数。
2.使用AES加密/解密
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
参数说明:
参数名称 | 描述 |
---|---|
in | 输入数据。必须是16字节。 |
out | 输出数据。必须是16字节。 |
key | 使用AES_set_encrypt/decrypt_key生成的Key。 |
AES_encrypt/AES_decrypt一次只处理16个字节。如果输入数据较长,你需要使用循环语句,每16个字节处理一次,直到所有数据处理完毕。如果数据不足16字节,可以用0填充至16字节。
3.使用AES CBC加密/解密
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, const int enc);
参数说明:
参数名称 | 描述 |
---|---|
in | 输入数据。长度任意。 |
out | 输出数据。能够容纳下输入数据,且长度必须是16字节的倍数。 |
length | 输入数据的实际长度。 |
key | 使用AES_set_encrypt/decrypt_key生成的Key。 |
ivec | 可读写的一块内存。长度必须是16字节。 |
enc | 是否是加密操作。AES_ENCRYPT表示加密,AES_DECRYPT表示解密。 |
这个函数比AES_encrypt多了一个ivec参数,ivec的内容可以任意指定,但是加密和解密操作必须使用同样的数据。在AES_cbc_encrypt底层,实际上是每16个字节做一次处理,先和ivec做异或运算,然后调用AES_encrypt函数进行加密。
AES_cbc_encrypt在加密的过程中会修改ivec的内容,因此ivec参数不能是一个常量,而且不能在传递给加密函数后再立马传递给解密函数,必须重新赋值之后再传递给解密函数。
关于输出数据的长度
输出数据缓冲区的长度必须是16字节的倍数,加密完成后,比输入长度多出来的输出数据是不可以丢弃的。因此,存档的时候,需要记录原始数据的长度
关于输入数据的长度不必是16字节的倍数(做个备忘):
下面是AES_cbc_encrypt函数的底层实现代码
...
//处理16字节倍数的数据
while (len >= 16) {
for (n = 0; n < 16; ++n)
out[n] = in[n] ^ iv[n];
(*block) (out, out, key); //调用AES_encrypt处理数据
iv = out;
len -= 16;
in += 16;
out += 16;
}
//当数据小于16字节的时候,进入下面的循环
while (len) {
for (n = 0; n < 16 && n < len; ++n)
out[n] = in[n] ^ iv[n];
for (; n < 16; ++n)
out[n] = iv[n]; //使用ivec补齐不足16字节的部分
(*block) (out, out, key); //调用AES_encrypt处理数据
iv = out;
if (len <= 16)
break;
len -= 16;
in += 16;
out += 16;
}
4.结尾
其他加密函数我还没有用过,在此就不继续列举了,但是参数跟上面几个相似,弄明白上面的就不成问题。