C# Dll 导入 Go Dll 字符串值差异 - CString 返回值



我在Go a dll中写了一个dll,用公钥/私钥编码解密/加密数据。

我遇到的第一个问题是在 dll 和 c# 代码之间共享字符串。

我通过使用 Go 中的 C 库解决了这个问题。

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 代码时有所帮助。

我真的不知道我做错了什么。有人知道我可以尝试什么吗?

输出去 1

输出去 2

我解决了一部分问题。加密的输出具有定义的大小。所以在 Go 中,我现在能够正确读取值。 在 C# 中有哪些选项可以正确读取值? Marshal.PtrToStringUTF8 似乎在 Marshal 函数中效果最好。但它不等于 Go 的值。

下面是一个在 go dll 中进行 AES 加密的示例;字符串对我来说是匹配的:

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:ReposGo_AEStest.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Encrypt(byte[] message);
[DllImport(@"C:ReposGo_AEStest.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Decrypt(byte[] encrypted_message);
}
}
}

谢谢你帮助我。

您的解决方案对我不起作用,但它对我有很大帮助。

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

我返回了一个指向结果字节数组的不安全指针。在 C# 端,我现在使用此代码。

byte[] ICipherManager.EncryptForDb(string value)
{
byte[] encryptedBytes = new byte[1024];
IntPtr pointer = EncryptForDb(value);
Marshal.Copy(pointer, encryptedBytes, 0, encryptedBytes.Length);
return encryptedBytes;
}

当 im 使用 C.CString 时,原始值被切片。 Go 和 C# 字符串确实包含长度属性。CStrings 由 ram 终止,我找不到使用它读取或写入整个加密字符串的解决方案。所以我决定改用 []byte。

最新更新