summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-10-06 14:50:45 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-10-06 14:56:16 +0200
commite980facce477e7bbe5de5d5e970124a9203c0004 (patch)
tree03d96d095939570b6e4788a39e711842b3dc1fdc
parentad127e721f512d3c77733db309cbe74956729069 (diff)
openpgp: Support encrypted keys protected by two octet sum.
- Encrypted key material can be protected by either SHA1 or a two octet sum over the key material. The latter is not used anymore, but GnuPG 2.1 emits this S2K usage octet when emitting TSKs with detached keys. - Fixes #569.
-rw-r--r--openpgp/src/packet/key.rs21
-rw-r--r--openpgp/src/parse.rs11
-rw-r--r--openpgp/src/serialize.rs8
-rw-r--r--openpgp/src/serialize/cert.rs9
4 files changed, 36 insertions, 13 deletions
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs
index 8ba4d5d2..3384738b 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key.rs
@@ -1363,15 +1363,16 @@ impl Unencrypted {
let mut trash = vec![0u8; algo.block_size()?];
crypto::random(&mut trash);
+ let checksum = Default::default();
let mut esk = Vec::new();
{
let mut encryptor = Encryptor::new(algo, &key, &mut esk)?;
encryptor.write_all(&trash)?;
self.map(|mpis| mpis.serialize_with_checksum(&mut encryptor,
- Default::default()))?;
+ checksum))?;
}
- Ok(Encrypted::new(s2k, algo, esk.into_boxed_slice()))
+ Ok(Encrypted::new(s2k, algo, Some(checksum), esk.into_boxed_slice()))
}
}
@@ -1386,6 +1387,8 @@ pub struct Encrypted {
s2k: S2K,
/// Symmetric algorithm used to encrypt the secret key material.
algo: SymmetricAlgorithm,
+ /// Checksum method.
+ checksum: Option<mpi::SecretKeyChecksum>,
/// Encrypted MPIs prefixed with the IV.
///
/// If we recognized the S2K object during parsing, we can
@@ -1433,19 +1436,21 @@ impl std::hash::Hash for Encrypted {
impl Encrypted {
/// Creates a new encrypted key object.
- pub fn new(s2k: S2K, algo: SymmetricAlgorithm, ciphertext: Box<[u8]>)
+ pub fn new(s2k: S2K, algo: SymmetricAlgorithm,
+ checksum: Option<mpi::SecretKeyChecksum>, ciphertext: Box<[u8]>)
-> Self
{
- Self::new_raw(s2k, algo, Ok(ciphertext))
+ Self::new_raw(s2k, algo, checksum, Ok(ciphertext))
}
/// Creates a new encrypted key object.
pub(crate) fn new_raw(s2k: S2K, algo: SymmetricAlgorithm,
+ checksum: Option<mpi::SecretKeyChecksum>,
ciphertext: std::result::Result<Box<[u8]>,
Box<[u8]>>)
-> Self
{
- Encrypted { s2k, algo, ciphertext }
+ Encrypted { s2k, algo, checksum, ciphertext }
}
/// Returns the key derivation mechanism.
@@ -1459,6 +1464,12 @@ impl Encrypted {
self.algo
}
+ /// Returns the checksum method used to protect the encrypted
+ /// secret key material, if any.
+ pub fn checksum(&self) -> Option<mpi::SecretKeyChecksum> {
+ self.checksum
+ }
+
/// Returns the encrypted secret key material.
///
/// If the [`S2K`] mechanism is not supported by Sequoia, this
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index 9adf0d01..2d333705 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -2120,7 +2120,7 @@ impl Key4<key::UnspecifiedParts, key::UnspecifiedRole>
return php.fail("unsupported secret key encryption");
}
// Encrypted, S2K & SHA-1 checksum
- 254 => {
+ 254 | 255 => {
let sk: SymmetricAlgorithm = php_try!(php.parse_u8("sym_algo")).into();
let s2k = php_try!(S2K::parse(&mut php));
let s2k_supported = s2k.is_supported();
@@ -2130,6 +2130,11 @@ impl Key4<key::UnspecifiedParts, key::UnspecifiedRole>
crate::packet::key::Encrypted::new_raw(
s2k, sk,
+ if s2k_usage == 254 {
+ Some(mpi::SecretKeyChecksum::SHA1)
+ } else {
+ Some(mpi::SecretKeyChecksum::Sum16)
+ },
if s2k_supported {
Ok(cipher)
} else {
@@ -2137,10 +2142,6 @@ impl Key4<key::UnspecifiedParts, key::UnspecifiedRole>
},
).into()
}
- // Encrypted, S2K & mod 65536 checksum: unsupported
- 255 => {
- return php.fail("unsupported secret key encryption");
- }
};
Some(sec)
diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs
index 032cc70b..0ebecf42 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -1831,7 +1831,13 @@ impl<P, R> Key4<P, R>
})?,
SecretKeyMaterial::Encrypted(ref e) => {
// S2K usage.
- write_byte(o, 254)?;
+ write_byte(o, match e.checksum() {
+ Some(SecretKeyChecksum::SHA1) => 254,
+ Some(SecretKeyChecksum::Sum16) => 255,
+ None => return Err(Error::InvalidOperation(
+ "In Key4 packets, encrypted secret keys must be \
+ checksummed".into()).into()),
+ })?;
write_byte(o, e.algo().into())?;
e.s2k().serialize(o)?;
o.write_all(e.raw_ciphertext())?;
diff --git a/openpgp/src/serialize/cert.rs b/openpgp/src/serialize/cert.rs
index 7489983e..177f9b8b 100644
--- a/openpgp/src/serialize/cert.rs
+++ b/openpgp/src/serialize/cert.rs
@@ -495,8 +495,13 @@ impl<'a> TSK<'a> {
};
let key_with_stub = key.clone()
.add_secret(key::SecretKeyMaterial::Encrypted(
- key::Encrypted::new(stub, 0.into(),
- vec![].into()))).0;
+ key::Encrypted::new(
+ stub, 0.into(),
+ // Mirrors more closely what GnuPG 2.1
+ // does (oddly, GnuPG 1.4 emits 0xfe
+ // here).
+ Some(crate::crypto::mpi::SecretKeyChecksum::Sum16),
+ vec![].into()))).0;
return match tag {
Tag::PublicKey =>
crate::Packet::SecretKey(key_with_stub.into())