Невозможно передать зашифрованный текст из C # в C ++ и наоборот - PullRequest
0 голосов
/ 10 мая 2018

У меня есть c ++ dll, включающий шифрование AES, функция имеет два входа:

  1. строка: для шифрования с AES

  2. строка: вывод шифрования

Вот внешняя функция:

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);

ВОПРОСЫ:

  • Если я установил CharSet в ANSI, строка ввода работает нормально, в c ++ возвращается право Но выходная строка неверно возвращает только один символ!

  • Если я установил для CharSet значение UNICODE, входная строка возвращает неправильный и только один символ. Но выходная строка возвращает прямо!

Где я допустил ошибку? Как я могу это исправить?

1 Ответ

0 голосов
/ 13 мая 2018

std::string и std::wstring нельзя скопировать друг на друга с помощью std::copy и связанных с ними методов, за исключением случаев, когда источник содержит символы ASCII.Это не тот случай, здесь.Несмотря на то, что вы смотрите на ASCII, зашифрованный текст будет в двоичном виде, это не ASCII и не Unicode.

Вы можете скопировать std::wstring в двоичном виде в std::string.Но я думаю, что это вам здесь не поможет, потому что encrypt, похоже, ожидает нулевую строку.

Вместо этого вы можете конвертировать 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 #Приложение получит зашифрованный двоичный файл data, некоторой длины datalen

["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 и пытается вернуть строку с нулевым символом в конце.Но ваша функция шифрования создает двоичные данные, которые могут иметь много нулей в середине.

Вы можете упростить ситуацию, если функция шифрования принимает двоичный ввод и выводит std::vector<BYTE> вместо std::string.Пример

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