Skip to content

Commit

Permalink
age: impl From<[u8; 16]> and ExposeSecret<[u8; 16]> for FileKey
Browse files Browse the repository at this point in the history
External crates will need to be able to create FileKeys in order to
implement the Identity trait, and will need to be able to to read them
in order to implement the future Recipient trait.
  • Loading branch information
str4d committed Jul 12, 2020
1 parent ce13b2a commit b7adcca
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 43 deletions.
13 changes: 7 additions & 6 deletions age/src/format/scrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use age_core::{
primitives::{aead_decrypt, aead_encrypt},
};
use rand::{rngs::OsRng, RngCore};
use secrecy::{ExposeSecret, Secret, SecretString};
use secrecy::{ExposeSecret, SecretString};
use std::convert::TryInto;
use std::time::Duration;
use zeroize::Zeroize;

use crate::{error::Error, keys::FileKey, primitives::scrypt, util::read::base64_arg};

Expand Down Expand Up @@ -91,7 +92,7 @@ impl RecipientStanza {
let enc_key = scrypt(&inner_salt, log_n, passphrase.expose_secret()).expect("log_n < 64");
let encrypted_file_key = {
let mut key = [0; ENCRYPTED_FILE_KEY_BYTES];
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.0.expose_secret()));
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.expose_secret()));
key
};

Expand Down Expand Up @@ -128,11 +129,11 @@ impl RecipientStanza {
}
})?;
aead_decrypt(&enc_key, &self.encrypted_file_key)
.map(|pt| {
.map(|mut pt| {
// It's ours!
let mut file_key = [0; 16];
file_key.copy_from_slice(&pt);
Some(FileKey(Secret::new(file_key)))
let file_key: [u8; 16] = pt[..].try_into().unwrap();
pt.zeroize();
Some(file_key.into())
})
.map_err(Error::from)
}
Expand Down
13 changes: 7 additions & 6 deletions age/src/format/ssh_ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use age_core::{
};
use curve25519_dalek::edwards::EdwardsPoint;
use rand::rngs::OsRng;
use secrecy::{ExposeSecret, Secret};
use secrecy::ExposeSecret;
use sha2::{Digest, Sha256, Sha512};
use std::convert::TryInto;
use x25519_dalek::{EphemeralSecret, PublicKey, StaticSecret};
use zeroize::Zeroize;

use crate::{
error::Error, format::x25519::ENCRYPTED_FILE_KEY_BYTES, keys::FileKey, util::read::base64_arg,
Expand Down Expand Up @@ -74,7 +75,7 @@ impl RecipientStanza {
);
let encrypted_file_key = {
let mut key = [0; ENCRYPTED_FILE_KEY_BYTES];
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.0.expose_secret()));
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.expose_secret()));
key
};

Expand Down Expand Up @@ -124,11 +125,11 @@ impl RecipientStanza {
Some(
aead_decrypt(&enc_key, &self.rest.encrypted_file_key)
.map_err(Error::from)
.map(|pt| {
.map(|mut pt| {
// It's ours!
let mut file_key = [0; 16];
file_key.copy_from_slice(&pt);
FileKey(Secret::new(file_key))
let file_key: [u8; 16] = pt[..].try_into().unwrap();
pt.zeroize();
file_key.into()
}),
)
}
Expand Down
14 changes: 8 additions & 6 deletions age/src/format/ssh_rsa.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use age_core::format::AgeStanza;
use rand::rngs::OsRng;
use rsa::{padding::PaddingScheme, PublicKey, RSAPrivateKey, RSAPublicKey};
use secrecy::{ExposeSecret, Secret};
use secrecy::ExposeSecret;
use sha2::{Digest, Sha256};
use std::convert::TryInto;
use zeroize::Zeroize;

use crate::{error::Error, keys::FileKey, util::read::base64_arg};

Expand Down Expand Up @@ -45,7 +47,7 @@ impl RecipientStanza {
.encrypt(
&mut rng,
PaddingScheme::new_oaep_with_label::<Sha256, _>(SSH_RSA_OAEP_LABEL),
file_key.0.expose_secret(),
file_key.expose_secret(),
)
.expect("pubkey is valid and file key is not too long");

Expand Down Expand Up @@ -75,11 +77,11 @@ impl RecipientStanza {
&self.encrypted_file_key,
)
.map_err(Error::from)
.map(|pt| {
.map(|mut pt| {
// It's ours!
let mut file_key = [0; 16];
file_key.copy_from_slice(&pt);
FileKey(Secret::new(file_key))
let file_key: [u8; 16] = pt[..].try_into().unwrap();
pt.zeroize();
file_key.into()
}),
)
}
Expand Down
20 changes: 10 additions & 10 deletions age/src/format/x25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use age_core::{
primitives::{aead_decrypt, aead_encrypt, hkdf},
};
use rand::rngs::OsRng;
use secrecy::{ExposeSecret, Secret};
use secrecy::ExposeSecret;
use std::convert::TryInto;
use x25519_dalek::{EphemeralSecret, PublicKey, StaticSecret};
use zeroize::Zeroize;

use crate::{error::Error, keys::FileKey, util::read::base64_arg};

Expand Down Expand Up @@ -48,7 +49,7 @@ impl RecipientStanza {
let enc_key = hkdf(&salt, X25519_RECIPIENT_KEY_LABEL, shared_secret.as_bytes());
let encrypted_file_key = {
let mut key = [0; ENCRYPTED_FILE_KEY_BYTES];
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.0.expose_secret()));
key.copy_from_slice(&aead_encrypt(&enc_key, file_key.expose_secret()));
key
};

Expand All @@ -70,11 +71,11 @@ impl RecipientStanza {

aead_decrypt(&enc_key, &self.encrypted_file_key)
.map_err(Error::from)
.map(|pt| {
.map(|mut pt| {
// It's ours!
let mut file_key = [0; 16];
file_key.copy_from_slice(&pt);
FileKey(Secret::new(file_key))
let file_key: [u8; 16] = pt[..].try_into().unwrap();
pt.zeroize();
file_key.into()
})
}
}
Expand Down Expand Up @@ -102,19 +103,18 @@ pub(super) mod write {
mod tests {
use quickcheck::TestResult;
use quickcheck_macros::quickcheck;
use secrecy::{ExposeSecret, Secret};
use secrecy::ExposeSecret;
use x25519_dalek::{PublicKey, StaticSecret};

use super::RecipientStanza;
use crate::keys::FileKey;

#[quickcheck]
fn wrap_and_unwrap(sk_bytes: Vec<u8>) -> TestResult {
if sk_bytes.len() > 32 {
return TestResult::discard();
}

let file_key = FileKey(Secret::new([7; 16]));
let file_key = [7; 16].into();
let sk = {
let mut tmp = [0; 32];
tmp[..sk_bytes.len()].copy_from_slice(&sk_bytes);
Expand All @@ -125,7 +125,7 @@ mod tests {
let res = stanza.unwrap_file_key(&sk);

TestResult::from_bool(
res.is_ok() && res.unwrap().0.expose_secret() == file_key.0.expose_secret(),
res.is_ok() && res.unwrap().expose_secret() == file_key.expose_secret(),
)
}
}
16 changes: 14 additions & 2 deletions age/src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,25 @@ fn parse_bech32(s: &str, expected_hrp: &str) -> Option<Result<[u8; 32], &'static
}

/// A file key for encrypting or decrypting an age file.
pub struct FileKey(pub(crate) Secret<[u8; 16]>);
pub struct FileKey(Secret<[u8; 16]>);

impl From<[u8; 16]> for FileKey {
fn from(file_key: [u8; 16]) -> Self {
FileKey(Secret::new(file_key))
}
}

impl ExposeSecret<[u8; 16]> for FileKey {
fn expose_secret(&self) -> &[u8; 16] {
self.0.expose_secret()
}
}

impl FileKey {
pub(crate) fn generate() -> Self {
let mut file_key = [0; 16];
OsRng.fill_bytes(&mut file_key);
FileKey(Secret::new(file_key))
file_key.into()
}

pub(crate) fn mac_key(&self) -> HmacKey {
Expand Down
23 changes: 10 additions & 13 deletions age/src/ssh/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,16 +281,13 @@ pub(crate) fn ssh_identity(input: &str) -> IResult<&str, Identity> {

#[cfg(test)]
pub(crate) mod tests {
use secrecy::{ExposeSecret, Secret};
use secrecy::ExposeSecret;
use std::io::BufReader;

use super::Identity;
use crate::{
keys::FileKey,
ssh::recipient::{
tests::{TEST_SSH_ED25519_PK, TEST_SSH_RSA_PK},
Recipient,
},
use crate::ssh::recipient::{
tests::{TEST_SSH_ED25519_PK, TEST_SSH_RSA_PK},
Recipient,
};

pub(crate) const TEST_SSH_RSA_SK: &str = "-----BEGIN RSA PRIVATE KEY-----
Expand Down Expand Up @@ -339,13 +336,13 @@ AAAEADBJvjZT8X6JRJI8xVq/1aU8nMVgOtVnmdwqWwrSlXG3sKLqeplhpW+uObz5dvMgjz
};
let pk: Recipient = TEST_SSH_RSA_PK.parse().unwrap();

let file_key = FileKey(Secret::new([12; 16]));
let file_key = [12; 16].into();

let wrapped = pk.wrap_file_key(&file_key);
let unwrapped = sk.unwrap_file_key(&wrapped);
assert_eq!(
unwrapped.unwrap().unwrap().0.expose_secret(),
file_key.0.expose_secret()
unwrapped.unwrap().unwrap().expose_secret(),
file_key.expose_secret()
);
}

Expand All @@ -359,13 +356,13 @@ AAAEADBJvjZT8X6JRJI8xVq/1aU8nMVgOtVnmdwqWwrSlXG3sKLqeplhpW+uObz5dvMgjz
};
let pk: Recipient = TEST_SSH_ED25519_PK.parse().unwrap();

let file_key = FileKey(Secret::new([12; 16]));
let file_key = [12; 16].into();

let wrapped = pk.wrap_file_key(&file_key);
let unwrapped = sk.unwrap_file_key(&wrapped);
assert_eq!(
unwrapped.unwrap().unwrap().0.expose_secret(),
file_key.0.expose_secret()
unwrapped.unwrap().unwrap().expose_secret(),
file_key.expose_secret()
);
}
}

0 comments on commit b7adcca

Please sign in to comment.