好习惯,先上代码再说事

加密

void AesEncrypt(unsigned char* pchIn, int nInLen, unsigned char *ciphertext, int &ciphertext_len, unsigned char * pchKey)
{
EVP_CIPHER_CTX en;
EVP_CIPHER_CTX_init(&en);
const EVP_CIPHER *cipher_type;
unsigned char *passkey, *passiv, *plaintxt;
unsigned char *plaintext = NULL; unsigned char iv[] = { 0x00}; cipher_type = EVP_aes_128_ecb();
EVP_EncryptInit_ex(&en, cipher_type, NULL, pchKey, iv); //当长度正好为16字节的倍数时,同样需要padding
static const int MAX_PADDING_LEN = 16; if(!EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL))
{
printf("ERROR in EVP_EncryptInit_ex \n");
return;
} int bytes_written = 0;
ciphertext_len = 0;
if(!EVP_EncryptUpdate(&en, ciphertext, &bytes_written, (unsigned char *) pchIn, nInLen) )
{
printf("ERROR in EVP_EncryptUpdate \n");
return;
}
ciphertext_len += bytes_written; if(!EVP_EncryptFinal_ex(&en, ciphertext + bytes_written, &bytes_written))
{
printf("ERROR in EVP_EncryptFinal_ex \n");
return;
}
ciphertext_len += bytes_written;
ciphertext[ciphertext_len] = 0; EVP_CIPHER_CTX_cleanup(&en); return;
}

 解密

void AesDecrypt(unsigned char* pchInPut, int nInl, unsigned char *pchOutPut, unsigned char *pchKey)
{
unsigned char achIv[8];
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx); EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, pchKey, achIv);
int nLen = 0;
int nOutl = 0; EVP_DecryptUpdate(&ctx, pchOutPut+nLen, &nOutl, pchInPut+nLen, nInl);
nLen += nOutl; EVP_DecryptFinal_ex(&ctx, pchOutPut+nLen, &nOutl);
nLen+=nOutl;
pchOutPut[nLen]=0;
EVP_CIPHER_CTX_cleanup(&ctx); return;
}

  

下面开始说事,纯A代码的下面不用看了。

首先明确以下概念,AES是加密的算法,使用128、192 和 256 位密钥,将被加密数据划分为128位(16字节)一块,然后使用某种加密模式进行加密。

1、主要的加密模式有以下几种:
ECB模式
按照块密码的块大小被分为数个块,并对每个块进行独立加密。
  优点:
  1.简单;
  2.有利于并行计算;
  3.误差不会被传送;
  缺点:
  1.不能隐藏明文的模式;
  2.可能对明文进行主动攻击;

CBC模式:
每个平文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有平文块。
同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
  优点:
  1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
  缺点:
  1.不利于并行计算;
  2.误差传递;
  3.需要初始化向量IV

CFB模式:
模式类似于CBC,可以将块密码变为自同步的流密码。
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.误差传送:一个明文单元损坏影响多个单元;
  3.唯一的IV;

OFB模式:
可以将块密码变成同步的流密码。它产生密钥流的块,然后将其与平文块进行异或,得到密文。
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.对明文的主动攻击是可能的;
  3.误差传送:一个明文单元损坏影响多个单元;

PCBC模式

CTR模式

在我的代码中使用的是最简单的ecb模式。

2、由于被加密数据分组时,有可能不会正好为128bit的整数倍,所以需要padding(填充补齐),而padding模式有以下几种:

None //不填充。
PKCS7 //填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
Zeros //填充字符串由设置为零的字节组成。
ANSIX923 //ANSIX923 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节均填充数字零。
ISO10126 //ISO10126 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据。

根据官方文档地址(https://www.openssl.org/docs/crypto/EVP_CIPHER_CTX_set_padding.html)中描述:
If padding is enabled (the default) then EVP_EncryptFinal_ex() encrypts the "final" data, that is any data that remains in a partial block. It uses standard block padding (aka PKCS padding) as described in the NOTES section, below. The encrypted final data is written to out which should have sufficient space for one cipher block. The number of bytes written is placed in outl. After this function is called the encryption operation is finished and no further calls to EVP_EncryptUpdate() should be made.

可以知道在调用EVP_EncryptFinal_ex函数时,padding是默认启用的。
是否使用padding可以通过EVP_CIPHER_CTX_set_padding函数设置,第二个参数为0则禁用padding,为1则启用padding。
文档中说padding的模式为PKCS padding,具体指的是PKCS#7。
这里用例子表述一下PKCS#7:
假设块长度为128bit,也就是16个字节。
那么当需要padding的字符串长度为11时(假设字符源串16进制为 : DD DD DD DD DD DD DD DD | DD DD DD DD ),则padding结果为:
| DD DD DD DD DD DD DD DD | DD DD DD DD 04 04 04 04 |
也就是缺4个字节,就是用04来padding,缺5个,就用05来Padding。
然后再将padding后的字符串进行加密。

我如何知道Padding模式是PKCS#7的?如果你不质疑我的分析,此部分可以跳过。
1.先使用一个key对长度为16的源串(随意)进行加密
EVP_EncryptFinal_ex函数调用后,得到结果如图1中红色部分,
红色部分就是padding内容的加密结果。

因为在PKCS#7模式下,padding的内容为 | 16 16 16 16 16 16 16 16 | 16 16 16 16 16 16 16 16 |
那么我构造一个字符串,如下图

经过加密后,如下图

可以看到此处16进制字符串与上面的红色字符串一致,所以能说明此处使用的Padding模式为PKCS#7。

为什么要研究这个padding?

1.当在使用openssl库与其他不同的库进行通信时,padding与加密模式不同(这都能搞错?)会导致让你蛋疼的问题。

2.理论是指导实践的标准,实践是检验理论的方法。

关于padding更详细的信息可以参考:
http://en.wikipedia.org/wiki/Padding_(cryptography)

最后hex与char互转的代码

char SupperToLower(char in)
{
if(in >= 65 && in <= 90)
return in + 32;
else
return in;
} char LowerToSupper(char in)
{
if(in >= 97 && in <= 122)
return in - 32;
else
return in;
} static const char *tohex = "0123456789ABCDEF"; void CharToHex(unsigned char *pchOut, const unsigned char *pchIn, int nLen)
{
int i = 0;
while(i < nLen)
{
*pchOut++ = tohex[pchIn[i] >> 4];
*pchOut++ = tohex[pchIn[i] & 0x0F];
++i;
} return;
} void HexToChar(unsigned char *pchOut, const unsigned char *pchIn, int nInLen)
{
int an=1,num=0,st,q,tmp,kk = 0;
for(q = nInLen - 1,st = nInLen / 2 - 1; q >= 0,st >= 0; q --)
{
if(kk==2)
{
pchOut[st] = (unsigned char)num;
st --;
num = 0;
an = 1;
kk = 0;
}
if(LowerToSupper(pchIn[q]) >= 'A' && LowerToSupper(pchIn[q]) <= 'F')
tmp = pchIn[q] - 'A' + 10;
else
tmp = pchIn[q] - '0';
num += an * tmp;
an *= 16;
kk ++;
} return;
}

  

openssl AES加密以及padding的更多相关文章

  1. openssl AES加密

    此代码不涉及ECB和CBC等关联加密 #include <stdio.h> #include <string.h> #include <stdlib.h> #inc ...

  2. JS和利用openssl的object C加密得到相同的aes加密密文

    这是之前接到的一个工作内容,项目原本的登录操作是获得账号和密码以后,对密码进行一遍MD5加密,然后传递账号和密文到cgi文件.在c中获取到账户以后,从数据库中获取到密码,对密码进行一次MD5的加密,然 ...

  3. openssl与cryptoAPI交互AES加密解密

    继上次只有CryptoAPI的加密后,这次要实现openssl的了 动机:利用CryptoAPI制作windows的IE,火狐和chrome加密控件后,这次得加上与android的加密信息交互 先前有 ...

  4. OPENSSL安装 以及使用openssl中的AES加密和解密

    OPENSSL安装:(VS) 1:第一步和所有的软件安装一样. 2:将OPENSSL中INLUCDE 和 LIB 分别拷贝到VS中VC的INLUCDE 和LIB目录下(我的机器上的目录是:C:\Pro ...

  5. [转贴]C++调用openssl 的AES加密例子

    #include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h ...

  6. openssl之aes加密(源码分析 AES_encrypt 与 AES_cbc_encrypt ,加密模式)

    首先要了解AES加密是什么,以及几种加密模式的区别.之后才是编程.具体的编程案例,在下面的链接. openssl之aes加密(AES_cbc_encrypt 与 AES_encrypt 的编程案例) ...

  7. openSSL实现AES加密

    Openssl是很常见的C接口的库,个人觉得易用.以下是AES加密的使用备忘.如果你有一定的密码学基础,那么就很好理解.代码是从网上弄下来的(原始地址已经忘记了),然后在尝试的过程中改了一点东西.其它 ...

  8. c#和js互通的AES加密解密

    一.使用场景 在使用前后端分离的框架中常常会进行传输数据相互加密解密以确保数据的安全性,如web Api返回加密数据客户端或web端进行解密,或者客户端或web端进行加密提交数据服务端解密数据等等. ...

  9. javascript AES加密 C#AES解密实现

    首先需要引入js类库 crypto-js(开源),地址:http://code.google.com/p/crypto-js 现在很多人无法打开这个地址不要紧,下面我们会将全部代码贴出来 需要引入 a ...

随机推荐

  1. c语言将2进制数转化为10进制数(栈的初始化,进栈,出栈)

    //c语言描述 将2进制转化为10进制 #include <stdio.h> #include <stdlib.h> #include <math.h> #defi ...

  2. SVN中取消冲突conflict

    在SVN update代码出现冲突的时候,可以先右键点击SVN commit,在打开的窗口中单击红框内区域: 然后,再一次点击edit->mark as resolved,然后删除代码中> ...

  3. c++11 中的 move 与 forward

    [update: 关于左值右值的另一点总结,请参看这篇] 一. move 关于 lvaue 和 rvalue,在 c++11 以前存在一个有趣的现象:T&  指向 lvalue (左传引用), ...

  4. (转)Java基础——嵌套类、内部类、匿名类

    本文内容分转自博客:http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html 将相关的类组织在一起,从而降低了命名空间的混乱. 一个内 ...

  5. 样式重置 取消input默认样式

    body, h1, h2, h3, h4, h5, h6, hr, p,blockquote, dl, dt, dd, ul, ol, li,pre, form, fieldset, legend, ...

  6. Oracle sqlldr使用示例

    SQLLDR用于快速的批量导入数据, 示例步骤如下: 1.确定Oracle的连接示例 username/password@sid 我使用的是:system/world @ localorcl sid是 ...

  7. 设计模式-外观模式(Facade)

    简介 外观模式(Facade),将外部与内部子系统的通信通过一个统一的门面对象进行. 由两部分组成: 门面角色:供外部调用,内部可能组装了多个子系统,多个方法. 子系统角色:子系统的方法也可以直接供外 ...

  8. 支持在安卓中UI(View)的刷新功能

     这是一款可以支持在安卓中UI(View)的刷新功能,Android中对View的更新有很多种方式,使用时要区分不同的应用场合.我感觉最要紧的是分清:多线程和双缓冲的使用情况.   现在可以尝试理解下 ...

  9. 在信号处理函数中调用longjmp

    错误情况及原因分析 前两天看APUE的时候,有个程序要自己制作一个sleep程序,结果在这个程序中就出现了在信号处理函数中调用longjmp函数的情况,结果就出现了错误,具体错误是啥呢,请参见下面这段 ...

  10. Ubuntu 14.04下java开发环境的搭建--1--JDK的安装

    说明:以下内容均是本人个人经验,接触ubuntu系统是从10.04开始,转眼转眼之间已经四年了,经常浏览各种相关论坛,发现从我刚开始基础到现在,论坛上还有很多人在问关于JAVA环境配置的相关问题.所以 ...