c/c++基于openssl库的DES加密ECB模式pkcs5padding填充

c/c++基于openssl库的DES加密ECB模式pkcs5padding填充前言最近项目中需要使用DES加密算法,因为算法模式以及填充方式的不同导致无法正确加密解密,最终通过基于openssl库来完成加密解密.网上对于DES加解密的原理较多,这里就不做介绍,直接上干货,这里只主要介绍ecb模式,pkcs5填充的加密算法的实例,如果需要更换算法,可在下面代码的注释中找到对应的设置参数.准备在线加解密:http://tool.chacuo.net/cryptdes…

目录

  • 前言
  • 准备
  • 流程
  • 一.添加openssl库
  • 二.evp接口简介
  • 使用实例

前言

最近项目中需要使用DES加密算法,因为算法模式以及填充方式的不同导致无法正确加密解密,最终通过基于openssl库来完成加密解密.网上对于DES加解密的原理较多,这里就不做介绍,直接上干货,
这里只主要介绍ecb模式,pkcs5填充的加密算法的实例,如果需要更换算法,可在下面代码的注释中找到对应的设置参数.

准备

在线加解密: http://tool.chacuo.net/cryptdes
openssl库: 我的网盘 里有编译好的库,提取码:cato
积攒下来很多实用工具,大家取完了点个赞哈.

流程介绍

一.添加openssl库

openssl库目录如下:
在这里插入图片描述
分别把头文件和库包含到项目中:
在这里插入图片描述
在这里插入图片描述
最后需要在代码中链接库,即可正常使用openssl库中的接口

#include "openssl/evp.h"				//因为使用evp接口,所以包含evp.h这个头文件
#pragma comment(lib,"ssleay32.lib")
#pragma comment(lib,"libeay32.lib")

二.evp接口简介

使用流程:
1.初始化算法结构体

EVP_CIPHER_CTX ctx;				//EVP算法上下文
EVP_CIPHER_CTX_init(&ctx);

2.设置算法种类/密钥/偏移量

/*
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,ENGINE *impl, unsigned char *key, unsigned char *iv);
该函数采用ENGINE参数impl的算法来设置并初始化加密结构体。其中,参数ctx必须在调用本函数之前已经进行了初始化。
参数type通常通过函数类型来提供参数,如EVP_des_cbc函数的形式,即对称加密算法的类型。
如果参数impl为NULL,那么就会使用缺省的实现算法。
参数key是用来加密的对称密钥,iv参数是初始化向量(如果需要的话)。
在算法中真正使用的密钥长度和初始化密钥长度是根据算法来决定的。
在调用该函数进行初始化的时候,除了参数type之外,所有其它参数可以设置为NULL,留到以后调用其它函数的时候再提供,这时候参数type就可设置为NULL。
在缺省的加密参数不合适的时候,可以这样处理。操作成功返回1,否则返回0。
*/
rv = EVP_EncryptInit_ex(&ctx, EVP_des_ecb(), NULL, key, iv);
if(rv != 1)
	return TRUE;

3.开始加密解密

/*
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl);
该函数执行对数据的加密。该函数加密从参数in输入的长度为inl的数据,并将加密好的数据写入到参数out里面去。
可以通过反复调用该函数来处理一个连续的数据块。
写入到out的数据数量是由已经加密的数据的对齐关系决定的,理论上来说,从0到(inl+cipher_block_size-1)的任何一个数字都有可能(单位是字节),
所以输出的参数out要有足够的空间存储数据。
写入到out中的实际数据长度保存在outl参数中。操作成功返回1,否则返回0。
*/
rv = EVP_EncryptUpdate(&ctx, sCipher, &nCipher, (BYTE*)strInput, strlen(strInput));
if(rv != 1)
	return TRUE;

4.输出数据

/*
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
该函数处理最后(Final)的一段数据。在函数在padding功能打开的时候(缺省)才有效,这时候,它将剩余的最后的所有数据进行加密处理。
该算法使用标志的块padding方式(AKA PKCS padding)。加密后的数据写入到参数out里面,参数out的长度至少应该能够一个加密块。
写入的数据长度信息输入到outl参数里面。该函数调用后,表示所有数据都加密完了,不应该再调用EVP_EncryptUpdate函数。
如果没有设置padding功能,那么本函数不会加密任何数据,如果还有剩余的数据,那么就会返回错误信息,也就是说,这时候数据总长度不是块长度的整数倍。
操作成功返回1,否则返回0。
PKCS padding标准是这样定义的,在被加密的数据后面加上n个值为n的字节,使得加密后的数据长度为加密块长度的整数倍。
无论在什么情况下,都是要加上padding的,也就是说,如果被加密的数据已经是块长度的整数倍,那么这时候n就应该等于块长度。
比如,如果块长度是9,要加密的数据长度是11,那么5个值为5的字节就应该增加在数据的后面。
*/
rv = EVP_EncryptFinal_ex(&ctx, sCipher + nCipher, &nTmp);
	if(rv != 1)
		return TRUE;

5.输出密文是不可视化的,以base64数据显示

使用实例

// Openssl_DES.cpp : 定义控制台应用程序的入口点。
//

#include <Windows.h>
#include "openssl/evp.h"
#pragma comment(lib,"ssleay32.lib")
#pragma comment(lib,"libeay32.lib")

int Base64Encode(unsigned char* pIn, unsigned char* pOut, int nInLen)
{
	char base64tab[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	unsigned char c1, c2, c3;
	int nInPos = 0;
	int nOutPos = 0;
	int i;

	for (i = 0; i<nInLen / 3; i++)
	{
		c1 = pIn[nInPos++];
		c2 = pIn[nInPos++];
		c3 = pIn[nInPos++];

		pOut[nOutPos++] = base64tab[(c1 & '\xFC') >> 2];
		pOut[nOutPos++] = base64tab[((c1 & '\x03') << 4) | ((c2 & '\xF0') >> 4)];
		pOut[nOutPos++] = base64tab[((c2 & '\x0F') << 2) | ((c3 & '\xC0') >> 6)];
		pOut[nOutPos++] = base64tab[c3 & '\x3F'];
	}

	if (nInLen % 3 == 1)
	{
		c1 = pIn[nInPos++];
		pOut[nOutPos++] = base64tab[(c1 & '\xFC') >> 2];
		pOut[nOutPos++] = base64tab[((c1 & '\x03') << 4)];
		pOut[nOutPos++] = '=';
		pOut[nOutPos++] = '=';
	}
	else if (nInLen % 3 == 2)
	{
		c1 = pIn[nInPos++];
		c2 = pIn[nInPos++];
		pOut[nOutPos++] = base64tab[(c1 & '\xFC') >> 2];
		pOut[nOutPos++] = base64tab[((c1 & '\x03') << 4) | ((c2 & '\xF0') >> 4)];
		pOut[nOutPos++] = base64tab[((c2 & '\x0F') << 2)];
		pOut[nOutPos++] = '=';
	}

	pOut[nOutPos] = '\0';
	return nOutPos;
}
bool Encrypt(unsigned char *key, unsigned char *iv, char *strInput, char *strOutput)
{
	EVP_CIPHER_CTX ctx;				//EVP算法上下文
	unsigned char sCipher[4096];	//密文缓冲区
	int nCipher;					//密文长度
	int nTmp;
	int rv;
	unsigned char sBase64[4096];

	//初始化密码算法结构体
	EVP_CIPHER_CTX_init(&ctx);
	//设置算法和密钥
	rv = EVP_EncryptInit_ex(&ctx, EVP_des_ecb(), NULL, key, iv);
	if (rv != 1)
		return TRUE;
	//数据加密
	rv = EVP_EncryptUpdate(&ctx, sCipher, &nCipher, (BYTE*)strInput, strlen(strInput));
	if (rv != 1)
		return TRUE;
	//结束数据加密,把剩余数据输出
	rv = EVP_EncryptFinal_ex(&ctx, sCipher + nCipher, &nTmp);
	if (rv != 1)
		return TRUE;
	nCipher = nCipher + nTmp;
	//可视化输出base64
	Base64Encode(sCipher, sBase64, nCipher);
	sprintf(strOutput, "%s", sBase64);
	EVP_CIPHER_CTX_cleanup(&ctx);
	return FALSE;
}

int main()
{
	char strTmp[1024] = { 0 };
	Encrypt((unsigned char*)"miyao", (unsigned char*)"", "12345678", strTmp);
	printf("Result:%s\n", strTmp);
	system("pause");
	return 0;
}

(全文完)

参考:
EVP_Encrypt系列函数详解 : https://blog.csdn.net/gdwzh/article/details/19230

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/29858.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注