利用C++编写AES,MD5 动态链接库程序,导出DLL文件,供C#程序调用

时间:2024-03-26 08:23:27

       在用unity开发过程中,由于客户需要将消息传输的消息体进行加密,由于客户提供了服务器代码,在我们开发过程中,尝试着使用C# 官方MD5, AES加解密算法去对消息进行加密,解密操作。然而我们所得的结果与想要的结果差别很大。所以我们采用了将客户的C++加密解密代码部分进行拆分,修改,生成动态链接库程序,以此在unity中调用。

      由于unity开发过程中使用的是C#,所以在测试程序中我用控制台程序替换了unity程序。

      在我提供的源码文件中包含了两个文件,第一个AES ,这是C++动态链接库程序,里面包含了MD5 ,AES的加解密。代码结构如图:

                                                      利用C++编写AES,MD5 动态链接库程序,导出DLL文件,供C#程序调用

aes.h,aesencryptor.h, aes.cpp,aesencryptor.cpp是AES加解密部分,md5.h,md5.cpp 是MD5加密部分 ,MyDll.h和MyDll.cpp是对加密,解密方法的封装,以便生成dll文件后,方法可以被外部程序访问。

MyDll.h文件有效代码如下:


#pragma once
#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif
#include <string>
extern "C" MATHLIBRARY_API int  Encrypt(char* md5, char* result);
extern "C" MATHLIBRARY_API int GetMD5(char* msg, char* result);
extern "C" MATHLIBRARY_API int Decrypt(char* aes, char* md5);
 

MyDll.cpp文件有效代码如下:

unsigned char key[16] = { 0x40, 0x1e, 0x78, 0x26 };
AesEncryptor l_AES(key);
char returnsmall[1024];
char returnlarge[1024*30];
std::ofstream outfile;

int Encrypt(char* md5, char* result ) {
    std::string temp = std::string(md5);
    std::string AESstr = l_AES.EncryptString(temp);
    //const int len = AESstr.length();
    char* c =const_cast<char*>( AESstr.c_str());
    //strcpy_s(c, len+1,AESstr.c_str());
    int length = strlen(c);

    memset(returnsmall, 0, length);
    memcpy(returnsmall, c, length);
    memcpy(result, returnsmall, length);
    return  length;
}

int   GetMD5(char* msg, char* result)
{
    std::string temp = std::string(msg);
    std::string     str = MD5(temp).toString();
    char* c= const_cast<char*>(str.c_str());
    int Length = strlen(c);
    memset(returnsmall, 0, Length);
    memcpy(returnsmall, c, Length);
    memcpy(result, returnsmall, Length);
    return  Length;
 }
int Decrypt(char* aes, char* md5) {
    std::string temp = std::string(aes);
    std::string str = l_AES.DecryptString(temp);
    char* c = const_cast<char*>(str.c_str());
    int Length = strlen(c);
    memset(returnsmall, 0, Length);
    memcpy(returnsmall, c, Length);
    memcpy(md5, returnsmall, Length);
    return  Length;
}

Encrypt 方法有两个Char * 类型的参数,第一个是需要在C#程序中传输MD5加密后的字符串,第二个参数用于C# 接收AES加密后的字符串,返回值是C#程序判断接收之后的有效长度,GetMD5,Decrypt分别是MD5 加密和AES解密方法,参数与返回值用法和Encrypt 相同。

C# 测试代码程序如下:

using System.Collections;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Runtime.InteropServices;
public class sUserInfo
{
    public string password;
    public string username;//用户名
    public sUserInfo()
    {
        password = "1";
        username = "1";
    }
}
/// <summary>
/// AES加密算法
/// </summary>
public class AESEncryption
{
    [DllImport(@".\DLL\AES.dll", EntryPoint = "Encrypt", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int Encrypt(string str, ref byte res);
    [DllImport(@".\DLL\AES.dll", EntryPoint = "GetMD5", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int GetMD5(string str, ref byte res);
    [DllImport(@".\DLL\AES.dll", EntryPoint = "Decrypt", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int Decrypt(string str, ref byte res);
    public static string AesEncrypt(string str)
    {
        byte[] s = new byte[1024];
        int l = Encrypt(str, ref s[0]);
        byte[] data = null;
        if (l > s.Length) return "";
        else
        {
            data = new byte[l];
            Buffer.BlockCopy(s, 0, data, 0, l);
            string strGet = System.Text.Encoding.Default.GetString(data, 0, data.Length);
            return strGet;
        }
    }

    public static string MD5Encrypt(string str)
    {
        byte[] s = new byte[1024];
        int l = GetMD5(str, ref s[0]);
        byte[] data = null;
        if (l > s.Length) return "";
        else
        {
            data = new byte[l];
            Buffer.BlockCopy(s, 0, data, 0, l);
            string strGet = System.Text.Encoding.Default.GetString(data, 0, data.Length);
            return strGet;
        }
    }
    public static string CreateData(string msg, string encrypt)
    {
        string buffer = "";
        string ms = msg + encrypt;
        int length = ms.Length;
        int cou = 8 - length.ToString().Length;
        for (int i = 0; i < cou; i++)
        {
            buffer += "0";
        }
        buffer += length.ToString() + ms;
        return buffer;
    }
    public static bool DataDecrypt(string msg)
    {
        int a = 0; int index = 0;
        for (int i = msg.Length - 1; i >= 0; i--)
        {
            a++;
            if (a == 96)
            {
                index = i;
                break;
            }
        }
        string aes = ""; string data = "";
        aes = msg.Substring(index);
        data = msg.Substring(0, msg.Length - 96);
        string md5 = MD5Encrypt(data);
        byte[] s = new byte[1024];
        int l = Decrypt(aes, ref s[0]);
        byte[] redata = null; string strGet = "";
        if (l > s.Length) strGet = "";
        else
        {
            redata = new byte[l];
            Buffer.BlockCopy(s, 0, redata, 0, l);
            strGet = System.Text.Encoding.Default.GetString(redata, 0, redata.Length);
        }
        if (md5 == strGet) return true;
        return false;
    }

}

首先需要将使用的方法进行声明:

DllImport(@".\DLL\AES.dll", EntryPoint = "Encrypt", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int Encrypt(string str, ref byte res);
    [DllImport(@".\DLL\AES.dll", EntryPoint = "GetMD5", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int GetMD5(string str, ref byte res);
    [DllImport(@".\DLL\AES.dll", EntryPoint = "Decrypt", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, ExactSpelling = false)]
    public static extern int Decrypt(string str, ref byte res);

具体使用请参照测试程序进行测试。

由于C#的字符串与C++的std::string 的区别,所以在C++方法内的参数是不能用std::string 的参数进行传递。至于接收加密后的字符串,为什么不能直接返回char* 类型数据,本渣渣也不是很清楚,如有大佬知晓欢迎留言,膜拜大佬。在此,我才用的是将地址传输给C++方法,在C++程序方法内将加密后的数据直接拷贝到内存中,然后根据返回值大小(有效数据长度),拷贝内存中有效数据进行转换。

源码请自行下载:https://download.csdn.net/download/qq_37699470/12412348