近期,由于工作上与第三方公司传输数据的时候需要采取数据加密,但是我们采用的时较低版本的Delphi 6;由于加密算法等差异,导致在传输的加密数据第三方一致解析不了(具体问题表现为base64加密中文乱码,AES加密方式的运算模式Mode,填充模式padding);限于代码的管理规范不能使用加密的插件,且网上搜索相关的delphi加密资料少之又少;故决定采取Visual Studio来写加密解密算法的动态库,由Delphi调用。
(1)C#端的代码实现,首先在vs中创建一个“类库”项目TestDll:
using System.Runtime.InteropServices;
namespace TestDll
{
public interface ITestClass
{
void YourProcedure(stirng param1);
}
[ClassInterface(ClassInterfaceType.None)]
public classTestClass:ITestClass
{
public void YourProcedure(stirng param1);
{ //自己的代码 }
}
}
(2)C#端的配置实现:
a.选中该项目右击,选择【属性】,然后在【应用程序】中选择【程序集信息】如图:
b.同样是选中该项目右击,选择【属性】,然后在【生成】中选择【为COM互操作注册】保存,如图:
c.接下来是dll的注册,可以采用cmd命令框,也可以采用Bat文件:
(3)接下来是Delphi端的实现,Delphi程序调用此Dll方式有两种:
a.打开vs自带的工具“Visual Studio命令提示”,输入 TlbExp 路径\TestClass.dll 得到一个TestClass.tlb 文件(这个文件其实在编译的时候就会生成,可不做)。打开Delphi,选择“Project”–“import type library”找到刚才的TestClass.tlb,点击 CreateUnit,向delphi中引入一个com接口。
delphi 调用代码如下:
var aClass:TestClass;
begin
aClass := CoTestClass.Create;
aClass.YourProcedure('参数');
end;
b.不需生成tlb文件,仿照调用Excel的方式。代码如下:
var aClass: Variant;
begin
aClass:= CreateOleObject('TestDll.TestClass');
aClass.YourProcedure('参数');
end;
以上两种方法都可以调用成功,其中调用regasm.exe向系统注册dll是必需的。第一种方法需要生成tlb文件,并引入delphi中,操作繁琐,但可以看到接口的定义。第二种方法操作简单,但看不到接口的定义。
AES加解密code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Encryption
{
public interface IAES
{
string AesEncrypt(string value, string key, int mode, int paddingMode, string iv = "");
string AesDecrypt(string value, string key, int mode, int paddingMode, string iv = "");
}
[ClassInterface(ClassInterfaceType.None)]
public class AES : IAES
{
///
/// AES加密
///
/// 待加密的字符串
/// 秘钥(16,24,32位)
/// 运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)
/// 填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
/// 初始化向量(至少16位)
/// 加密后的字符串
public string AesEncrypt(string value, string key, int mode, int paddingMode, string iv = "")
{
if (string.IsNullOrEmpty(value)) return string.Empty;
if (key == null) throw new Exception("未将对象引用设置到对象的实例。");
if (key.Length < 16) throw new Exception("指定的密钥长度不能少于16位。");
if (key.Length > 32) throw new Exception("指定的密钥长度不能多于32位。");
if (key.Length != 16 && key.Length != 24 && key.Length != 32) throw new Exception("指定的密钥长度不明确。");
if (!string.IsNullOrEmpty(iv))
{
if (iv.Length < 16) throw new Exception("指定的向量长度不能少于16位。");
}
var _keyByte = Encoding.UTF8.GetBytes(key);
var _valueByte = Encoding.UTF8.GetBytes(value);
using (var aes = new RijndaelManaged())
{
aes.IV = !string.IsNullOrEmpty(iv) ? Encoding.UTF8.GetBytes(iv) : Encoding.UTF8.GetBytes(key.Substring(0, 16));
aes.Key = _keyByte;
switch(mode)
{
case 1:
aes.Mode = CipherMode.CBC;
break;
case 2:
aes.Mode = CipherMode.ECB;
break;
case 3:
aes.Mode = CipherMode.OFB;
break;
case 4:
aes.Mode = CipherMode.CFB;
break;
case 5:
aes.Mode = CipherMode.CTS;
break;
default:
aes.Mode = CipherMode.CBC;
break;
}
switch (paddingMode)
{
case 1:
aes.Padding = PaddingMode.None;
break;
case 2:
aes.Padding = PaddingMode.PKCS7;
break;
case 3:
aes.Padding = PaddingMode.Zeros;
break;
case 4:
aes.Padding = PaddingMode.ANSIX923;
break;
case 5:
aes.Padding = PaddingMode.ISO10126;
break;
default:
aes.Padding = PaddingMode.PKCS7;
break;
}
var cryptoTransform = aes.CreateEncryptor();
var resultArray = cryptoTransform.TransformFinalBlock(_valueByte, 0, _valueByte.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
}
///
/// AES解密
///
/// 待解密的字符串
/// 秘钥(16,24,32位)
/// 运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)
/// 填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
/// 初始化向量(至少16位)
/// 解密后的字符串
public string AesDecrypt(string value, string key, int mode, int paddingMode, string iv = "")
{
if (string.IsNullOrEmpty(value)) return string.Empty;
if (key == null) throw new Exception("未将对象引用设置到对象的实例。");
if (key.Length < 16) throw new Exception("指定的密钥长度不能少于16位。");
if (key.Length > 32) throw new Exception("指定的密钥长度不能多于32位。");
if (key.Length != 16 && key.Length != 24 && key.Length != 32) throw new Exception("指定的密钥长度不明确。");
if (!string.IsNullOrEmpty(iv))
{
if (iv.Length < 16) throw new Exception("指定的向量长度不能少于16位。");
}
var _keyByte = Encoding.UTF8.GetBytes(key);
var _valueByte = Convert.FromBase64String(value);
using (var aes = new RijndaelManaged())
{
aes.IV = !string.IsNullOrEmpty(iv) ? Encoding.UTF8.GetBytes(iv) : Encoding.UTF8.GetBytes(key.Substring(0, 16));
aes.Key = _keyByte;
switch (mode)
{
case 1:
aes.Mode = CipherMode.CBC;
break;
case 2:
aes.Mode = CipherMode.ECB;
break;
case 3:
aes.Mode = CipherMode.OFB;
break;
case 4:
aes.Mode = CipherMode.CFB;
break;
case 5:
aes.Mode = CipherMode.CTS;
break;
default:
aes.Mode = CipherMode.CBC;
break;
}
switch (paddingMode)
{
case 1:
aes.Padding = PaddingMode.None;
break;
case 2:
aes.Padding = PaddingMode.PKCS7;
break;
case 3:
aes.Padding = PaddingMode.Zeros;
break;
case 4:
aes.Padding = PaddingMode.ANSIX923;
break;
case 5:
aes.Padding = PaddingMode.ISO10126;
break;
default:
aes.Padding = PaddingMode.PKCS7;
break;
}
var cryptoTransform = aes.CreateDecryptor();
var resultArray = cryptoTransform.TransformFinalBlock(_valueByte, 0, _valueByte.Length);
return Encoding.UTF8.GetString(resultArray);
}
}
}
}
Base64加解密code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Encryption
{
public interface IBase64
{
string UnBase64String(string value);
string ToBase64String(string value);
}
[ClassInterface(ClassInterfaceType.None)]
public class Base64 : IBase64
{
public string UnBase64String(string value)
{
if (value == null || value == "")
{
return "";
}
byte[] bytes = Convert.FromBase64String(value);
return Encoding.UTF8.GetString(bytes);
}
public string ToBase64String(string value)
{
if (value == null || value == "")
{
return "";
}
byte[] bytes = Encoding.UTF8.GetBytes(value);
return Convert.ToBase64String(bytes);
}
}
}
DES加解密code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Encryption
{
interface IDES
{
string Encrypt(string entryStr, string key, int mode, int paddingMode);
string Decrypt(string entryStr, string key, int mode, int paddingMode);
}
public class DES:IDES
{
///
/// DES 加密
///
/// 待加密字符串
/// 8位16进制密钥字符串
/// 运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)
/// 填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
///
public string Encrypt(string entryStr, string key, int mode, int paddingMode)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
switch (mode)
{
case 1:
des.Mode = CipherMode.CBC;
break;
case 2:
des.Mode = CipherMode.ECB;
break;
case 3:
des.Mode = CipherMode.OFB;
break;
case 4:
des.Mode = CipherMode.CFB;
break;
case 5:
des.Mode = CipherMode.CTS;
break;
default:
des.Mode = CipherMode.ECB;
break;
}
switch (paddingMode)
{
case 1:
des.Padding = PaddingMode.None;
break;
case 2:
des.Padding = PaddingMode.PKCS7;
break;
case 3:
des.Padding = PaddingMode.Zeros;
break;
case 4:
des.Padding = PaddingMode.ANSIX923;
break;
case 5:
des.Padding = PaddingMode.ISO10126;
break;
default:
des.Padding = PaddingMode.Zeros;
break;
}
var _keyByte = Encoding.UTF8.GetBytes(key);
var _valueByte = Encoding.UTF8.GetBytes(entryStr);
des.Key = _keyByte;
using (MemoryStream ms = new MemoryStream())
{
byte[] bytes = _valueByte;
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytes, 0, bytes.Count());
cs.FlushFinalBlock();
}
return System.Text.Encoding.Default.GetString(ms.ToArray());
}
}
///
/// DES 解密
///
/// 待解密加密的字符串
/// 8位16进制密钥字符串
/// 运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)
/// 填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
///
public string Decrypt(string entryStr, string key, int mode, int paddingMode)
{
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
switch (mode)
{
case 1:
des.Mode = CipherMode.CBC;
break;
case 2:
des.Mode = CipherMode.ECB;
break;
case 3:
des.Mode = CipherMode.OFB;
break;
case 4:
des.Mode = CipherMode.CFB;
break;
case 5:
des.Mode = CipherMode.CTS;
break;
default:
des.Mode = CipherMode.ECB;
break;
}
switch (paddingMode)
{
case 1:
des.Padding = PaddingMode.None;
break;
case 2:
des.Padding = PaddingMode.PKCS7;
break;
case 3:
des.Padding = PaddingMode.Zeros;
break;
case 4:
des.Padding = PaddingMode.ANSIX923;
break;
case 5:
des.Padding = PaddingMode.ISO10126;
break;
default:
des.Padding = PaddingMode.Zeros;
break;
}
var _keyByte = Encoding.UTF8.GetBytes(key);
var _valueByte = Encoding.UTF8.GetBytes(entryStr);
des.Key = _keyByte;
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(_valueByte, 0, _valueByte.Count());
cs.FlushFinalBlock();
}
return System.Text.Encoding.Default.GetString(ms.ToArray());
}
}
}
}
MD5加密code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Encryption
{
interface IMD5Encryt
{
string GetMd5Str(string ConvertString);
string UserMd5(string str);
}
class MD5Encryt : IMD5Encryt
{
///
/// MD5 16位加密
///
///
///
public string GetMd5Str(string ConvertString)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);
t2 = t2.Replace("-", "");
return t2;
}
///
/// MD5 32位加密
///
///
///
public string UserMd5(string str)
{
string cl = str;
string pwd = "";
MD5 md5 = MD5.Create();//实例化一个md5对像
// 加密后是一个字节类型的数组,这里要注意编码UTF8/Unicode等的选择
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(cl));
// 通过使用循环,将字节类型的数组转换为字符串,此字符串是常规字符格式化所得
for (int i = 0; i < s.Length; i++)
{
// 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符
pwd = pwd + s[i].ToString("X");
}
return pwd;
}
}
}
(1)Delphi端调用C#的base64加密:
(2)Delphi端调用C#的base64解密:
(1)按照配置生成了,也regasm注册成功了,但是在调用的时候会报错:
原因:虽然说我们用命令行注册时提示成功,但是我们所进入的Framework有问题,如图Microsoft.NET文件夹下面有两个版本的Framework,请选择和自己计算机位数相同的版本,或者说可以逐个尝试一下。
另外:选择regasm所在的目录也要根据vs输出的Framework版本一致,例如我的是4.5,那么需要进入v4.0.30319:
输出的目标框架在属性中可以看到:
感谢您看到了这儿,请收下测试通过的源码(包含Base64/AES/DES的加密解密(可指定运算模式Mode,填充模式Padding,向量V),MD5的加密):
链接:https://pan.baidu.com/s/1CLnwtGOFf0oGzCvyNef0YA 密码:hyuj