在C#中解密使用AES-GSM方法编码的GO字符串。

huangapple go评论87阅读模式
英文:

Decrypting a string in C# that was encoded in GO using the AES-GSM method

问题

我有一个在Go中使用AES-GCM加密的字符串,同时还有它的密码短语,并尝试在C#中解密它。然而,我无法找到正确的方法在C#中解密相同的字符串。

我得到的错误提到了IV的大小,块长度不适合C#解密算法。以下是来自Go的值:

AES加密/解密密码短语:this-is-a-test-passphrase

输入字符串:text to encrypt hello world 123

加密字符串:94b681ef29d9a6d7-e6fa36c4c00977de1745fc63-a1ad0481bdbeeaa02c013a2dce82520ddd762355e18f1e2f20c0ea9d001ece24e9b8216ed4b9c6a06e1ef34c953f80

这是Go中的解密代码:

func AppDecryptImpl(passphrase, ciphertext string) string {
    arr := strings.Split(ciphertext, "-")
    salt, _ := hex.DecodeString(arr[0])
    iv, _ := hex.DecodeString(arr[1])
    data, _ := hex.DecodeString(arr[2])
    key, _ := appDeriveKey(passphrase, salt)
    b, _ := aes.NewCipher(key)
    aesgcm, _ := cipher.NewGCM(b)
    data, _ = aesgcm.Open(nil, iv, data, nil)
    return string(data)
}

func appDeriveKey(passphrase string, salt []byte) ([]byte, []byte) {
    if salt == nil {
        salt = make([]byte, 8)
        rand.Read(salt)
    }
    return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), salt
}

这是Go中的加密代码:

func AppEncryptImpl(passphrase string, plaintext string) string {
    key, salt := appDeriveKey(passphrase, nil)
    iv := make([]byte, 12)
    rand.Read(iv)
    b, _ := aes.NewCipher(key)
    aesgcm, _ := cipher.NewGCM(b)
    data := aesgcm.Seal(nil, iv, []byte(plaintext), nil)
    return hex.EncodeToString(salt) + "-" + hex.EncodeToString(iv) + "-" + hex.EncodeToString(data)
}

我正在尝试在C#中复制相同的解密逻辑,以便能够解密并生成最终字符串。

我尝试了几种在C#中进行解密的逻辑,可以在以下链接中找到:

当前使用的方法是否正确?还是有其他方法可以在C#中解密AES-GCM?在C#中如何绕过这些错误?

英文:

I've got a string that was AES-GCM encrypted in Go, along with it's pass phrase and am trying to decrypt it in C#. However, I'm unable to find the right methods to decrypt the same in C#.
The errors I'm getting mentions the size of the IV, block not being the right lengths for the C# decryption algorithm. Below are the values from Go:

> AES encr/decr Passphrase: this-is-a-test-passphrase

> Input String: text to encrypt hello world 123

> Encrypted String: 94b681ef29d9a6d7-e6fa36c4c00977de1745fc63-a1ad0481bdbeeaa02c013a2dce82520ddd762355e18f1e2f20c0ea9d001ece24e9b8216ed4b9c6a06e1ef34c953f80

GO code: https://go.dev/play/p/jN8Ie61Ntzw

This is the decryption code in Go

func AppDecryptImpl(passphrase, ciphertext string) string {
arr := strings.Split(ciphertext, "-")
salt, _ := hex.DecodeString(arr[0])
iv, _ := hex.DecodeString(arr[1])
data, _ := hex.DecodeString(arr[2])
key, _ := appDeriveKey(passphrase, salt)
b, _ := aes.NewCipher(key)
aesgcm, _ := cipher.NewGCM(b)
data, _ = aesgcm.Open(nil, iv, data, nil)
return string(data)
}

func appDeriveKey(passphrase string, salt []byte) ([]byte, []byte) {
if salt == nil {
	salt = make([]byte, 8)
	rand.Read(salt)
}
return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), salt
}

And this is the encryption code in Go

func AppEncryptImpl(passphrase string, plaintext string) string {
key, salt := appDeriveKey(passphrase, nil)
iv := make([]byte, 12)
rand.Read(iv)
b, _ := aes.NewCipher(key)
aesgcm, _ := cipher.NewGCM(b)
data := aesgcm.Seal(nil, iv, []byte(plaintext), nil)
return hex.EncodeToString(salt) + "-" + hex.EncodeToString(iv) + "-" + hex.EncodeToString(data)
}

I'm trying to replicate the same decryption login in C#, so it'll be able to decrypt and produce the final string.

I've tried several logic when it comes to decryption in C#, they can be found here:

  • <https://dotnetfiddle.net/32sb5m> This one uses the System.Security.Cryptography namespace, but it results in an IV size error.

  • <https://dotnetfiddle.net/WxKUYR> A modified version of the above for .NET 5 produces the same result

  • <https://dotnetfiddle.net/6IfTps> Using the bouncy castle library results in an "mac check in GCM failed" error

  • <https://dotnetfiddle.net/8mJS3G> Another method using the Rfc2898DeriveBytes method produces an error saying "The computed authentication tag did not match the input authentication tag"

Is the approach that's currently being used the right approach or is there another method to decrypt AES-GCM it in C#? And what can be done to bypass these errors when it comes to C#?

答案1

得分: 2

你离上次的代码很接近了。Go将认证标签附加到生成的密文的末尾。你在这里正确地提取了它:

// 从加密的字节数组中提取标签
byte[] tag = new byte[16];
Array.Copy(encryptedData, encryptedData.Length - 16, tag, 0, 16);

但是然后你继续将包含实际加密文本和认证标签的数组视为仅包含加密文本。为了修复这个问题,也要提取它:

public static void Main() {
    // 这是你提供的加密字符串
    string encryptedString = "a6c0952b78967559-2953e738b9b005028bf4f6c0-7b8464d1ed75bc38b4503f6c8d25d6bfc22a19cc1a8a92bc6faa1ed6cd837b97072bc8e16fd95b6cfca67fccbad8fc";

    // 这是你提供的密码短语
    string passphrase = "this-is-a-test-passphrase";

    string[] splitStrs = encryptedString.Split('-');

    byte[] salt = Convert.FromHexString(splitStrs[0]);
    byte[] iv = Convert.FromHexString(splitStrs[1]);
    // 这是加密数据+标签
    byte[] encryptedDataWithTag = Convert.FromHexString(splitStrs[2]);
    // 从加密的字节数组中提取标签
    byte[] tag = new byte[16];
    // 但也要提取实际的加密数据
    byte[] encryptedData = new byte[encryptedDataWithTag.Length - 16];
    Array.Copy(encryptedDataWithTag, 0, encryptedData, 0, encryptedData.Length);
    Array.Copy(encryptedDataWithTag, encryptedDataWithTag.Length - 16, tag, 0, 16);
    byte[] key = new Rfc2898DeriveBytes(passphrase, salt, 1000, HashAlgorithmName.SHA256).GetBytes(32);
    // 创建一个AesGcm对象
    AesGcm aesGcm = new AesGcm(key);
    int textLength = encryptedData.Length;
    // 解密密文
    byte[] plaintext = new byte[textLength];
    aesGcm.Decrypt(iv, encryptedData, tag, plaintext);
    // 将明文转换为字符串并打印出来
    string decryptedString = Encoding.UTF8.GetString(plaintext);
    Console.WriteLine(decryptedString);
}
英文:

You are close with the last code. Go appends authentication tag to the end of produced ciphertext. And you correctly extract it here:

// Extract the tag from the encrypted byte array
byte[] tag = new byte[16];
Array.Copy(encryptedData, encryptedData.Length - 16, tag, 0, 16);

But then you continue to treat array with actual encrypted text + auth tag as if it contained only encrypted text. To fix, extract it also:

public static void Main() {
    // This is the encrypted string that you provided
    string encryptedString = &quot;a6c0952b78967559-2953e738b9b005028bf4f6c0-7b8464d1ed75bc38b4503f6c8d25d6bfc22a19cc1a8a92bc6faa1ed6cd837b97072bc8e16fd95b6cfca67fccbad8fc&quot;;

    // This is the passphrase that you provided
    string passphrase = &quot;this-is-a-test-passphrase&quot;;

    string[] splitStrs = encryptedString.Split(&#39;-&#39;);

    byte[] salt = Convert.FromHexString(splitStrs[0]);
    byte[] iv = Convert.FromHexString(splitStrs[1]);
    // this is encrypted data + tag
    byte[] encryptedDataWithTag = Convert.FromHexString(splitStrs[2]);
    // Extract the tag from the encrypted byte array
    byte[] tag = new byte[16];
    // But also extract actual encrypted data
    byte[] encryptedData = new byte[encryptedDataWithTag.Length - 16];
    Array.Copy(encryptedDataWithTag, 0, encryptedData, 0, encryptedData.Length);
    Array.Copy(encryptedDataWithTag, encryptedDataWithTag.Length - 16, tag, 0, 16);
    byte[] key = new Rfc2898DeriveBytes(passphrase, salt, 1000, HashAlgorithmName.SHA256).GetBytes(32);
    // Create an AesGcm object
    AesGcm aesGcm = new AesGcm(key);
    int textLength = encryptedData.Length;
    // Decrypt the ciphertext
    byte[] plaintext = new byte[textLength];
    aesGcm.Decrypt(iv, encryptedData, tag, plaintext);
    // Convert the plaintext to a string and print it
    string decryptedString = Encoding.UTF8.GetString(plaintext);
    Console.WriteLine(decryptedString);
}

huangapple
  • 本文由 发表于 2023年1月10日 15:20:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75066668.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定