无法将加密的文本从 C# 传递到 C++ 和相反

Cannot pass encrypted Text from C# to C++ and opposite

我有一个包含 AES 加密的 c++ dll,该函数有两个输入:

  1. 字符串:使用 AES

  2. 加密
  3. string : 加密输出

外部函数如下:

extern "C" __declspec(dllexport) void aes_crypter(const char* string_in , wchar_t* string_out);
void aes_crypter(const char* string_in , wchar_t* string_out)
{
    std::string X_KEY = "abcdefghijklmnopqrstuvwxyz123412";
    std::string X_PSS = "612345601234512";

    //////// convert input text to LPCWSTR
    const wchar_t* inputtext = convertCharArrayToLPCWSTR(string_in);

    //////// convert LPCWSTR to string [const to string result wrong ]
    std::wstring ws(inputtext);   
    std::string str(ws.begin(), ws.end());

    //////// Encrypt
    auto encr = encrypt(str, key, X_PSS);

    //////// Convert and Return to Output String
    std::wstring widestr = std::wstring(encr.begin(), encr.end()); 
    const wchar_t* output_crypt = widestr.c_str(); /// CONVERT STD TO WCHAR
    swprintf(string_out, 4096,output_crypt);

}

代码工作正常,问题出在我的 C# 应用程序中:

这里是导入函数代码:

[DllImport("simpleAES.dll",
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern void aes_crypter(string string_in, StringBuilder string_out);

问题:

我哪里弄错了?我该如何解决?

std::stringstd::wstring 无法使用 std::copy 和相关方法相互复制,除非源包含 ASCII 字符。这里不是这种情况。虽然你用的是 ASCII,但加密的文本将是二进制的,它既不是 ASCII 也不是 Unicode。

您可以将二进制的 std::wstring 复制到 std::string。但我认为这对你没有帮助,因为 encrypt 似乎期望以 null 结尾的字符串。

相反,您可以将 UTF16 转换为 UTF8 并返回:

#include <string>
#include <codecvt>

extern "C" __declspec(dllexport)
bool aes_crypter(const wchar_t* string_in, BYTE* data, int &datalen)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
    std::string utf8 = convert.to_bytes(string_in);

    std::string encr = encrypt(utf8, X_KEY, X_PSS);
    datalen = encr.size();
    if(datalen > 4096)
        return false;

    memcpy(data, &encr[0], datalen);
    return true;
}

extern "C" __declspec(dllexport)
void aes_decrypter(const BYTE *data, int datalen, wchar_t* string_out)
{
    std::string utf8 = decrypt(data, datalen, X_KEY, X_PSS);
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> convert;
    std::wstring utf16 = convert.from_bytes(utf8);
    wcscpy_s(string_out, 4096, utf16.c_str());
}

您的 C# 应用程序将收到长度为 datalen

的加密二进制文件 data
["simpleAES.dll",
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern bool aes_crypter(string input, IntPtr data, ref int datalen);

["simpleAES.dll",
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
private static extern bool aes_decrypter(IntPtr data, int datalen, StringBuilder sb);

static void Main(string[] args)
{
    int datalen = 0;
    IntPtr data = Marshal.AllocHGlobal(4096);
    if (aes_crypter("1234", data, ref datalen))
    {
        StringBuilder sb = new StringBuilder(4096);
        aes_decrypter(data, datalen, sb);
        string recover = sb.ToString();
        Console.WriteLine(recover);
    }
    Marshal.FreeHGlobal(data);
}

您还应该传递 StringBuilder 的大小,而不是假设它是 4096

请注意,在 C++ 中,c_str() 方法将查找 NUL 字符并尝试 return 以 null 结尾的字符串。但是你的加密函数创建的二进制数据中间可能有很多零。

如果加密函数接受二进制输入并输出 std::vector<BYTE> 而不是 std::string,您可以使事情变得更容易。例子

std::vector<BYTE> encrypt(binary_data_to_encrypt, datalen, X_KEY, X_PSS);