AES-GCM 256 decryption fails even with correct data

Viewed 1271

I have a given encrypted message (decrypted, it is "encrypted secret message") and I'm trying to retrieve this original string from the AES-GCM 256 encrypted one. I use the aes-gcm crate to do this:

use aes_gcm::Aes256Gcm;
use aead::{Aead, NewAead, generic_array::GenericArray};

fn main() {
    let key_bytes = hex::decode("ce265dbc38bb25ef29fade77a4b88fe07b6063215f6526a4623cf810a3d611c9").unwrap();
    let nonce_bytes = hex::decode("ce77357fe7b2401400408f44").unwrap();
    let ciphertext_bytes = hex::decode("fd77fae68fa27ea00afbe474f4fcd47248a19b3cbf2a6d7e").unwrap();

    let key = GenericArray::clone_from_slice(key_bytes.as_slice());
    let nonce = GenericArray::from_slice(nonce_bytes.as_slice());

    let cipher = Aes256Gcm::new(key);
    let plaintext = cipher.decrypt(nonce, ciphertext_bytes.as_slice()).unwrap(); // panic on a decryption failure

    println!("{:?}", plaintext);
}

This is the dependencies section of my Cargo.toml:

[dependencies]
aes-gcm = "0.5.0"
aead = "0.2.0"
hex = "0.4.2"

The problem is that the program always panics at the unwrap call on line 13, even though the encrypted message, the key and the nonce are good:

thread 'main' panicked at 'called Result::unwrap() on an Err value: Error', src\main.rs:13:21

It looks like it's an error from the encrypted message being invalid, from the encrypted message, the key or the nonce being invalid, but it's not. I wrote a Python program that does exactly the same thing and it works; the output is indeed encrypted secret message!

from Crypto.Cipher import AES

key = bytes.fromhex("ce265dbc38bb25ef29fade77a4b88fe07b6063215f6526a4623cf810a3d611c9")

nonce = bytes.fromhex("ce77357fe7b2401400408f44")
cipher_text = bytes.fromhex("fd77fae68fa27ea00afbe474f4fcd47248a19b3cbf2a6d7e")

cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
plaintext = cipher.decrypt(cipher_text)

print(plaintext.decode("utf-8"))

I want to be able to decrypt these kind of encrypted messages in Rust, not in Python. I don't know why I get an error at all. Did I miss something?

1 Answers

From encrypt, emphasis mine:

The default implementation assumes a postfix tag (ala AES-GCM, AES-GCM-SIV, ChaCha20Poly1305). Aead implementations which do not use a postfix tag will need to override this to correctly assemble the ciphertext message.

Since you say you have the tag:

I have the associated tag for this encrypted message as well

You can follow the same pattern:

use aead::{generic_array::GenericArray, Aead, NewAead};
use aes_gcm::Aes256Gcm;

fn main() {
    let key_hex = "ce265dbc38bb25ef29fade77a4b88fe07b6063215f6526a4623cf810a3d611c9";
    let nonce_hex = "ce77357fe7b2401400408f44";
    let ciphertext_hex = "fd77fae68fa27ea00afbe474f4fcd47248a19b3cbf2a6d7e";

    // Append the tag data to the encrypted data
    let tag_hex = "2ef2a9d27909df90bcb45606067148a6";
    let ciphertext_and_tag_hex = format!("{}{}", ciphertext_hex, tag_hex);
    let ciphertext_bytes = hex::decode(ciphertext_and_tag_hex).unwrap();

    let key_bytes = hex::decode(key_hex).unwrap();
    let nonce_bytes = hex::decode(nonce_hex).unwrap();

    let key = GenericArray::clone_from_slice(&key_bytes);
    let nonce = GenericArray::from_slice(&nonce_bytes);

    let cipher = Aes256Gcm::new(key);

    let plaintext = cipher.decrypt(nonce, &*ciphertext_bytes).unwrap();
    println!("{}", String::from_utf8_lossy(&plaintext));
}

You can also investigate the decrypt_in_place_detached method, which is more complicated but allows specifying the tag separately.

Related