summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-06-07 11:49:09 +0200
committerJustus Winter <justus@sequoia-pgp.org>2021-06-07 12:33:20 +0200
commitb4734fbe18dbdbb096a7c3f3814f69a432025c8e (patch)
tree0fad77839230f29f29a1acde30900a9bdb604177
parent1a9708fcc43830fb7f617381af0b42f56f4b8924 (diff)
openpgp: Check that generated cv25519 keys are properly clamped.
-rw-r--r--openpgp/src/crypto/ecdh.rs37
1 files changed, 37 insertions, 0 deletions
diff --git a/openpgp/src/crypto/ecdh.rs b/openpgp/src/crypto/ecdh.rs
index 5ed7c203..df88c946 100644
--- a/openpgp/src/crypto/ecdh.rs
+++ b/openpgp/src/crypto/ecdh.rs
@@ -507,4 +507,41 @@ mod tests {
assert_eq!(&Protected::from(test.key_data), &key_data);
}
}
+
+ #[test]
+ fn cv25519_generation() -> Result<()> {
+ const CURVE25519_SIZE: usize = 32;
+
+ fn check_clamping<S: AsRef<[u8]>>(s: S) {
+ // Curve25519 Paper, Sec. 3: A user can, for example,
+ // generate 32 uniform random bytes, clear bits 0, 1, 2 of
+ // the first byte, clear bit 7 of the last byte, and set
+ // bit 6 of the last byte.
+
+ // OpenPGP stores the secret in reverse order.
+ const FIRST: usize = CURVE25519_SIZE - 1;
+ const LAST: usize = 0;
+
+ let s = s.as_ref();
+ assert_eq!(s[FIRST] & ! 0b1111_1000, 0);
+ assert_eq!(s[LAST] & 0b1100_0000, 0b0100_0000);
+ }
+
+ for _ in 0..5 {
+ let k: key::Key4<_, key::SubordinateRole> =
+ key::Key4::generate_ecc(false, Curve::Cv25519)?;
+ match k.secret() {
+ key::SecretKeyMaterial::Unencrypted(m) => m.map(|mpis| {
+ match mpis {
+ mpi::SecretKeyMaterial::ECDH { scalar } =>
+ check_clamping(scalar.value()),
+ o => panic!("unexpected key material: {:?}", o),
+ }
+ }),
+ o => panic!("expected unencrypted material: {:?}", o),
+ }
+ }
+
+ Ok(())
+ }
}