openssl AES加密以及padding

好习惯,先上代码再说事

加密

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;
}

  

时间: 2024-08-24 05:27:29

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

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

这是之前接到的一个工作内容,项目原本的登录操作是获得账号和密码以后,对密码进行一遍MD5加密,然后传递账号和密文到cgi文件.在c中获取到账户以后,从数据库中获取到密码,对密码进行一次MD5的加密,然后将该密文与post过来的密文进行对比,进行登录验证.也就是说,虽然进行了一次密码加密,但是在get/post的过程中,该密文是可见的,不符合客户的保密需求. 经过协商以后决定,在传递的过程中不再对密码进行传输,而是将账号与session进行组合,组合成一个新的字符串以后,将密码当做密钥,进行一次A

使用 openssl 的AES 加密

源码: #include <stdio.h> #include <memory.h> #include <stdlib.h> #include <openssl/aes.h> int main(int argc, char *argv[]){ unsigned char buf[16] = "1234567890abcde"; unsigned char buf2[16]; unsigned char buf3[16]; // 密钥为 0

Java aes加密C#解密的取巧方法

摘要: 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦.Java的代码和C#的代码无法互通. Java代码: /** * 加密 * * @param content 需要加密的内... 项目开发过程中遇到一个棘手的问题:A系统使用java开发,通过AES加密数据,B系统使用C#开发,需要从A系统获取数据,但在AES解密的时候遇到麻烦.Java的代码和C#的代码无法互通. Java代码: /**

非对称技术栈实现AES加密解密

非对称技术栈实现AES加密解密 正如前面的一篇文章所述,https协议的SSL层是实现在传输层之上,应用层之下,也就是说在应用层上看到的请求还是明码的,对于某些场景下要求这些http请求参数是非可读的,这就要求在前端和后端不同的技术栈上完成信息的加密解密.当然我们通常完成这样专业的功能都会考虑使用相应的框架或者程序库来完成功能,前端或者NodeJS平台通常是JavaScript语言,JavaScript主流的加密解密库分别是SjclJS和CryptoJS, 本文以CryptoJS为例进行讨论.另

关于CryptoJS中md5加密以及aes加密的随笔

最近项目中用到了各种加密,其中就包括从没有接触过得aes加密,因此从网上各种查,官方的一种说法: 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用.经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准.2

C#实现DES加密解密,AES加密解密

DES算法描述简介: DES是Data Encryption Standard(数据加密标准)的缩写.它是由IBM公司研制的一种加密算法,美国国家标准局于1977年公布把它作为非机要部门使用的数据加密标准:它是一个分组加密算法,他以64位为分组对数据加密.同时DES也是一个对称算法:加密和解密用的是同一个算法.它的密匙长度是56位(因为每个第8 位都用作奇偶校验),密匙可以是任意的56位的数,而且可以任意时候改变. /// <summary>   /// DES加密   /// </su

透过 Delphi 使用二进位金钥做 AES 加密.

从 1994 年开始,笔者就开始接触加密与网路安全的世界,从鲁立忠老师的指导当中获益良多,后来在台湾的元智大学就读研究所的时候,也以此为研究主题. 在当时,电子商务是显学,Visa跟 Master Card还特别为了网路交易制作了厚厚三大本的商务通讯协定,命名为SET (Secure Electronic Transaction,安全电子交易),从客户端.商店端.银行端定义了绵绵密密的交易规范. 然而,网际网路的世界跟 Visa Master Card所熟悉的专用网路世界差的远了,不是大狗们(B

C# AES加密解密算法

/// <summary> /// AES加密 /// </summary> /// <param name="encryptStr">明文</param> /// <param name="key">密钥</param> /// <returns></returns> public static string Encrypt(string encryptStr,stri

AES加密在IOS中的使用

现在做的App,因为考虑到安全性,所以用到了AES加密,以及配对安卓使用的AES加密. .h文件 #import <Foundation/Foundation.h> #import <CommonCrypto/CommonCryptor.h> #import <CommonCrypto/CommonKeyDerivation.h> #define AES_KEY @"[email protected]!*&y.)x#[;>" #defi