C#调用Crypto++库AES ECB CBC加解密
本文章使用上一篇《C#调用C++类库例子》的项目代码作为Demo。本文中,C#将调用C++的Crypto++库,实现AES的ECB和CBC加解密。
一、下载Crypto
1、进入Crypto的官网下载openssl。网址是: https://www.cryptopp.com/。

2、点击“DownLoad”,选择最新的可下载的版本即可。此时我下载的是cryptopp820.zip,如下图所示的。

3、解压 cryptopp820.zip。
4、打开cryptopp820文件夹中的cryptest.sln,点击“重定解决方案目标”。


5、重新生成解决方案。
二、建立自己使用的Crypto++ Library
由于从官方网下载的Crypto++库是开源的,只有源文件和几个可以生成lib、dll的工程,以及一个使用的例子工程,因此希望生成自己建的工程能使用的SDK。
1. 编译链接生成cryptlib.lib
根据当前项目系统设置平台(我是设置为x64),分别在Debug模式和Release模式下编译链接cryptlib工程,成功后会在cryptopp820\x64\Output\Debug和cryptopp820\x64\Output\Release下生成cryptlib.lib文件。
2. 建立Crypto++ SDK
在解决方案下新建一文件夹,取名“CryptoPP”,里面新建文件夹“include”、“lib”,在“lib”中新建文件夹“debug”、“release”。将Crypto++库中的所有头文件复制到“include”文件夹中,再将上面生成的两个cryptlib.lib分别复制到“debug”和“release”中。

三、设置工程属性
在EncryptBese项目--右键--属性:
(1)“配置属性”→“C/C++” →“常规”,右边的“附加包含目录”设置为上面建好的Crypto++ SDK的Include文件夹,“E:\Project\ArticleProject\AuthorizationTest\CryptoPP\include”;

(2) “配置属性”→“Linker” →“链接器”,右边的“附加库目录”设置为上面建好的Crypto++ SDK的Lib\Debug文件夹,“E:\Project\ArticleProject\AuthorizationTest\CryptoPP\lib\debug”(Release模式下对应着Release文件夹);

(3) “配置属性”→“C/C++” →“代码生成”,右边的“运行库”设置为“Multi-threaded Debug (/MTd)”(Release模式下对应着“Multi-threaded (/MT)”)

四、为EncryptBase项目添加代码
1、在EncryptBase.h文件添加以下代码
#ifndef _ENCRYPTBASE_H //定义_ENRYPTBASE_H宏,是为了防止头文件的重复引用
#define _ENCRYPTBASE_H #ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件,
extern "C" { //因为cpp文件默认定义了该宏),则采用C语言方式进行编译
#endif #ifdef DLL_EXPORTS
#define DLL_EXPORTS __declspec(dllexport)
#else
#define DLL_EXPORTS __declspec(dllimport)
#endif
enum AESMode
{
ECB = 0x00,
CBC,
};
enum BlockPaddingScheme {
NO_PADDING,
ZEROS_PADDING,
PKCS_PADDING,
ONE_AND_ZEROS_PADDING,
W3C_PADDING,
DEFAULT_PADDING
}; DLL_EXPORTS int AesEncrypt(AESMode mode, BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int ivlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen);
DLL_EXPORTS int AesDecrypt(AESMode mode, BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int inlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen); int AesEcbEncrypt(BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int inlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen);
int AesEcbDecrypt(BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int inlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen);
int AesCbcEncrypt(BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int inlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen);
int AesCbcDecrypt(BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int inlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen); #ifdef __cplusplus
}
#endif #endif // !_ENCRYPTBASE_H
2、EncryptBase.cpp添加相关代码,如下图。

在EncryptBase.cpp修改为以下代码:
// EncryptBase.cpp: 定义 DLL 应用程序的导出函数。
// #include "stdafx.h"
#include "EncryptBase.h"
#include "base64.h"
#include <aes.h>
#include <modes.h>
#include <Hex.h> // StreamTransformationFilter using namespace std;
using namespace CryptoPP;
#pragma comment(lib, "cryptlib.lib") //加密
int AesEncrypt(AESMode mode, BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int ivlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen)
{
int rtnRs = 0;
switch (mode)
{
case AESMode::ECB:
rtnRs = AesEcbEncrypt(scheme, key, keylen, iv, ivlen, plainText, txtlen, out, outLen);
break;
case AESMode::CBC:
rtnRs = AesCbcEncrypt(scheme, key, keylen, iv, ivlen, plainText, txtlen, out, outLen);
break;
}
return rtnRs;
}
//解密
int AesDecrypt(AESMode mode, BlockPaddingScheme scheme, const BYTE *key, int keylen, const BYTE *iv, int ivlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen)
{
int rtnRs = 0;
switch (mode)
{
case AESMode::ECB:
rtnRs = AesEcbDecrypt(scheme, key, keylen, iv, ivlen, cipherText, txtlen, out, outLen);
break;
case AESMode::CBC:
rtnRs = AesCbcDecrypt(scheme, key, keylen, iv, ivlen, cipherText, txtlen, out, outLen);
break;
}
return rtnRs;
} //AES_ECB加密
int AesEcbEncrypt(BlockPaddingScheme scheme, const BYTE *skey, int keylen, const BYTE *iv, int ivlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen)
{
int rtnLength = -1;
try {
//填key
SecByteBlock key(AES::MIN_KEYLENGTH);
memset(key, 0x00, key.size()); if (keylen <= AES::MIN_KEYLENGTH)
{
memcpy(key, skey, keylen);
}
else
{
memcpy(key, skey, AES::MIN_KEYLENGTH);
}
AES::Encryption aesEncryption(key, AES::MIN_KEYLENGTH); ECB_Mode_ExternalCipher::Encryption ecbEncryption(aesEncryption); vector<BYTE> encrypted;
StreamTransformationFilter stfEncryptor(
ecbEncryption,
new VectorSink(encrypted),
(CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme)scheme); stfEncryptor.Put(plainText, txtlen); //this is where it crashes
stfEncryptor.MessageEnd(); rtnLength = encrypted.size();
memcpy(out, encrypted.data(), rtnLength); }
catch (exception e)
{
cout << e.what() << endl;
//TODO:记录日志
rtnLength = -1;
} return rtnLength;
} //AES_ECB解密
int AesEcbDecrypt(BlockPaddingScheme scheme, const BYTE *skey, int keylen, const BYTE *siv, int ivlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen)
{
int rtnLength = -1;
try {
//填key
SecByteBlock key(AES::MIN_KEYLENGTH);
memset(key, 0x00, key.size());
if (keylen <= AES::MIN_KEYLENGTH)
{
memcpy(key, skey, keylen);
}
else
{
memcpy(key, skey, AES::MIN_KEYLENGTH);
}
ECB_Mode<AES>::Decryption ecbDecryption(key, AES::MIN_KEYLENGTH); vector<BYTE> decrypted;
StreamTransformationFilter stfDecryptor(
ecbDecryption,
new VectorSink(decrypted),
(CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme)scheme); stfDecryptor.Put(cipherText, txtlen);
stfDecryptor.MessageEnd(); rtnLength = decrypted.size();
memcpy(out, decrypted.data(), rtnLength); }
catch (exception e)
{
cout << e.what() << endl;
//TODO:记录日志
} return rtnLength;
} //AES_CBC加密
int AesCbcEncrypt(BlockPaddingScheme scheme, const BYTE *skey, int keylen, const BYTE *siv, int ivlen, const BYTE *plainText, int txtlen, BYTE *out, int outLen)
{ int rtnLength = -1;
try {
//填key
SecByteBlock key(AES::MIN_KEYLENGTH);
memset(key, 0x00, key.size());
if (keylen <= AES::MIN_KEYLENGTH)
{
memcpy(key, skey, keylen);
}
else
{
memcpy(key, skey, AES::MIN_KEYLENGTH);
} //填iv
byte iv[AES::BLOCKSIZE];
memset(iv, 0x00, AES::BLOCKSIZE);
if (ivlen <= AES::BLOCKSIZE)
{
memcpy(iv, siv, ivlen);
}
else
{
memcpy(iv, siv, AES::BLOCKSIZE);
} AES::Encryption aesEncryption((byte *)key, AES::MIN_KEYLENGTH); CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv); vector<BYTE> decrypted;
StreamTransformationFilter stfDecryptor(
cbcEncryption,
new VectorSink(decrypted),
(CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme)scheme); stfDecryptor.Put(plainText, txtlen);
stfDecryptor.MessageEnd(); rtnLength = decrypted.size();
memcpy(out, decrypted.data(), rtnLength);
}
catch (exception e)
{
cout << e.what() << endl;
//TODO:记录日志
rtnLength = -1;
}
return rtnLength;
} //AES_CBC解密
int AesCbcDecrypt(BlockPaddingScheme scheme, const BYTE *skey, int keylen, const BYTE *siv, int ivlen, const BYTE *cipherText, int txtlen, BYTE *out, int outLen)
{
int rtnLength = -1;
try
{
//填key
SecByteBlock key(AES::MIN_KEYLENGTH);
memset(key, 0x00, key.size()); if (keylen <= AES::MIN_KEYLENGTH)
{
memcpy(key, skey, keylen);
}
else
{
memcpy(key, skey, AES::MIN_KEYLENGTH);
}
//填iv
byte iv[AES::BLOCKSIZE];
memset(iv, 0x00, AES::BLOCKSIZE);
if (ivlen <= AES::BLOCKSIZE)
{
memcpy(iv, siv, ivlen);
}
else
{
memcpy(iv, siv, AES::BLOCKSIZE);
} CBC_Mode<AES>::Decryption cbcDecryption(key, AES::MIN_KEYLENGTH, iv); vector<BYTE> decrypted;
StreamTransformationFilter stfDecryptor(
cbcDecryption,
new VectorSink(decrypted),
(CryptoPP::BlockPaddingSchemeDef::BlockPaddingScheme)scheme); stfDecryptor.Put(cipherText, txtlen);
stfDecryptor.MessageEnd(); rtnLength = decrypted.size();
memcpy(out, decrypted.data(), rtnLength);
}
catch (exception e)
{
cout << e.what() << endl;
//TODO:记录日志
} return rtnLength;
}
五、编写测试代码
1、在在FrameworkConsoleTest项目的Program编写以下代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks; namespace FrameworkConsoleTest
{
class Program
{
[DllImport("EncryptBase.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AesEncrypt(AESMode mode, BlockPaddingScheme scheme, byte[] key, int keylen, byte[] iv, int ivlen, byte[] plainTextPtr, int txtlen, byte[] outBytes, int outLen); [DllImport("EncryptBase.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AesDecrypt(AESMode mode, BlockPaddingScheme scheme, byte[] key, int keylen, byte[] iv, int ivlen, byte[] plainTextPtr, int txtlen, byte[] outBytes, int outLen); static void Main(string[] args)
{
try
{ string plainText = "123456";
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); //AesKey密匙
string key = "abc123456_+,./@$";
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
//IV向量
byte[] ivBytes = new byte[16];
for (int i = 0; i < 16; i++)
{
ivBytes[i] = 0;
}
string strEncrypt = string.Empty;
string strDecrypt = string.Empty;
byte[] encryptOutBytes = new byte[100];
int execRs = -1; execRs = ToAesEncrypt(AESMode.ECB, BlockPaddingScheme.PKCS_PADDING, keyBytes, ivBytes, plainTextBytes, ref encryptOutBytes);
if (execRs > 0)
{
strEncrypt = Convert.ToBase64String(encryptOutBytes, 0, execRs);
}
Console.WriteLine("Aes Ecb Encrypt,明文:{0},密文:{1}", plainText, strEncrypt);
if (execRs > 0)
{
byte[] decryptBytes = new byte[execRs];
for (int i = 0; i<execRs; i++)
{
decryptBytes[i] = encryptOutBytes[i];
}
byte[] decryptOutBytes = new byte[100];
execRs = ToAesDecrypt(AESMode.ECB, BlockPaddingScheme.PKCS_PADDING, keyBytes, ivBytes, decryptBytes, ref decryptOutBytes);
if (execRs > 0)
{
strDecrypt = System.Text.Encoding.UTF8.GetString(decryptOutBytes, 0, execRs);
}
Console.WriteLine("Aes Ecb Decrypt,解密后明文:{0}", strDecrypt);
} byte[] encryptOutBytes2 = new byte[100];
execRs = ToAesEncrypt(AESMode.CBC, BlockPaddingScheme.PKCS_PADDING, keyBytes, ivBytes, plainTextBytes, ref encryptOutBytes2);
if (execRs > 0)
{
strEncrypt = Convert.ToBase64String(encryptOutBytes2, 0, execRs);
}
Console.WriteLine("Aes Cbc Encrypt,明文:{0},密文:{1}", plainText, strEncrypt);
if (execRs > 0)
{
byte[] decryptBytes2 = new byte[execRs];
for (int i = 0; i<execRs; i++)
{
decryptBytes2[i] = encryptOutBytes2[i];
}
byte[] decryptOutBytes2 = new byte[100];
execRs = ToAesDecrypt(AESMode.CBC, BlockPaddingScheme.PKCS_PADDING, keyBytes, ivBytes, decryptBytes2, ref decryptOutBytes2);
if (execRs > 0)
{
strDecrypt = System.Text.Encoding.UTF8.GetString(decryptOutBytes2, 0, execRs);
}
Console.WriteLine("Aes Cbc Decrypt,解密后明文:{0}", strDecrypt);
} }
catch (Exception ex)
{
Console.WriteLine("Main,ex:{0}", ex);
}
Console.ReadKey();
}
private static int ToAesEncrypt(AESMode mode, BlockPaddingScheme scheme, byte[] keyBytes, byte[] ivBytes, byte[] encryptBytes, ref byte[] outBytes)
{
int rtnRs = -1;
if (encryptBytes == null || encryptBytes.Count() == 0)
{
rtnRs = 0;
goto TOEND;
}
try
{
int keyBytesLen = keyBytes.Length;
int ivBytesLen = ivBytes.Length;
int txtBytesLen = encryptBytes.Length; int outLen = outBytes.Length;
//C#数组有长度,C++指针没长度,所以函数应该定义两个参数,一个数据BYTE*,一个长度int
rtnRs = AesEncrypt(mode, scheme, keyBytes, keyBytesLen, ivBytes, ivBytesLen, encryptBytes, txtBytesLen, outBytes, outLen);
}
catch (Exception ex)
{
Console.WriteLine("AesEncrypt,ex:{0}", ex);
}
TOEND:
;
return rtnRs;
} private static int ToAesDecrypt(AESMode mode, BlockPaddingScheme scheme, byte[] keyBytes, byte[] ivBytes, byte[] decryptBytes, ref byte[] outBytes)
{
int rtnRs = -1;
if (decryptBytes == null || decryptBytes.Count() == 0)
{
rtnRs = 0;
goto TOEND;
}
try
{
//因为 C++ 返回的是 char* ,是指针,所以c# 要用 IntPtr 来接收
int txtBytesLen = decryptBytes.Length;
int keyBytesLen = keyBytes.Length;
int ivBytesLen = ivBytes.Length; int outLen = outBytes.Length; //C#数组有长度,C++指针没长度,所以函数应该定义两个参数,一个数据char*,一个长度int
rtnRs = AesDecrypt(mode, scheme, keyBytes, keyBytesLen, ivBytes, ivBytesLen, decryptBytes, txtBytesLen, outBytes, outLen); }
catch (Exception ex)
{
Console.WriteLine("AesDecrypt,ex:{0}", ex);
}
TOEND:
;
return rtnRs;
}
}
}
2、添加Enum.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace FrameworkConsoleTest
{
enum AESMode
{
ECB = 0x00,
CBC,
}; enum BlockPaddingScheme
{
NO_PADDING,
ZEROS_PADDING,
PKCS_PADDING,
ONE_AND_ZEROS_PADDING,
W3C_PADDING,
DEFAULT_PADDING
};
}
六、整体结构

七、结果测试
1、运行结果

2、通过和其它平台测试比较结果,我是在http://tool.chacuo.net/cryptaes进行结果比对的。 
八、下载地址
https://download.csdn.net/download/suterfo/12155867
九、参考资料:
https://www.cnblogs.com/cxun/archive/2008/07/30/743541.html
https://blog.csdn.net/liang19890820/article/details/51659452
https://www.cryptopp.com/wiki/Filter
C#调用Crypto++库AES ECB CBC加解密的更多相关文章
- python 实现 AES ECB模式加解密
AES ECB模式加解密使用cryptopp完成AES的ECB模式进行加解密. AES加密数据块分组长度必须为128比特,密钥长度可以是128比特.192比特.256比特中的任意一个.(8比特 == ...
- golang AES/ECB/PKCS5 加密解密 url-safe-base64
因为项目的需要用到golang的一种特殊的加密解密算法AES/ECB/PKCS5,但是算法并没有包含在标准库中,经过多次失败的尝试,终于解码成功,特此分享: /* 描述 : golang AES/EC ...
- Asp.Net Core 2.0 项目实战(7)MD5加密、AES&DES对称加解密
本文目录 1. 摘要 2. MD5加密封装 3. AES的加密.解密 4. DES加密/解密 5. 总结 1. 摘要 C#中常用的一些加密和解密方案,如:md5加密.RSA加密与解密和DES加密等, ...
- iOS CommonCrypto 对称加密 AES ecb,cbc
CommonCrypto 为苹果提供的系统加密接口,支持iOS 和 mac 开发: 不仅限于AES加密,提供的接口还支持其他DES,3DES,RC4,BLOWFISH等算法, 本文章主要讨论AES在i ...
- AES/ECB/NoPadding 加减密
package unit; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache. ...
- POCO库——Foundation组件之加解密Crypt
加解密Crypt:内部提供多种加解密方式.信息摘要提取.随机数产生等,具体的算法内部实现不做研究学习: DigestEngine.h :DigestEngine类作为各种摘要提取的基类,提供必要的接口 ...
- 使用java实现AES算法的加解密(亲测可用)
话不多说,直接上代码 import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.cryp ...
- AES和RSA加解密的Python用法
AES AES 是一种对称加密算法,用key对一段text加密,则用同一个key对密文解密, from Crypto import Random from Crypto.Hash import SHA ...
- 使用RAS+AES对接口数据加解密
在实际开发中,会遇到两个系统之间传输数据,为了对传输的数据进行保护,需要发送方对接口数据进行加密,接收方对数据解密. 对数据加密,采用RSA+AES双重加密,是数据更加安全. 使用前提: 如果客户端本 ...
随机推荐
- python 函数3(模块)
1.将函数存储在模块中 1.1.导入整个模块 要将函数导入,得先创建模块,模块 是扩展名为.py的文件,包含要导入到程序中的代码. 首先定义编写一个.py的文件,命名为pizza.py,代码如下: d ...
- java(list,set,map)链接
http://blog.csdn.net/smileiam/article/details/49836865 http://blog.csdn.net/u013344815/article/detai ...
- ARTS Week 8
Dec 16, 2019 ~ Dec 22, 2019 Algorithm Problem 53 Maximum Subarray 最大子数组 题目链接 题目描述:给定一个数组,在所有连续的子数组中, ...
- (三)(2)wait/notify实现生产者-消费者模型,join方法
生产者,消费者模型 举个例子来说明,厨师,服务员,厨师做菜,服务员上菜,如果厨师没有做好菜,那么服务员就无法上菜,厨师做好了菜,然后通知服务员消费(上菜).在这个过程之中,厨师扮演的就是生产者,服务员 ...
- jsp关于request.setAttribue还有response.addCookie()的两个问题
刚才使用request.getAttribute();时候无法获取到值,一直为null,经过分析,得到下面的 index1.jsp <%-- Created by IntelliJ IDEA. ...
- 五种编程语言解释数据结构与算法——顺序表1(理论与C语言实现)
1.线性表的分类 2.线性表的定义及其基本操作 2.1.定义:线性表是具有相同类型的n(n>=0)个元素的有序序列,其中n为表长,当n=0时,该表为空表. 2.3.线性表的逻辑结构为: 2.4. ...
- 免费网盘!无限申请5TB容量并且不限速的网盘!
鸽了好久没有更新博客了哎…… 前言 这里我先说一下下,本人深受百度网盘坑害,自己上传的文件,16GB下载花了3天时间 最后下载失败? 所以找到的一个新的储存个人文件的方法. 这个网盘是onedrive ...
- step1:准备歌词之《前端开发是个啥》
以下是给大家介绍前端开发的填词,曲子是李圣杰的<最近>,大家喜欢可以试试唱. 点赞关注超过100的平台,我后续上来发本人原唱视频(目前正在练习中...),另外大家觉得哪些词写得不好的,欢迎 ...
- Python3(九) 闭包
一. 一切皆对象 函数式编程并没有标准定义,如果代码非常繁琐则考虑使用. 学习闭包的概念,不是python独有的. 其他大多数语言中的函数只是一段可执行的代码,并不是对象. python中的函数是对象 ...
- Java逃逸分析
Java逃逸分析 记录下看到的别人的博客内容,以后深入了解再详细写篇,加深下基础概念和印象! 一般来说,Java对象的创建,通常是在堆空间中分配内存,但是如果大量的临时对象也在堆空间创建的话,会导致性 ...