C#调用Crypto++库AES ECB加解密
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了C#调用Crypto++库AES ECB加解密,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含13005字,纯文字阅读大概需要19分钟。
内容图文
本文章使用上一篇《C#调用C++类库例子》的项目代码作为Demo。本文中,C#将调用C++的Crypto++库,实现AES和ECB加解密。
一、下载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
原文:https://www.cnblogs.com/suterfo/p/12304673.html
内容总结
以上是互联网集市为您收集整理的C#调用Crypto++库AES ECB加解密全部内容,希望文章能够帮你解决C#调用Crypto++库AES ECB加解密所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。