本文章使用上一篇《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://stackoverflow.com/questions/59323973/aes-ctr-decryption-stops-unexpectedly-using-crypto?r=SearchResults

https://www.cryptopp.com/wiki/Filter

C#调用Crypto++库AES ECB CBC加解密的更多相关文章

  1. python 实现 AES ECB模式加解密

    AES ECB模式加解密使用cryptopp完成AES的ECB模式进行加解密. AES加密数据块分组长度必须为128比特,密钥长度可以是128比特.192比特.256比特中的任意一个.(8比特 == ...

  2. golang AES/ECB/PKCS5 加密解密 url-safe-base64

    因为项目的需要用到golang的一种特殊的加密解密算法AES/ECB/PKCS5,但是算法并没有包含在标准库中,经过多次失败的尝试,终于解码成功,特此分享: /* 描述 : golang AES/EC ...

  3. Asp.Net Core 2.0 项目实战(7)MD5加密、AES&DES对称加解密

    本文目录 1. 摘要 2. MD5加密封装 3. AES的加密.解密 4. DES加密/解密 5. 总结 1.  摘要 C#中常用的一些加密和解密方案,如:md5加密.RSA加密与解密和DES加密等, ...

  4. iOS CommonCrypto 对称加密 AES ecb,cbc

    CommonCrypto 为苹果提供的系统加密接口,支持iOS 和 mac 开发: 不仅限于AES加密,提供的接口还支持其他DES,3DES,RC4,BLOWFISH等算法, 本文章主要讨论AES在i ...

  5. AES/ECB/NoPadding 加减密

    package unit; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.apache. ...

  6. POCO库——Foundation组件之加解密Crypt

    加解密Crypt:内部提供多种加解密方式.信息摘要提取.随机数产生等,具体的算法内部实现不做研究学习: DigestEngine.h :DigestEngine类作为各种摘要提取的基类,提供必要的接口 ...

  7. 使用java实现AES算法的加解密(亲测可用)

    话不多说,直接上代码 import javax.crypto.Cipher;   import javax.crypto.spec.IvParameterSpec; import javax.cryp ...

  8. AES和RSA加解密的Python用法

    AES AES 是一种对称加密算法,用key对一段text加密,则用同一个key对密文解密, from Crypto import Random from Crypto.Hash import SHA ...

  9. 使用RAS+AES对接口数据加解密

    在实际开发中,会遇到两个系统之间传输数据,为了对传输的数据进行保护,需要发送方对接口数据进行加密,接收方对数据解密. 对数据加密,采用RSA+AES双重加密,是数据更加安全. 使用前提: 如果客户端本 ...

随机推荐

  1. java设计模式5——适配器模式

    java设计模式5--适配器模式 1.结构型模式介绍 1.1.作用 从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题. 分类: 适配器模式 代理模式 桥接模式 装饰模式 组合模式 ...

  2. 用MYSQL的存储过程创建百万级测试数据表

    创建随机字符串函数,便于创建名称 DROP function if EXISTS rand_string; #创建一个指定字符个数的函数 create function rand_string(n I ...

  3. 搭建python运行环境

    一.下载Anaconda Anaconda是Python的包管理器和环境管理器 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 参考:ht ...

  4. Go语言实现:【剑指offer】二维数组中的查找

    该题目来源于牛客网<剑指offer>专题. 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一 ...

  5. 转:RBAC如何设计一个权限系统

    前言 权限管理是所有后台系统的都会涉及的一个重要组成部分,主要目的是对不同的人访问资源进行权限的控制,避免因权限控制缺失或操作不当引发的风险问题,如操作错误,隐私数据泄露等问题.目前在公司负责权限这块 ...

  6. liunx 上守护进程的设置

    */2 * * * * root /data/autojobsh/auto_ck_pms_10250.sh */2 * * * * root /data/autojobsh/auto_ck_ipms_ ...

  7. Java HashMap 四种遍历方式

    HashMap遍历方式包含以下4种: 1.遍历KeySet,再通过Key来getValue. 2.使用entrySet的迭代器. 3.foreach entrySet的方式. 3.foreache v ...

  8. 《自拍教程17》Python调用命令

    他山之石 何为他山之石,就是借助外界工具,来实现自己想要的功能. 命令行界面软件, 即各种命令,我们也叫命令行工具, 此类工具也是测试人员或者开发人员常用的工具的一种. 测试人员可以借助这类工具,快速 ...

  9. tensorflow roadshow 全球巡回演讲 会议总结

    非常荣幸有机会来到清华大学的李兆基楼,去参加 tensorflow的全球巡回.本次主要介绍tf2.0的新特性和新操作. 1. 首先,tensorflow的操作过程和机器学习的正常步骤一样,(speak ...

  10. KubeSphere企业级分布式多租户容器管理平台

    KubeSphere企业级分布式多租户容器管理平台 KubeSphere安装部署2.1.0DEV版本