summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-08-12 11:02:51 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-08-12 13:34:02 +0200
commit5a5e909dd1cc5949d1995a7bf48e7ad11ee40e45 (patch)
treee05041e689a1598097286579cc7e01e9084a7945
parentaeeb728a6dcef2eafa53d3754c67cadd765820a2 (diff)
openpgp: Improve SKESK?::with_password.
- Previously, the symmetric algorithm argument conflated the algorithm to protect the payload and the one to protect the session key. Fix that by adding an argument to make the choice explicit.
-rw-r--r--openpgp/src/message/mod.rs1
-rw-r--r--openpgp/src/packet/skesk.rs67
-rw-r--r--openpgp/src/serialize/stream.rs5
3 files changed, 51 insertions, 22 deletions
diff --git a/openpgp/src/message/mod.rs b/openpgp/src/message/mod.rs
index 92346701..a436fde0 100644
--- a/openpgp/src/message/mod.rs
+++ b/openpgp/src/message/mod.rs
@@ -1057,6 +1057,7 @@ mod tests {
#[allow(deprecated)]
packets.push(SKESK4::with_password(
cipher,
+ cipher,
S2K::Simple { hash: HashAlgorithm::SHA256 },
&sk,
&"12345678".into()).unwrap().into());
diff --git a/openpgp/src/packet/skesk.rs b/openpgp/src/packet/skesk.rs
index 9e6d9a2c..27293aa5 100644
--- a/openpgp/src/packet/skesk.rs
+++ b/openpgp/src/packet/skesk.rs
@@ -97,27 +97,38 @@ impl SKESK4 {
/// Creates a new SKESK4 packet with the given password.
///
- /// The given symmetric algorithm must match the algorithm that is
- /// used to encrypt the payload, and is also used to encrypt the
- /// given session key.
- pub fn with_password(algo: SymmetricAlgorithm, s2k: S2K,
+ /// This function takes two [`SymmetricAlgorithm`] arguments: The
+ /// first, `payload_algo`, is the algorithm used to encrypt the
+ /// message's payload (i.e. the one used in the [`SEIP`] or
+ /// [`AED`] packet), and the second, `esk_algo`, is used to
+ /// encrypt the session key. Usually, one should use the same
+ /// algorithm, but if they differ, the `esk_algo` should be at
+ /// least as strong as the `payload_algo` as not to weaken the
+ /// security of the payload encryption.
+ ///
+ /// [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html
+ /// [`SEIP`]: ../enum.SEIP.html
+ /// [`AED`]: ../enum.AED.html
+ pub fn with_password(payload_algo: SymmetricAlgorithm,
+ esk_algo: SymmetricAlgorithm,
+ s2k: S2K,
session_key: &SessionKey, password: &Password)
-> Result<SKESK4> {
- if session_key.len() != algo.key_size()? {
+ if session_key.len() != payload_algo.key_size()? {
return Err(Error::InvalidArgument(format!(
"Invalid size of session key, got {} want {}",
- session_key.len(), algo.key_size()?)).into());
+ session_key.len(), payload_algo.key_size()?)).into());
}
// Derive key and make a cipher.
- let key = s2k.derive_key(password, algo.key_size()?)?;
- let mut cipher = algo.make_encrypt_cfb(&key[..])?;
- let block_size = algo.block_size()?;
+ let key = s2k.derive_key(password, esk_algo.key_size()?)?;
+ let mut cipher = esk_algo.make_encrypt_cfb(&key[..])?;
+ let block_size = esk_algo.block_size()?;
let mut iv = vec![0u8; block_size];
// We need to prefix the cipher specifier to the session key.
let mut psk = Vec::with_capacity(1 + session_key.len());
- psk.push(algo.into());
+ psk.push(payload_algo.into());
psk.extend_from_slice(session_key);
let mut esk = vec![0u8; psk.len()];
@@ -126,7 +137,7 @@ impl SKESK4 {
cipher.encrypt(&mut iv[..], ct, pt)?;
}
- SKESK4::new(algo, s2k, Some(esk))
+ SKESK4::new(esk_algo, s2k, Some(esk))
}
/// Gets the symmetric encryption algorithm.
@@ -292,24 +303,38 @@ impl SKESK5 {
}
/// Creates a new SKESK version 5 packet with the given password.
- pub fn with_password(cipher: SymmetricAlgorithm,
- aead: AEADAlgorithm, s2k: S2K,
+ ///
+ /// This function takes two [`SymmetricAlgorithm`] arguments: The
+ /// first, `payload_algo`, is the algorithm used to encrypt the
+ /// message's payload (i.e. the one used in the [`SEIP`] or
+ /// [`AED`] packet), and the second, `esk_algo`, is used to
+ /// encrypt the session key. Usually, one should use the same
+ /// algorithm, but if they differ, the `esk_algo` should be at
+ /// least as strong as the `payload_algo` as not to weaken the
+ /// security of the payload encryption.
+ ///
+ /// [`SymmetricAlgorithm`]: ../../types/enum.SymmetricAlgorithm.html
+ /// [`SEIP`]: ../enum.SEIP.html
+ /// [`AED`]: ../enum.AED.html
+ pub fn with_password(payload_algo: SymmetricAlgorithm,
+ esk_algo: SymmetricAlgorithm,
+ esk_aead: AEADAlgorithm, s2k: S2K,
session_key: &SessionKey, password: &Password)
-> Result<Self> {
- if session_key.len() != cipher.key_size()? {
+ if session_key.len() != payload_algo.key_size()? {
return Err(Error::InvalidArgument(format!(
"Invalid size of session key, got {} want {}",
- session_key.len(), cipher.key_size()?)).into());
+ session_key.len(), payload_algo.key_size()?)).into());
}
// Derive key and make a cipher.
- let key = s2k.derive_key(password, cipher.key_size()?)?;
- let mut iv = vec![0u8; aead.iv_size()?];
+ let key = s2k.derive_key(password, esk_algo.key_size()?)?;
+ let mut iv = vec![0u8; esk_aead.iv_size()?];
crypto::random(&mut iv);
- let mut ctx = aead.context(cipher, &key, &iv)?;
+ let mut ctx = esk_aead.context(esk_algo, &key, &iv)?;
// Prepare associated data.
- let ad = [0xc3, 5, cipher.into(), aead.into()];
+ let ad = [0xc3, 5, esk_algo.into(), esk_aead.into()];
ctx.update(&ad);
// We need to prefix the cipher specifier to the session key.
@@ -317,10 +342,10 @@ impl SKESK5 {
ctx.encrypt(&mut esk, &session_key);
// Digest.
- let mut digest = vec![0u8; aead.digest_size()?];
+ let mut digest = vec![0u8; esk_aead.digest_size()?];
ctx.digest(&mut digest);
- SKESK5::new(cipher, aead, s2k, iv.into_boxed_slice(), esk,
+ SKESK5::new(esk_algo, esk_aead, s2k, iv.into_boxed_slice(), esk,
digest.into_boxed_slice())
}
diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs
index 6982f4dc..2ff14398 100644
--- a/openpgp/src/serialize/stream.rs
+++ b/openpgp/src/serialize/stream.rs
@@ -2523,12 +2523,15 @@ impl<'a> Encryptor<'a> {
// Write the SKESK packet(s).
for password in self.passwords.iter() {
if let Some(aead) = aead.as_ref() {
- let skesk = SKESK5::with_password(self.sym_algo, aead.algo,
+ let skesk = SKESK5::with_password(self.sym_algo,
+ self.sym_algo,
+ aead.algo,
Default::default(),
&sk, password).unwrap();
Packet::SKESK(skesk.into()).serialize(&mut inner)?;
} else {
let skesk = SKESK4::with_password(self.sym_algo,
+ self.sym_algo,
Default::default(),
&sk, password).unwrap();
Packet::SKESK(skesk.into()).serialize(&mut inner)?;