Skip to content

Commit

Permalink
age: Add scrypt::Recipient::set_work_factor for overriding default
Browse files Browse the repository at this point in the history
This can only be configured by using `scrypt::Recipient` directly in a
library context. The helper method `Encryptor::with_user_passphrase`
does not expose this, and `rage` continues to use the default.

Closes #383.
  • Loading branch information
str4d committed Aug 28, 2024
1 parent 84eacb7 commit e841593
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 6 deletions.
6 changes: 5 additions & 1 deletion age/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,12 @@ mod tests {
fn scrypt_round_trip() {
let test_msg = b"This is a test message. For testing.";

let mut recipient = scrypt::Recipient::new(SecretString::new("passphrase".to_string()));
// Override to something very fast for testing.
recipient.set_work_factor(2);

let mut encrypted = vec![];
let e = Encryptor::with_user_passphrase(SecretString::new("passphrase".to_string()));
let e = Encryptor::with_recipients(vec![Box::new(recipient)]).unwrap();
{
let mut w = e.wrap_output(&mut encrypted).unwrap();
w.write_all(test_msg).unwrap();
Expand Down
29 changes: 24 additions & 5 deletions age/src/scrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,33 @@ fn target_scrypt_work_factor() -> u8 {
/// [`x25519::Identity`]: crate::x25519::Identity
pub struct Recipient {
passphrase: SecretString,
log_n: u8,
}

impl Recipient {
/// Constructs a new `Recipient` with the given passphrase.
///
/// The scrypt work factor is picked to target about 1 second for encryption or
/// decryption on this device. Override it with [`Self::set_work_factor`].
pub fn new(passphrase: SecretString) -> Self {
Self { passphrase }
Self {
passphrase,
log_n: target_scrypt_work_factor(),
}
}

/// Sets the scrypt work factor to `N = 2^log_n`.
///
/// This method must be called before [`Self::wrap_file_key`] to have an effect.
///
/// [`Self::wrap_file_key`]: crate::Recipient::wrap_file_key
///
/// # Panics
///
/// Panics if `log_n == 0` or `log_n >= 64`.
pub fn set_work_factor(&mut self, log_n: u8) {
assert!(0 < log_n && log_n < 64);
self.log_n = log_n;
}
}

Expand All @@ -127,10 +148,8 @@ impl crate::Recipient for Recipient {
inner_salt[..SCRYPT_SALT_LABEL.len()].copy_from_slice(SCRYPT_SALT_LABEL);
inner_salt[SCRYPT_SALT_LABEL.len()..].copy_from_slice(&salt);

let log_n = target_scrypt_work_factor();

let enc_key =
scrypt(&inner_salt, log_n, self.passphrase.expose_secret()).expect("log_n < 64");
scrypt(&inner_salt, self.log_n, self.passphrase.expose_secret()).expect("log_n < 64");
let encrypted_file_key = aead_encrypt(&enc_key, file_key.expose_secret());

let encoded_salt = BASE64_STANDARD_NO_PAD.encode(salt);
Expand All @@ -140,7 +159,7 @@ impl crate::Recipient for Recipient {
Ok((
vec![Stanza {
tag: SCRYPT_RECIPIENT_TAG.to_owned(),
args: vec![encoded_salt, format!("{}", log_n)],
args: vec![encoded_salt, format!("{}", self.log_n)],
body: encrypted_file_key,
}],
iter::once(label).collect(),
Expand Down

0 comments on commit e841593

Please sign in to comment.