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

Time:01-12

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:

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#?

CodePudding user response:

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);
}
  • Related