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.结尾

其他加密函数我还没有用过,在此就不继续列举了,但是参数跟上面几个相似,弄明白上面的就不成问题。

posted @ 2017-10-19 18:07  游蓝海2017  阅读(14317)  评论(3编辑  收藏  举报