-
Notifications
You must be signed in to change notification settings - Fork 269
Description
I tried using version of 0.14.0-pre.2 of ed448_goldilocks and encountered a problem that I'm pretty sure is a bug in the library:
const PRIVATE_KEY: &str = "-----BEGIN PRIVATE KEY-----
MEcCAQAwBQYDK2VxBDsEOYrsF28Jlv/NB2SCjTz0Ax578DThtcGskl01aPFyjIsQ
yx0O34c/sstZ3SeqFbpP62izrpcSrMDXJA==
-----END PRIVATE KEY-----
";
use ed448_goldilocks::{SigningKey, pkcs8::DecodePrivateKey};
SigningKey::from_pkcs8_pem(PRIVATE_KEY)This returns an Err, despite the key being correct. I think the bug is here:
elliptic-curves/ed448-goldilocks/src/sign/signing_key.rs
Lines 339 to 371 in 20eeeff
| #[cfg(feature = "pkcs8")] | |
| impl TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for KeypairBytes { | |
| type Error = pkcs8::Error; | |
| fn try_from(value: pkcs8::PrivateKeyInfoRef<'_>) -> Result<Self, Self::Error> { | |
| if value.algorithm.oid != super::ALGORITHM_OID { | |
| return Err(pkcs8::Error::KeyMalformed); | |
| } | |
| if value.private_key.as_bytes().len() != SECRET_KEY_LENGTH { | |
| return Err(pkcs8::Error::KeyMalformed); | |
| } | |
| let mut secret_key = [0u8; SECRET_KEY_LENGTH]; | |
| secret_key.copy_from_slice(value.private_key.as_bytes()); | |
| let verifying_key = if let Some(public_key) = value.public_key { | |
| if public_key.has_unused_bits() { | |
| return Err(pkcs8::Error::KeyMalformed); | |
| } | |
| let public_key = public_key.raw_bytes(); | |
| if public_key.len() != PUBLIC_KEY_LENGTH { | |
| return Err(pkcs8::Error::KeyMalformed); | |
| } | |
| let mut bytes = [0u8; PUBLIC_KEY_LENGTH]; | |
| bytes.copy_from_slice(public_key); | |
| Some(bytes) | |
| } else { | |
| None | |
| }; | |
| Ok(KeypairBytes { | |
| secret_key, | |
| verifying_key, | |
| }) | |
| } | |
| } |
It checks value.private_key.as_bytes().len() != SECRET_KEY_LENGTH, but value.private_key.as_bytes() returns the whole base64 encoded data, including the PKCS8 header.
let (_, pkcs8_bytes) = pem_rfc7468::decode_vec(PRIVATE_KEY.as_bytes()).unwrap();
let info = pkcs8::PrivateKeyInfoRef::try_from(pkcs8_bytes.as_slice()).unwrap();
println!("{:02x?}", info.private_key.as_bytes());
This prints [04, 39, 8a, ec, 17, 6f, 09, 96, ff, cd, 07, 64, 82, 8d, 3c, f4, 03, 1e, 7b, f0, 34, e1, b5, c1, ac, 92, 5d, 35, 68, f1, 72, 8c, 8b, 10, cb, 1d, 0e, df, 87, 3f, b2, cb, 59, dd, 27, aa, 15, ba, 4f, eb, 68, b3, ae, 97, 12, ac, c0, d7, 24]
Letting openssl print the info about the key:
➜ openssl pkey -in ed448-key.pem -text -noout
ED448 Private-Key:
priv:
8a:ec:17:6f:09:96:ff:cd:07:64:82:8d:3c:f4:03:
1e:7b:f0:34:e1:b5:c1:ac:92:5d:35:68:f1:72:8c:
8b:10:cb:1d:0e:df:87:3f:b2:cb:59:dd:27:aa:15:
ba:4f:eb:68:b3:ae:97:12:ac:c0:d7:24
We see that it's the same data, without the first 2 bytes.