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双重加密,是数据更加安全. 使用前提: 如果客户端本 ...
随机推荐
- css实现渐变字体和流光字体
这是段渐变文本 .text{ font-size: 30px; font-weight: bold; background-image: linear-gradient(#ed3f27, #9b099 ...
- 机器学习总结-sklearn参数解释
本文转自:lytforgood 机器学习总结-sklearn参数解释 实验数据集选取: 1分类数据选取 load_iris 鸢尾花数据集 from sklearn.datasets import lo ...
- Codeforces 1188B Count Pairs (同余+分离变量)
题意: 给一个3e5的数组,求(i,j)对数,使得$(a_i+a_j)(a_i^2+a_j^2)\equiv k\ mod\ p$ 思路: 化简$(a_i^4-a_j^4)\equiv k(a_i-a ...
- java6循环结构二
public class jh_01_回顾与作业点评 { public static void main(String[] args) { int val = 12345; System.out.pr ...
- LeetCode 127. Word Ladder 单词接龙(C++/Java)
题目: Given two words (beginWord and endWord), and a dictionary's word list, find the length of shorte ...
- C#实现读取IPv6 UDP Socket数据,再发送出去
C#实现读取IPv6 UDP Socket数据,再发送出去. 不知为何,黑框点一下就停止刷新了,再点一下,就继续刷新了. using System; using System.Collections. ...
- 在列表中动态设置元素的id
<div class="col-6" v-for="(item,i) in showpics" :key="i"> <im ...
- ES6学习笔记(一):轻松搞懂面向对象编程、类和对象
目录 面向过程编程P OP(Process oriented programming) 面向对象编程OOP(Object Oriented Programming) 总结 @ 面向过程编程P OP(P ...
- Java面试—消息队列
消息队列面试题 题目来自于中华石杉,解决方案根据自己的思路来总结而得. 题目主要如下: 1. 为什么要引入消息队列? 消息队列的引入可以解决3个核心问题: 解耦 异步 削峰 解耦 在一个项目中,如果一 ...
- 【STM32H7教程】第61章 STM32H7的MDMA基础知识和HAL库API
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第61章 STM32H7的MDMA基础知识和HAL ...