本文主要是介绍EVP AES_CBC加密解密记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最近学习了openssl中AES有关加密解密的接口,以下内容为测试代码,需要注意使用EVP函数接口实现AES_CBC时需注意末尾字符的填充处理,我使用的算法为“EVP_aes_128_cbc”,需要注意的是分组加密中最小组为16字节,加密操作中使用的缓冲区需比源数据多16个字节,原因是若分组后最后一组数据不够16个字节,则按照填充规则填满至16字节,若分组后正好是16的整数倍,最后需再加一个分组,并将16个字节按照规则填充。
#include<iostream>
#include<stdio.h>
#include<openssl/evp.h>
#define MSG_LEN 16
#define IV_LEN 16
#define DECRY 0
#define ENCRY 1
typedef enum{
AES_CBC,
AES_EBC
}EVP_ALGORITHM;
void my_evp_init()
{
//如果不经过初始化就调用了加密或摘要相关的EVP接口,则会返回错误。
//OpenSSL中所有的对称和摘要算法都需要进行全局初始化,方法如下:
OpenSSL_add_all_algorithms();
//当然也可以只载入加密算法或摘要算法
// OpenSSL_add_all_digest();
// OpenSSL_add_all_cipher();
return;
}
//对称算法
/*
*@ciphername 算法名称,通过此名称找到EVP_CIPHER结构
*@dir 加密解密标志,0为解密,非0为加密
*@aKey 对称算法秘钥
*@iVec IV向量
*
*/
static int OpenSSL_Cipher(int ciphername, int dir,
const unsigned char *aKey, const unsigned char *iVec,
const unsigned char *in, int inlen,
unsigned char *out, int *poutlen)
{
int rv = 0, tmplen = 0;
const EVP_CIPHER *cipher = NULL;
EVP_CIPHER_CTX ctx;
/* 初始化加密调用的上下文 */
EVP_CIPHER_CTX_init(&ctx);
/* 根据名称(如des-cbc,或rc4)获取CIPHER对象,OpenSSL支持的算法名称可以用openssl enc -h命令列出 */
#if 0
cipher = EVP_get_cipherbyname(ciphername);
if (NULL == cipher) {
fprintf( stderr, "OpenSSL_Cipher: Cipher for %s is NULL\n", ciphername );
rv = -1;
goto err;
}
#endif
printf("ciphername is %d\n",ciphername);
printf("AES_CBC is %d\n",AES_CBC);
switch(ciphername)
{
case AES_CBC:
cipher = EVP_aes_128_cbc();
break;
default:
printf("no switch EVP_CIPHER");
return -9;
}
/**
* 初始化算法:设置对称算法的密钥,IV,以及加解密标志位dir
* 如果使用Engine,此时会调用其实现的EVP_CIPHER->init回调函数
*/
if (!EVP_CipherInit_ex(&ctx, cipher, NULL, aKey, iVec, dir)) {
fprintf( stderr, "OpenSSL_Cipher: EVP_CipherInit failed\n");
rv = -2;
goto err;
}
/**
* 对数据进行加/解密运算(如果使用Engine,此时会调用其实现的EVP_CIPHER->do_cipher回调函数)
* 对于连续数据流,CipherUpdate一般会被调用多次
*/
if (!EVP_CipherUpdate(&ctx, out, poutlen, in, inlen)) {
fprintf( stderr, "OpenSSL_Cipher: EVP_CipherInit failed\n");
rv = -3;
goto err;
}
/**
* 输出最后一块数据结果(块加密时,数据将被padding到block长度的整数倍,因此会产生额外的最后一段数据)
* 注意:如果使用Engine,此时会触发其实现的EVP_CIPHER->do_cipher,而不是EVP_CIPHER->cleanup
* 这点上与EVP_DigestFinal/EVP_SignFinal/EVP_VerifyFinal是完全不同的
*/
if (!EVP_CipherFinal(&ctx, out + *poutlen, &tmplen)) {
fprintf( stderr, "OpenSSL_Cipher: EVP_CipherInit failed\n");
rv = -4;
goto err;
}
*poutlen += tmplen;
err:
/* 释放上下文(如果使用Engine,此时会调用其实现的EVP_CIPHER->cleanup回调函数) */
EVP_CIPHER_CTX_cleanup(&ctx);
return rv;
}
void my_evp_free()
{
//与OpenSSl_add_all_algorithms正好相反
EVP_cleanup();
return;
}
int main(int argc,char *argv[])
{
EVP_ALGORITHM chname;
printf("chname = %d\n",chname);
chname = AES_CBC;
printf("chname = %d\n",chname);
#if 1
int i = 0;
int detct_len = 0;
int source_len = 0;
unsigned char source[4*MSG_LEN] = {0};
unsigned char detct[4*MSG_LEN] = {0};
my_evp_init();
FILE * fre = fopen(argv[1],"rb");
size_t fre_len = 0;
FILE * fwr = fopen(argv[2],"wb");
size_t fwr_len = 0;
unsigned char key[16] = {0};
unsigned char iv[16] = {0};
for(i = 0;i<16;i++)
key[i] = 32 + i;
while(!feof(fre))
{
printf("chname = %d\n",chname);
fre_len = fread(source,sizeof(char),2*MSG_LEN,fre);
OpenSSL_Cipher(chname, ENCRY,key,iv,source,fre_len,detct,&detct_len);
printf("detct_len = %d\n",detct_len);
memset(source,0,sizeof(source));
OpenSSL_Cipher(chname, DECRY,key,iv,detct,detct_len,source,&source_len);
printf("source_len = %d\n",source_len);
fwr_len = fwrite(source,sizeof(char),source_len,fwr);
}
fclose(fre);
fclose(fwr);
my_evp_free();
#endif
return 0;
}
这篇关于EVP AES_CBC加密解密记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!