rustopenpgp

What's wrong with my Rust, sequoia_openpgp code that it generates different outputs each time?


Any idea why the following code is generating different value each time? Shouldn't the output be the same given same message and same password?

Also any idea what can I do to make it faster? It takes about half a second in release mode. The JavaScript equivalent using OpenPGP.js is much faster.

use base64::{engine::general_purpose, Engine as _};
use sequoia_openpgp::serialize::stream::{Encryptor, LiteralWriter, Message};
use std::io::Write;

pub fn main() {
    let mut sink = vec![];
    let message = Encryptor::with_passwords(Message::new(&mut sink), Some("password"))
        .build()
        .unwrap();
    let mut w = LiteralWriter::new(message).build().unwrap();
    let _ = w.write_all(b"Hello world.");
    let _ = w.finalize();
    let b64 = general_purpose::STANDARD.encode(sink);

    println!("{}", b64);
}

Solution

  • It's expected that the data is different every time. OpenPGP symmetric encryption generates a new key and initialization vector every time it encrypts, and then encrypts the symmetric key used for that encryption with a symmetric key generated from the password.

    This allows one to use both one or more passwords and one or more OpenPGP keys to encrypt the same data, since the symmetric key for the data is simply encrypted by each of the other keys (the OpenPGP asymmetric ones and the ones generated from the passwords).

    In general, secure symmetric cryptography uses a random IV each time because it randomizes the encryption and therefore prevents attackers from determining if the same message is encrypted multiple times. An attacker who saw the same message encrypted multiple times might be able to guess as to its contents or otherwise perform some sort of correlation. Also, in many cases, reusing the same key and IV catastrophically weakens the system.

    There are symmetric encryption modes such as AES-SIV that are secure when used with the same key and IV, and in that case, produces a deterministic result. There are some cases where that is desirable or required, but in general, since it allows the correlation attacks above, it's not recommended. OpenPGP doesn't offer those modes at all, so if you absolutely need that, you'll need to choose a different way to encrypt.