C # Dll Импорт Go Dll расхождение строковых значений - CString возвращаемых значений - PullRequest
0 голосов
/ 24 сентября 2019

я написал в Go dll, чтобы расшифровать / зашифровать данные с кодировкой открытого / секретного ключа.

Первая проблема, с которой я столкнулся, - это совместное использование строк между dll и кодом c #.

Я решил это, используя библиотеку C в Go.

func myfunc( password *C.char, passwordLength C.int )  *C.char{
   result = C.GoStringN(password, passwordLength)
   return C.CString(result)
}

Более или менее Нечто подобное.

В C # аналогом является

Marshal.PtrToStringAuto(value);

Моя проблема сейчас в том, что строки не совпадают в go и c #.Одна функция возвращает зашифрованное значение, и когда я регистрирую его с помощью

fmt.println(...)

Это не соответствует возвращаемому значению, которое я регистрирую в c #

Console.writeln(...)

Я пробовал разные функции:

Marshal.PtrToStringAuto(...)
Marshal.PtrToStringAnsi(...)
Marshal.PtrToStringUTF8(...)
Marshal.PtrToStringUni(...)

После использования библиотеки C у меня тоже были проблемы со строками в go.Из-за этого я добавил длину и перешел из C.GoString в C.GoStringN, что помогло при отладке кода в Go.

Я действительно не знаю, что я делаю неправильно.Кто-нибудь знает, что я мог бы попробовать?

Выход Go 1

Выход Go 2

Я решил частьпроблема.Вывод шифрования имеет определенный размер.Так что в Go я теперь могу правильно читать значения.Какие варианты у меня есть в C #, чтобы правильно прочитать значения?Marshal.PtrToStringUTF8, кажется, работает лучше всего из функций Marshal.Но это не равно значению от Go.

Ответы [ 2 ]

0 голосов
/ 25 сентября 2019

Спасибо, что помогли мне.

Ваше решение не сработало для меня, но оно мне очень помогло.

//export EncryptForDb
func EncryptForDb(value *C.char) unsafe.Pointer {
   encodedString := Cipher.PrivatKeyEncryptValue(Cipher.PrivatKey, C.GoString(value))
   return C.CBytes([]byte(encodedString))
}

Я возвращаю небезопасный указатель на результат ByteArray.На стороне C # я сейчас использую этот код.

byte[] ICipherManager.EncryptForDb(string value)
{
    byte[] encryptedBytes = new byte[1024];

    IntPtr pointer = EncryptForDb(value);
    Marshal.Copy(pointer, encryptedBytes, 0, encryptedBytes.Length);

    return encryptedBytes;
}

Когда я использую C.CString, сырое значение нарезается.Строки Go и C # содержат свойство length.Строки CS прекращаются ОЗУ, и я не смог найти решение для чтения или записи всей зашифрованной строки с ним.Поэтому я решил использовать [] байт вместо.

0 голосов
/ 25 сентября 2019

Вот пример с шифрованием AES в go dll;строки для меня совпадают:

Код Go (скомпилирован с CGO_ENABLED=1 GOARCH=386 GOOS=windows go build -buildmode=c-shared -o test.dll AES.go):

package main

import (
    "C"
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "errors"
    "io"
)

var cipherKey = []byte("Zq4t7w!z%C&F)J@N")

func main() {}

//export Encrypt
func Encrypt(cMessage *C.char) *C.char {
    message := C.GoString(cMessage)
    plainText := []byte(message)

    block, err := aes.NewCipher(cipherKey)
    if err != nil {
        panic(err)
    }

    cipherText := make([]byte, aes.BlockSize+len(plainText))
    iv := cipherText[:aes.BlockSize]
    if _, err = io.ReadFull(rand.Reader, iv); err != nil {
        panic(err)
    }

    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(cipherText[aes.BlockSize:], plainText)

    //returns to base64 encoded string
    encmess := base64.URLEncoding.EncodeToString(cipherText)
    return C.CString(encmess)
}

//export Decrypt
func Decrypt(cEncryptedMessage *C.char) *C.char {
    encryptedMessage := C.GoString(cEncryptedMessage)
    cipherText, err := base64.URLEncoding.DecodeString(encryptedMessage)
    if err != nil {
        panic(err)
    }

    block, err := aes.NewCipher(cipherKey)
    if err != nil {
        panic(err)
    }

    if len(cipherText) < aes.BlockSize {
        err = errors.New("Ciphertext block size is too short!")
        panic(err)
    }

    iv := cipherText[:aes.BlockSize]
    cipherText = cipherText[aes.BlockSize:]

    stream := cipher.NewCFBDecrypter(block, iv)
    stream.XORKeyStream(cipherText, cipherText)

    decodedmess := string(cipherText)
    return C.CString(decodedmess)
}

Код C #:

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var encrypted = GoFunctions.Encrypt(System.Text.Encoding.UTF8.GetBytes("hello"));
            var decrypted = GoFunctions.Decrypt(System.Text.Encoding.UTF8.GetBytes(Marshal.PtrToStringAnsi(encrypted)));
            label1.Text = Marshal.PtrToStringAnsi(encrypted);
            label2.Text = Marshal.PtrToStringAnsi(decrypted);
        }

        static class GoFunctions
        {
            [DllImport(@"C:\Repos\Go_AES\test.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
            public static extern IntPtr Encrypt(byte[] message);

            [DllImport(@"C:\Repos\Go_AES\test.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
            public static extern IntPtr Decrypt(byte[] encrypted_message);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...