Skip to content

Commit

Permalink
Merge pull request #520 from str4d/383-scrypt-enc-work-factor
Browse files Browse the repository at this point in the history
age: Add `scrypt::Recipient::set_work_factor` for overriding default
  • Loading branch information
str4d authored Aug 28, 2024
2 parents 84eacb7 + 67a5397 commit b179b7c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 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
35 changes: 27 additions & 8 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 Expand Up @@ -177,13 +196,13 @@ impl Identity {
}
}

/// Sets the maximum accepted scrypt work factor to `2^max_work_factor`.
/// Sets the maximum accepted scrypt work factor to `N = 2^max_log_n`.
///
/// This method must be called before [`Self::unwrap_stanza`] to have an effect.
///
/// [`Self::unwrap_stanza`]: crate::Identity::unwrap_stanza
pub fn set_max_work_factor(&mut self, max_work_factor: u8) {
self.max_work_factor = max_work_factor;
pub fn set_max_work_factor(&mut self, max_log_n: u8) {
self.max_work_factor = max_log_n;
}
}

Expand Down

0 comments on commit b179b7c

Please sign in to comment.