summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-09-28 14:53:08 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-09-28 14:53:08 +0200
commit17bbe07459ff0affbc9482ab432d51dd0cb91e7b (patch)
tree4c38b9a5b29267a3a7668e1d226374f895fa03c6
parent67a874462b716c9af52a64946a22f7456b4e1bd6 (diff)
openpgp: Add and use a type holding session keys.
-rw-r--r--ffi/src/openpgp.rs3
-rw-r--r--openpgp/examples/decrypt-with.rs2
-rw-r--r--openpgp/src/autocrypt.rs2
-rw-r--r--openpgp/src/key.rs3
-rw-r--r--openpgp/src/lib.rs46
-rw-r--r--openpgp/src/message/mod.rs3
-rw-r--r--openpgp/src/parse/parse.rs15
-rw-r--r--openpgp/src/parse/stream.rs7
-rw-r--r--openpgp/src/pkesk.rs11
-rw-r--r--openpgp/src/s2k.rs5
-rw-r--r--openpgp/src/serialize/stream.rs8
-rw-r--r--openpgp/src/skesk.rs16
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.