diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-09-28 14:53:08 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-09-28 14:53:08 +0200 |
commit | 17bbe07459ff0affbc9482ab432d51dd0cb91e7b (patch) | |
tree | 4c38b9a5b29267a3a7668e1d226374f895fa03c6 | |
parent | 67a874462b716c9af52a64946a22f7456b4e1bd6 (diff) |
openpgp: Add and use a type holding session keys.
-rw-r--r-- | ffi/src/openpgp.rs | 3 | ||||
-rw-r--r-- | openpgp/examples/decrypt-with.rs | 2 | ||||
-rw-r--r-- | openpgp/src/autocrypt.rs | 2 | ||||
-rw-r--r-- | openpgp/src/key.rs | 3 | ||||
-rw-r--r-- | openpgp/src/lib.rs | 46 | ||||
-rw-r--r-- | openpgp/src/message/mod.rs | 3 | ||||
-rw-r--r-- | openpgp/src/parse/parse.rs | 15 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 7 | ||||
-rw-r--r-- | openpgp/src/pkesk.rs | 11 | ||||
-rw-r--r-- | openpgp/src/s2k.rs | 5 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 8 | ||||
-rw-r--r-- | openpgp/src/skesk.rs | 16 |
12 files changed, 88 insertions, 33 deletions
diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs index f17f9db7..a5fe6d46 100644 --- a/ffi/src/openpgp.rs +++ b/ffi/src/openpgp.rs @@ -1467,7 +1467,8 @@ pub extern "system" fn sq_packet_parser_decrypt<'a> let key = unsafe { slice::from_raw_parts(key, key_len as usize) }; - fry_status!(ctx, pp.decrypt((algo as u8).into(), key)) + let key = key.to_owned().into(); + fry_status!(ctx, pp.decrypt((algo as u8).into(), &key)) } diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs index 695bf7af..a8b48d9b 100644 --- a/openpgp/examples/decrypt-with.rs +++ b/openpgp/examples/decrypt-with.rs @@ -69,7 +69,7 @@ pub fn main() { tsk.secret() { if let Ok((algo, key)) = pkesk.decrypt(tsk, mpis) { - let r = pp.decrypt(algo, &key[..]); + let r = pp.decrypt(algo, &key); if r.is_ok() { state = Some(State::Deciphered); break; diff --git a/openpgp/src/autocrypt.rs b/openpgp/src/autocrypt.rs index d98d1159..4aed6934 100644 --- a/openpgp/src/autocrypt.rs +++ b/openpgp/src/autocrypt.rs @@ -568,7 +568,7 @@ impl<'a> AutocryptSetupMessageParser<'a> { } let (algo, key) = self.skesk.decrypt(passcode)?; - self.pp.decrypt(algo, &key[..])?; + self.pp.decrypt(algo, &key)?; self.passcode = Some(passcode.into()); diff --git a/openpgp/src/key.rs b/openpgp/src/key.rs index bcd1aa56..2fb69029 100644 --- a/openpgp/src/key.rs +++ b/openpgp/src/key.rs @@ -260,8 +260,7 @@ impl SecretKey { Err(Error::InvalidOperation("Key is not encrypted".into()) .into()), &SecretKey::Encrypted { ref s2k, algorithm, ref ciphertext } => { - let key = s2k.derive_key(password, algorithm.key_size()?)? - .into_boxed_slice(); + let key = s2k.derive_key(password, algorithm.key_size()?)?; let mut cur = Cursor::new(ciphertext); let mut dec = Decryptor::new(algorithm, &key, cur)?; let mut trash = vec![0u8; algorithm.block_size()?]; diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs index 690827cc..8cf34296 100644 --- a/openpgp/src/lib.rs +++ b/openpgp/src/lib.rs @@ -509,6 +509,52 @@ pub enum RevocationStatus<'a> { NotAsFarAsWeKnow, } +use std::ops::Deref; +use nettle::random::Yarrow; + +/// Holds a session key. +/// +/// The session key is cleared when dropped. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SessionKey(Box<[u8]>); + +impl SessionKey { + /// Creates a new session key. + pub fn new(rng: &mut Yarrow, size: usize) -> Self { + let mut sk = vec![0; size]; + rng.random(&mut sk); + sk.into() + } +} + +impl Deref for SessionKey { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From<Vec<u8>> for SessionKey { + fn from(v: Vec<u8>) -> Self { + SessionKey(v.into_boxed_slice()) + } +} + +impl From<Box<[u8]>> for SessionKey { + fn from(v: Box<[u8]>) -> Self { + SessionKey(v) + } +} + +impl Drop for SessionKey { + fn drop(&mut self) { + unsafe { + memsec::memzero(self.0.as_mut_ptr(), self.0.len()); + } + } +} + use std::io::Read; use nettle::Hash; diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs index 8cad0789..572a812e 100644 --- a/openpgp/src/message/mod.rs +++ b/openpgp/src/message/mod.rs @@ -889,9 +889,10 @@ mod tests { // 0: SK-ESK // => bad. let mut packets : Vec<Packet> = Vec::new(); + let sk = ::SessionKey::new(&mut Default::default(), 8); packets.push(SKESK::new(SymmetricAlgorithm::AES256, S2K::Simple { hash: HashAlgorithm::SHA256 }, - &b"12345678"[..], + &sk, &b"12345678"[..]).unwrap().to_packet()); let message = Message::from_packets(packets.clone()); assert!(message.is_err(), "{:?}", message); diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs index c632d1dc..a8029e9c 100644 --- a/openpgp/src/parse/parse.rs +++ b/openpgp/src/parse/parse.rs @@ -37,6 +37,7 @@ use { Packet, KeyID, SecretKey, + SessionKey, packet::PKESK, }; use constants::{ @@ -3014,7 +3015,7 @@ impl<'a> PacketParser<'a> { /// If this function is called on a packet that does not contain /// encrypted data, or some of the data was already read, then it /// returns `Error::InvalidOperation`. - pub fn decrypt(&mut self, algo: SymmetricAlgorithm, key: &[u8]) + pub fn decrypt(&mut self, algo: SymmetricAlgorithm, key: &SessionKey) -> Result<()> { let trace = self.state.settings.trace; @@ -3155,9 +3156,9 @@ mod test { loop { if let Packet::SEIP(_) = pp.packet { let key = ::conversions::from_hex(test.key_hex, false) - .unwrap(); + .unwrap().into(); - pp.decrypt(test.algo, &key[..]).unwrap(); + pp.decrypt(test.algo, &key).unwrap(); // SEIP packet. let ((packet, _), (pp, _)) = pp.recurse().unwrap(); @@ -3219,9 +3220,9 @@ mod test { loop { if let Packet::SEIP(_) = pp.packet { let key = ::conversions::from_hex(test.key_hex, false) - .unwrap(); + .unwrap().into(); - pp.decrypt(test.algo, &key[..]).unwrap(); + pp.decrypt(test.algo, &key).unwrap(); // SEIP packet. let ((packet, _), (pp, _)) = pp.recurse().unwrap(); @@ -3297,8 +3298,8 @@ mod test { match pp.packet { Packet::SEIP(_) => { let key = ::conversions::from_hex(test.key_hex, false) - .unwrap(); - pp.decrypt(test.algo, &key[..]).unwrap(); + .unwrap().into(); + pp.decrypt(test.algo, &key).unwrap(); }, Packet::Literal(_) => { assert!(! saw_literal); diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index 5b774171..0b4238f5 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -23,6 +23,7 @@ use { packet::Signature, TPK, mpis, + SessionKey, }; use parse::{ Cookie, @@ -591,7 +592,7 @@ pub enum Secret { /// The symmetric algorithm used to encrypt the SEIP packet. algo: SymmetricAlgorithm, /// The decrypted session key. - session_key: Box<[u8]>, + session_key: SessionKey, }, } @@ -693,7 +694,7 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> { if let Ok((algo, key)) = pkesk.decrypt(&key, &secret) { - if pp.decrypt(algo, &key[..]).is_ok() { + if pp.decrypt(algo, &key).is_ok() { decrypted = true; break 'decrypt_seip; } @@ -707,7 +708,7 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> { for skesk in skesks.iter() { let (algo, key) = skesk.decrypt(pass)?; - if pp.decrypt(algo, &key[..]).is_ok() { + if pp.decrypt(algo, &key).is_ok() { decrypted = true; break 'decrypt_seip; } diff --git a/openpgp/src/pkesk.rs b/openpgp/src/pkesk.rs index 938e4de0..4416a226 100644 --- a/openpgp/src/pkesk.rs +++ b/openpgp/src/pkesk.rs @@ -6,6 +6,7 @@ use Packet; use PublicKeyAlgorithm; use Result; use SymmetricAlgorithm; +use SessionKey; use ecdh; use nettle::{rsa, Yarrow}; use packet; @@ -36,7 +37,7 @@ impl PKESK { /// The given symmetric algorithm must match the algorithm that is /// used to encrypt the payload. pub fn new(algo: SymmetricAlgorithm, - session_key: &[u8], recipient: &Key) + session_key: &SessionKey, recipient: &Key) -> Result<PKESK> { use PublicKeyAlgorithm::*; let mut rng = Yarrow::default(); @@ -131,13 +132,13 @@ impl PKESK { /// Decrypts the ESK and returns the session key and symmetric algorithm /// used to encrypt the following payload. pub fn decrypt(&self, recipient: &Key, recipient_sec: &mpis::SecretKey) - -> Result<(SymmetricAlgorithm, Box<[u8]>)> + -> Result<(SymmetricAlgorithm, SessionKey)> { use PublicKeyAlgorithm::*; use mpis::PublicKey; use nettle::rsa; - let plain = match + let plain: SessionKey = match (self.pk_algo, recipient.mpis(), recipient_sec, &self.esk) { (RSAEncryptSign, @@ -168,7 +169,7 @@ impl PKESK { return Err(Error::MalformedPacket(format!( "unsupported combination of algorithm {:?}, key pair {:?}/{:?} and ciphertext {:?}", algo, public, secret, cipher)).into()), - }; + }.into(); let key_rgn = 1..(plain.len() - 2); let symm_algo: SymmetricAlgorithm = plain[0].into(); @@ -187,7 +188,7 @@ impl PKESK { | (plain[plain.len() - 1] as usize); if their_checksum == our_checksum { - Ok((symm_algo, key.into_boxed_slice())) + Ok((symm_algo, key.into())) } else { Err(Error::MalformedPacket(format!("key checksum wrong")) .into()) diff --git a/openpgp/src/s2k.rs b/openpgp/src/s2k.rs index 3e0236fb..e1d32211 100644 --- a/openpgp/src/s2k.rs +++ b/openpgp/src/s2k.rs @@ -9,6 +9,7 @@ use Error; use Result; use HashAlgorithm; +use SessionKey; use std::fmt; @@ -68,7 +69,7 @@ impl Default for S2K { impl S2K { /// Convert the string to a key using the S2K's paramters. pub fn derive_key(&self, string: &[u8], key_size: usize) - -> Result<Vec<u8>> { + -> Result<SessionKey> { match self { &S2K::Simple { hash } | &S2K::Salted { hash, .. } | &S2K::Iterated { hash, .. } => { @@ -121,7 +122,7 @@ impl S2K { zeros.push(0); } - Ok(ret) + Ok(ret.into()) } &S2K::Unknown(u) | &S2K::Private(u) => Err(Error::MalformedPacket( diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index cfa430e0..a0f0eb6d 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -17,6 +17,7 @@ use { packet::PKESK, Result, SecretKey, + SessionKey, packet::SKESK, packet::{signature, Signature}, Tag, @@ -855,8 +856,7 @@ impl<'a> Encryptor<'a> { let algo = SymmetricAlgorithm::AES256; // Generate a session key. - let mut sk = vec![0; algo.key_size().unwrap()]; - rng.random(&mut sk); + let sk = SessionKey::new(&mut rng, algo.key_size().unwrap()); if tpks.len() + passwords.len() == 0 { return Err(Error::InvalidArgument( @@ -1287,7 +1287,7 @@ mod test { #[derive(Debug, PartialEq)] enum State { Start, - Decrypted(Vec<(SymmetricAlgorithm, Vec<u8>)>), + Decrypted(Vec<(SymmetricAlgorithm, SessionKey)>), Deciphered, MDC, Done, @@ -1319,7 +1319,7 @@ mod test { Packet::SEIP(_) => loop { if let Some((algo, key)) = keys.pop() { - let r = pp.decrypt(algo, &key[..]); + let r = pp.decrypt(algo, &key); if r.is_ok() { break State::Deciphered; } diff --git a/openpgp/src/skesk.rs b/openpgp/src/skesk.rs index 33afa2b6..c38727c1 100644 --- a/openpgp/src/skesk.rs +++ b/openpgp/src/skesk.rs @@ -4,6 +4,7 @@ use Error; use SymmetricAlgorithm; use packet; use Packet; +use SessionKey; /// Holds an symmetrically encrypted session key. /// @@ -33,7 +34,7 @@ impl SKESK { /// used to encrypt the payload, and is also used to encrypt the /// given session key. pub fn new(algo: SymmetricAlgorithm, s2k: S2K, - session_key: &[u8], password: &[u8]) + session_key: &SessionKey, password: &[u8]) -> Result<SKESK> { // Derive key and make a cipher. let key = s2k.derive_key(password, algo.key_size()?)?; @@ -105,7 +106,7 @@ impl SKESK { /// tuple of the symmetric cipher to use with the key and the key /// itself. pub fn decrypt(&self, password: &[u8]) - -> Result<(SymmetricAlgorithm, Vec<u8>)> + -> Result<(SymmetricAlgorithm, SessionKey)> { let key = self.s2k.derive_key(password, self.symm_algo.key_size()?)?; @@ -124,10 +125,13 @@ impl SKESK { dec.decrypt(&mut iv[..], pl, ct); } - let sym = SymmetricAlgorithm::from(plain[0]); - let key = plain[1..].to_vec(); - - Ok((sym, key)) + // Get the algorithm from the front. While doing that, + // push and pop a value to overwrite the position formerly + // occupied by last byte of the session key. + plain.push(0); + let sym = SymmetricAlgorithm::from(plain.remove(0)); + plain.pop(); + Ok((sym, plain.into())) } else { // No ESK, we return the derived key. |