http://www.cnblogs.com/adylee/archive/2007/09/14/893438.html
ECB模式
优势:
1.简单;
2.有利于并行计算;
3.偏差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
CBC模式:
优势:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.偏差传递;
3.
须要初始化向量IV
CFB模式:
优势:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.能够及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.偏差传送:一个明文单元损坏影响多个单元;
3.惟一的IV;
ofb模式:
优势:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.能够及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.偏差传送:一个明文单元损坏影响多个单元;
了解这些加密模式以后,再看openssl提供的接口就好理解了。
如下接口来自“crypto/aes/aes.h”,有openssl源码。
//设置加密和解密器
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);
//默认的加密解密方式,参数好理解
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);
//下面这些也是经常使用的加密方式,可是参数不少,而源码对于参数使用介绍很少,只能摸索
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key, const int enc);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, const int enc); //参数相对复杂
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, int *num, const int enc);
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, int *num, const int enc);
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, int *num, const int enc);
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, int *num);
void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char ivec[AES_BLOCK_SIZE],
unsigned char ecount_buf[AES_BLOCK_SIZE],
unsigned int *num);
从下面这个文件能够看出,
AES_encrypt
就是ecb加密的方式。而AES_set_encrypt_key和
AES_encrypt,它们的实如今"crypto/aes/aes_x86core.c"和
"crypto/aes/aes_core.c",也就是有两个版本,根据平台选择。看源码。
"
crypto/aes/
aes_ecb.c"
void
AES_ecb_encrypt
(
const
unsigned
char
*
in
,
unsigned
char
*
out
,
const
AES_KEY
*
key
,
const
int
enc
)
{
assert
(
in
&&
out
&&
key
);
assert
((
AES_ENCRYPT
==
enc
)||(
AES_DECRYPT
==
enc
));
if
(
AES_ENCRYPT
==
enc
)
AES_encrypt
(
in
,
out
,
key
);
else
AES_decrypt
(
in
,
out
,
key
);
}
从这里能够看出,ecb方式的加密,是由AES_encrypt接口实现的。
而cbc的加密方式在另外的地方实现了,下面给出目录以及源代码。
"crypto/aes/aes_cbc.c"
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, unsigned char *ivec, const int enc) { if (enc) CRYPTO_cbc128_encrypt(in,out,len,key,ivec,(block128_f)AES_encrypt); else CRYPTO_cbc128_decrypt(in,out,len,key,ivec,(block128_f)AES_decrypt); }函数
从这里看出,cbc加密方式,调用接口CRYPTO_cbc128_decrypt,而它又将AES_encrypt做为参数传入。ui
"crypto/modes/
cbc128.c"
void
CRYPTO_cbc128_encrypt
(
const
unsigned
char
*
in
,
unsigned
char
*
out
,
size_t
len
,
const
void
*
key
,
unsigned
char
ivec
[
16
],
block128_f block
)
{
//这里的block就是AES_encrypt
size_t n;
const unsigned char *iv = ivec;
assert(in && out && key && ivec);
#if !defined(OPENSSL_SMALL_FOOTPRINT)
if (STRICT_ALIGNMENT &&
((size_t)in|(size_t)out|(size_t)ivec)%sizeof(size_t) != 0) {
while (len>=16) {
for(n=0; n<16; ++n)
out[n] = in[n] ^ iv[n];
//输入与初始化向量进行异或,保存在out
(*block)(out, out, key);
//调用AES_encrypt进行加密,异或结果out做为加密输入
//加密输出结果也保存在out里面,
iv = out;
//将前一次密文,做为后一次的初始化向量,从而完成加密
len -= 16;
in += 16;
out += 16;
}
} else {
while (len>=16) {
for(n=0; n<16; n+=sizeof(size_t))
*(size_t*)(out+n) =
*(size_t*)(in+n) ^ *(size_t*)(iv+n);
(*block)(out, out, key);
iv = out;
len -= 16;
in += 16;
out += 16;
}
}
#endif
while (len) {
for(n=0; n<16 && n<len; ++n)
out[n] = in[n] ^ iv[n];
//in和iv异或
for(; n<16; ++n)
//若是in长度不是16的整数倍
out[n] = iv[n];
//最后的out直接用iv初始化,其实也就至关于out与0进行异或
(*block)(out, out, key);
iv = out;
if (len<=16) break;
//加密结束
len -= 16;
in += 16;
out += 16;
}
memcpy(ivec,iv,16);
}
//从上面的源码能够看出,cbc本质上和ecb差异不大,惟一区别是将前一次加密结果,与要加密的内容异或。所以,cbc的并行性较差,由于每次都要等待前一次的结果,而ecb则不用,速度较快。其主要区别仍然看文章开头,原理图看参考连接。
调用实例:
int aes_encrypt(char* in, char* key, char* out)//, int olen)
{
if(!in || !key || !out) return 0;
AES_KEY aes;
if(AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
{
return 0;
}
int len=strlen(in)/<span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">AES_BLOCK_SIZE*</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">AES_BLOCK_SIZE</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">, en_len=0;</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">
</span> while(en_len<len)//输入输出字符串够长,而且是AES_BLOCK_SIZE的整数倍,须要严格限制
{
AES_encrypt((unsigned char*)in, (unsigned char*)out, &aes);
in+=AES_BLOCK_SIZE;
out+=AES_BLOCK_SIZE;
en_len+=AES_BLOCK_SIZE;
}
return 1;
}
int aes_decrypt(char* in, char* key, char* out)
{
if(!in || !key || !out) return 0;
AES_KEY aes;
if(AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
{
return 0;
}
int len=strlen(in), en_len=0;
while(en_len<len)
{
AES_decrypt((unsigned char*)in, (unsigned char*)out, &aes);
in+=AES_BLOCK_SIZE;
out+=AES_BLOCK_SIZE;
en_len+=AES_BLOCK_SIZE;
}
return 1;
}
最近遇到一个坑,
AES_encrypt <pre code_snippet_id="232583" snippet_file_name="blog_20140312_1_226454" name="code" class="cpp" style="color: rgb(55, 42, 24); font-size: 16px; line-height: 28px;">AES_decrypt
就是这两个函数让我折腾了四五天,心力憔悴,几近崩溃,也许是走火入魔了,由于遇到了挑战,非要干掉它,而不是绕过!
int aes_encrypt(char* in, char* key, char* out)//, int olen)
{
if(!in || !key || !out) return 0;
AES_KEY aes;
if(AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
{
return 0;
}
<pre code_snippet_id="232583" snippet_file_name="blog_20140312_1_226454" name="code" class="cpp" style="color: rgb(55, 42, 24); font-size: 16px; line-height: 28px;"> int len=strlen(in)/<span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">AES_BLOCK_SIZE*</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">AES_BLOCK_SIZE</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">, en_len=0;</span>
char *lptmp = new char[len+1];
memset(lptmp, '\0', len+1);
while(en_len<len)//输入输出字符串够长,而且是AES_BLOCK_SIZE的整数倍,须要严格限制
{
AES_encrypt((unsigned char*)in, (unsigned char*)lptmp, &aes);
in+=AES_BLOCK_SIZE;
<span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">lptmp</span><span style="font-family: 'Hiragino Sans GB W3', 'Hiragino Sans GB', Arial, Helvetica, simsun, u5b8bu4f53;">+=AES_BLOCK_SIZE;</span>
en_len+=AES_BLOCK_SIZE;
<span style="color:#372a18;"> //hex(lptmp) </span><strong><span style="color:#ff0000;">那么就发现第一个数据块加密的结果是对的,后面就错误了,加密后的数据不少是0,查了openssl的</span></strong>
<strong><span style="color:#ff0000;"> //源代码这个aes这块的加解密是线程安全的,有谁知道缘由?</span></strong>
}
if(lptmp)
{
delete []lptmp;
lptmp = NULL;
}
return 1;
}
最后给出一个连接,利用openssl的AES接口进行编程。
参考资料: