红联Linux门户
Linux帮助

Linux下使用openssl的AES加密-CBC模式

发布时间:2017-04-14 09:22:30来源:blog.csdn.net/liuyueyi1995作者:liuyueyi1995
最近需要用到AES加密,为了图方便就打算使用openssl自带的AES加密算法的API来实现。
主要用到了ECB和CBC两种加密模式。
ECB模式之前一篇(http://www.linuxdiyf.com/linux/29980.html)已经写过了。这篇就写一下CBC模式。
 
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/aes.h>
void my_AES_cbc_encrypt(unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char *ivec)
{
size_t n;
const unsigned char *iv = ivec;
if (len == 0)
return;
while (len) {
for (n = 0; n < 16 && n < len; ++n)
out[n] = in[n] ^ iv[n];
for (; n < 16; ++n)
out[n] = iv[n];
AES_encrypt(out, out, key);
iv = out;
if (len <= 16)
break;
len -= 16;
in += 16;
out += 16;
}
memcpy(ivec, iv, 16);
}
void my_AES_cbc_decrypt(unsigned char *in, unsigned char *out,
size_t len, const void *key,
unsigned char *ivec)
{
size_t n;
union {
size_t t[16 / sizeof(size_t)];
unsigned char c[16];
} tmp;
if (len == 0)
return;
while (len) {
unsigned char c;
AES_decrypt(in, tmp.c, key);
for (n = 0; n < 16 && n < len; ++n) {
c = in[n];
out[n] = tmp.c[n] ^ ivec[n];
ivec[n] = c;
}
if (len <= 16) {
for (; n < 16; ++n)
ivec[n] = in[n];
break;
}
len -= 16;
in += 16;
out += 16;
}
}
int main(int argc, char**argv) {
if(argc != 2) {
printf("使用方法为:\n./cbc text\ntext为待加密的明文。\n");
return -1;
}
unsigned char *data = argv[1];
printf("原始数据:%s\n",data);
size_t len = strlen(data);
printf("明文长度:%d\n",len);
size_t length = ((len+AES_BLOCK_SIZE-1)/AES_BLOCK_SIZE)*AES_BLOCK_SIZE;  //对齐分组
char userkey[AES_BLOCK_SIZE];
unsigned char *iv1 = malloc(AES_BLOCK_SIZE);
unsigned char *iv2 = malloc(AES_BLOCK_SIZE);
unsigned char *encrypt_result = malloc(length);
unsigned char *decrypt_result = malloc(length);
AES_KEY en_key;
AES_KEY de_key;
memset((char*)userkey,'k',AES_BLOCK_SIZE);
memset((unsigned char*)iv1,'m',AES_BLOCK_SIZE);
memset((unsigned char*)iv2,'m',AES_BLOCK_SIZE);
memset((unsigned char*)encrypt_result, 0, length);
memset((unsigned char*)decrypt_result, 0, length);
AES_set_encrypt_key(userkey, AES_BLOCK_SIZE*8, &en_key);
printf("加密密钥:%d\n",en_key);
my_AES_cbc_encrypt(data, encrypt_result, len, &en_key, iv1);
printf("加密结果:%s\n",encrypt_result);
AES_set_decrypt_key(userkey, AES_BLOCK_SIZE*8, &de_key);
printf("解密密钥:%d\n",de_key);
my_AES_cbc_decrypt(encrypt_result, decrypt_result, len, &de_key, iv2);
printf("解密结果:%s\n",decrypt_result);
}
 
代码说明:
1.openssl库其实已经实现了CBC模式的AES,但是我实际使用时,发现最后一个分组总是解密不对,没有找到问题的根本,所以干脆自己写了CBC的实现。
2.对齐分组的作用是把实际长度扩充成16(AES_BLOCK_SIZE)的整数倍。
3.iv1和iv2其实是一样的,但是因为加密之后直接解密,导致解密时iv值被加密过程污染了。具体表现就是解密的iv变成了加密时最后一个分组的结果。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/29981.html