Delphi调用C#的加密解密(Base64/AES/DES/MD5可扩充)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_41660162/article/details/81773545

1. 背景:

近期,由于工作上与第三方公司传输数据的时候需要采取数据加密,但是我们采用的时较低版本的Delphi 6;由于加密算法等差异,导致在传输的加密数据第三方一致解析不了(具体问题表现为base64加密中文乱码,AES加密方式的运算模式Mode,填充模式padding);限于代码的管理规范不能使用加密的插件,且网上搜索相关的delphi加密资料少之又少;故决定采取Visual Studio来写加密解密算法的动态库,由Delphi调用。

2. 行动:

(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文件:
bat文件方式
CMD命令行方式
(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
    {
        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="value">待加密的字符串</param>
        /// <param name="key">秘钥(16,24,32位)</param>
        /// <param name="mode">运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)</param>
        /// <param name="paddingMode">填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
        /// <param name="iv">初始化向量(至少16位)</param>
        /// <returns>加密后的字符串</returns>
        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);
            }
        }
        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="value">待解密的字符串</param>
        /// <param name="key">秘钥(16,24,32位)</param>
        /// <param name="mode">运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)</param>
        /// <param name="paddingMode">填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
        /// <param name="iv">初始化向量(至少16位)</param>
        /// <returns>解密后的字符串</returns>
        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
    {
        /// <summary>
        /// DES 加密
        /// </summary>
        /// <param name="entryStr">待加密字符串</param>
        /// <param name="key">8位16进制密钥字符串</param>
        /// <param name="mode">运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)</param>
        /// <param name="paddingMode">填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
        /// <returns></returns>
        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()); 
            }
        }
        /// <summary>
        /// DES 解密 
        /// </summary>
        /// <param name="bytes">待解密加密的字符串</param>
        /// <param name="key">8位16进制密钥字符串</param>
         /// <param name="mode">运算模式(CBC = 1,ECB = 2,OFB = 3,CFB = 4,CTS = 5)</param>
        /// <param name="paddingMode">填充模式(None = 1,PKCS7 = 2,Zeros = 3,ANSIX923 = 4,ISO10126 = 5)
        /// <returns></returns>
        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
    {
        /// <summary>
        /// MD5 16位加密
        /// </summary>
        /// <param name="ConvertString"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// MD5 32位加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        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;
        }
    }
}

3. 测试:

(1)Delphi端调用C#的base64加密:
这里写图片描述
(2)Delphi端调用C#的base64解密:
这里写图片描述

4.报错与解决

(1)按照配置生成了,也regasm注册成功了,但是在调用的时候会报错:
这里写图片描述
原因:虽然说我们用命令行注册时提示成功,但是我们所进入的Framework有问题,如图Microsoft.NET文件夹下面有两个版本的Framework,请选择和自己计算机位数相同的版本,或者说可以逐个尝试一下。
这里写图片描述
另外:选择regasm所在的目录也要根据vs输出的Framework版本一致,例如我的是4.5,那么需要进入v4.0.30319:
这里写图片描述
输出的目标框架在属性中可以看到:
这里写图片描述

5.感谢:

感谢您看到了这儿,请收下测试通过的源码(包含Base64/AES/DES的加密解密(可指定运算模式Mode,填充模式Padding,向量V),MD5的加密):
链接:https://pan.baidu.com/s/1CLnwtGOFf0oGzCvyNef0YA 密码:hyuj

猜你喜欢

转载自blog.csdn.net/weixin_41660162/article/details/81773545