diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-06-07 11:49:09 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-06-07 12:33:20 +0200 |
commit | b4734fbe18dbdbb096a7c3f3814f69a432025c8e (patch) | |
tree | 0fad77839230f29f29a1acde30900a9bdb604177 | |
parent | 1a9708fcc43830fb7f617381af0b42f56f4b8924 (diff) |
openpgp: Check that generated cv25519 keys are properly clamped.
-rw-r--r-- | openpgp/src/crypto/ecdh.rs | 37 |
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(()) + } } |