首先要了解AES加密是什么,以及几种加密模式的区别。之后才是编程。具体的编程案例,在下面的链接。

openssl之aes加密(AES_cbc_encrypt 与 AES_encrypt 的编程案例)

下面这个链接有详细图解。
http://www.cnblogs.com/adylee/archive/2007/09/14/893438.html

AES加密算法 - 加密模式

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提供的接口就好理解了。

openssl提供的aes加密接口

以下接口来自“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作为参数传入


"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接口进行编程。
参考资料:

分组对称加密模式:ECB/CBC/CFB/OFB缺CTR

http://fossies.org/dox/openssl-1.0.1f/index.html (详细源码)


openssl之aes加密(源码分析 AES_encrypt 与 AES_cbc_encrypt ,加密模式)的更多相关文章

  1. React Fiber源码分析 第二篇(同步模式)

    先附上两张流程图 1.scheduleRootUpdate  这个函数主要执行了两个操作  1个是创建更新createUpdate并放到更新队列enqueueUpdate, 1个是执行sheculeW ...

  2. React Fiber源码分析 (介绍)

    写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...

  3. 鸿蒙内核源码分析(寄存器篇) | 小强乃宇宙最忙存储器 | 百篇博客分析OpenHarmony源码 | v38.02

    百篇博客系列篇.本篇为: v38.xx 鸿蒙内核源码分析(寄存器篇) | 小强乃宇宙最忙存储器 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪 ...

  4. Openssl编程--源码分析

    Openssl编程 赵春平 著 Email: forxy@126.com 第一章 基础知识 8 1.1 对称算法 8 1.2 摘要算法 9 1.3 公钥算法 9 1.4 回调函数 11 第二章 ope ...

  5. 转载-FileZilla Server源码分析(1)

    FileZilla Server源码分析(1) 分类: VC 2012-03-27 17:32 2363人阅读 评论(0) 收藏 举报 serversocketftp服务器usersockets工作 ...

  6. 死磕以太坊源码分析之rlpx协议

    死磕以太坊源码分析之rlpx协议 本文主要参考自eth官方文档:rlpx协议 符号 X || Y:表示X和Y的串联 X ^ Y: X和Y按位异或 X[:N]:X的前N个字节 [X, Y, Z, ... ...

  7. MyCat源码分析系列之——前后端验证

    更多MyCat源码分析,请戳MyCat源码分析系列 MyCat前端验证 MyCat的前端验证指的是应用连接MyCat时进行的用户验证过程,如使用MySQL客户端时,$ mysql -uroot -pr ...

  8. PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看

    catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...

  9. Mysqldump源码分析

    版权声明:本文由王珏原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/261 来源:腾云阁 https://www.qclou ...

随机推荐

  1. 高手用的SourceInsight配置文件——仿Sublime风格【转】

    本文转载自:https://blog.csdn.net/weixin_38233274/article/details/80209100 配置文件下载地址:https://download.csdn. ...

  2. Mybatis动态SQL——if,where,trim,choose,set.foreach的用法

    知识点:主要介绍mybatis中,动态sql中的if,where,trim,set,foreach的用法 自学谷粒学院mybatis学习视频,参考mybatis官方文档 java包:log4j.jar ...

  3. thinkphp 模板中得到controller name,得到当前文件路径

    <li><a href="/Admin/account" <eq name="Think.CONTROLLER_NAME" value= ...

  4. [Vue]Vue实例的选项props传递数据props为驼峰式命名

    在vue的中文官网有这样的说明: HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符.这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop ...

  5. python PIL/Pillow图像扩展、复制、粘贴处理

    http://blog.csdn.net/yuanyangsdo/article/details/60957685

  6. [嵌入式培训 笔记]-----Vim编辑器使用简介

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 第一讲小结 1. 光标在屏幕文本中的移动既 ...

  7. 十四 web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码

    打码接口文件 # -*- coding: cp936 -*- import sys import os from ctypes import * # 下载接口放目录 http://www.yundam ...

  8. HQL查询中取个别几个字段

    数据表:

  9. laravel中修改默认时区

    在config文件夹下app.php中找到timezone,有RTC改成PRC

  10. Docker的大坑小洼(二)

    再谈<Docker的大坑小洼> 今天闲暇看了一下宏亮同学写的一篇<Docker的大坑小洼>,非常受启发.因为Docker的文章真的很多了,但大家如果只是玩一玩,有很多坑是不会碰 ...