英文:
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#中进行解密的逻辑,可以在以下链接中找到:
-
https://dotnetfiddle.net/32sb5m 这个示例使用了System.Security.Cryptography命名空间,但结果出现了IV大小错误。
-
https://dotnetfiddle.net/WxKUYR 上述示例的修改版本用于.NET 5,产生了相同的结果。
-
https://dotnetfiddle.net/6IfTps 使用Bouncy Castle库会出现“mac check in GCM failed”错误。
-
https://dotnetfiddle.net/8mJS3G 另一种使用Rfc2898DeriveBytes方法的方法会产生错误,提示“计算的身份验证标记与输入的身份验证标记不匹配”。
当前使用的方法是否正确?还是有其他方法可以在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 = "a6c0952b78967559-2953e738b9b005028bf4f6c0-7b8464d1ed75bc38b4503f6c8d25d6bfc22a19cc1a8a92bc6faa1ed6cd837b97072bc8e16fd95b6cfca67fccbad8fc";
// This is the passphrase that you provided
string passphrase = "this-is-a-test-passphrase";
string[] splitStrs = encryptedString.Split('-');
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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论