rage icon indicating copy to clipboard operation
rage copied to clipboard

Performance Issues

Open tengkuizdihar opened this issue 1 year ago • 3 comments

What were you trying to do

Right now I'm trying to create a note taking application. Every note is a row in the database and the contents are encrypted by a password based encryption method.

What happened

It's quite slow, for example encrypting a small struct takes about ~1.5 second. Decryption also has a similar runtime. Is there a way to speed this process up?

Below is the function I used to encrypt data.

pub fn encrypt_data<T: Serialize>(
    data: T,
    secret: &str, // this is user's password
) -> Result<Vec<u8>, CryptoError> {
    let encryptor =
        age::Encryptor::with_user_passphrase(age::secrecy::Secret::new(secret.to_owned()));

    let mut encrypted = vec![];
    let mut writer = encryptor
        .wrap_output(&mut encrypted)
        .map_err(|_| CryptoError::CryptoError)?;

    let writing_start = Instant::now();
    writer
        .write_all(data_serialized.as_slice())
        .map_err(|_| CryptoError::CryptoError)?;

    writer.finish().map_err(|_| CryptoError::CryptoError)?;

    Ok(encrypted)
}

This is the function I used to test how long it take to encrypt it.

fn testEncryption() {
    let user_password = "boogydown5114141";

    #[derive(Serialize, Deserialize)]
    struct TestingData {
        first: String,
        second: String,
    }

    let start = Instant::now();
    let _ = encrypt_data(
        TestingData {
            first: "back in the days in the boulevard".to_string(),
            second: "back in the days in the boulevard".to_string(),
        },
        user_password,
    )
    .unwrap();
    println!("Encryption Duration: {:?}", start.elapsed());
}

Printed: Encryption Duration: 1.841529562s

I'm also aware of https://github.com/str4d/rage/pull/148, seems like it's abandoned for now (?).

Questions

If this is currently unsolvable, forgive me if I'm being rude, but do you have a suggestion about other encryption libraries that could do a passphrase based encryption upon a stream of data? Similar to what with_user_passphrase() offers. I'm also interested in helping this, but I doubt my current understanding of encryption is good enough to help you guys.

tengkuizdihar avatar Jul 05 '23 15:07 tengkuizdihar

The performance problem you are noticing is the cost of running the scrypt PBKDF on the user passphrase, which is automatically set at encryption time to a hardness level of at least 1 second of computation on the current machine (and due to the granularity of the hardness setting could be anywhere between 1 and 2 seconds). This is a security measure used by all password-based encryption mechanisms, and thus you'll likely see the same performance issues with any other library. Additionally, when used this way, the passphrase is run through PBKDF with a unique salt for each encryption (as a defense against security issues related to passphrase reuse), which means the 1-2 seconds of PBKDF cost are paid per row.

[Obligatory "I Am Not Your Cryptographer" disclaimer]

Instead of encrypting every row with the user's passphrase, a more performant approach would be to encrypt every row with a native age key, and encrypt that with the user's passphrase. Then on start, your application could decrypt the native age key into memory, and then use that for on-the-fly encryption and decryption of rows.

str4d avatar Jul 05 '23 17:07 str4d

@str4d is there a way for me to use a "native age key" directly to encrypt a stream of data?

~~I'll maybe try to make the Stream struct public so it can be reusable for as long as my application is opened.~~

tengkuizdihar avatar Jul 07 '23 07:07 tengkuizdihar

Instead of encrypting every row with the user's passphrase, a more performant approach would be to encrypt every row with a native age key, and encrypt that with the user's passphrase.

I think it's currently impossible to do that right now because StreamWriter::finish() consumes itself after it's used.

tengkuizdihar avatar Jul 07 '23 08:07 tengkuizdihar