use crate::Error;
use crate::error::KeyFormatError;
use crate::high::asn1::{self, Type, pkix};
use crate::high::pkcs8;
use crate::low::{Entry, ct, zeroise};
use crate::mid::ed25519;
use crate::mid::rng::{RandomSource, SystemRandom};
#[derive(Debug)]
pub(crate) struct Ed25519VerifyingKey(ed25519::VerifyingKey);
impl Ed25519VerifyingKey {
pub(crate) fn to_spki_der<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], Error> {
let pub_key_buffer = self.as_bytes();
let spki = pkix::SubjectPublicKeyInfo {
algorithm: pkix::AlgorithmIdentifier {
algorithm: asn1::oid::id_ed25519.clone(),
parameters: None,
},
subjectPublicKey: asn1::BitString::new(&pub_key_buffer[..]),
};
let len = spki
.encode(&mut asn1::Encoder::new(output))
.map_err(|_| Error::WrongLength)?;
Ok(&output[..len])
}
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_public();
ed25519::VerifyingKey::from_bytes(bytes).map(Self)
}
pub(crate) fn as_bytes(&self) -> [u8; 32] {
self.0.as_bytes()
}
pub(crate) fn verify(&self, signature: &[u8], message: &[u8]) -> Result<(), Error> {
let _entry = Entry::new_public();
self.0.verify(
signature.try_into().map_err(|_| Error::BadSignature)?,
message,
)
}
}
pub(crate) struct Ed25519SigningKey(ed25519::SigningKey);
impl Ed25519SigningKey {
pub(crate) fn generate() -> Result<Self, Error> {
let _entry = Entry::new_secret();
let mut seed = [0u8; 32];
SystemRandom.fill(&mut seed)?;
let r = Ok(Self(ed25519::SigningKey::from_seed(&seed)));
zeroise(&mut seed);
r
}
pub(crate) fn sign(&self, message: &[u8]) -> [u8; 64] {
let _entry = Entry::new_secret();
self.0.sign(message)
}
pub(crate) fn public_key(&self) -> Ed25519VerifyingKey {
let _entry = Entry::new_public();
Ed25519VerifyingKey(self.0.verifying_key().clone())
}
pub(crate) fn from_pkcs8_der(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_secret();
let p8 = pkcs8::Key::decode(bytes, &asn1::oid::id_ed25519, None)?;
let key = asn1::OctetString::from_bytes(p8.private_key())
.map_err(|e| Error::from(KeyFormatError::Asn1(e)))
.and_then(|pk| Self::from_bytes(pk.as_octets()))?;
if let Some(alleged_pub_key) = p8.public_key() {
let actual_pub_key = key.public_key().as_bytes();
if alleged_pub_key != actual_pub_key {
return Err(KeyFormatError::MismatchedPkcs8PublicKey.into());
}
}
Ok(key)
}
pub(crate) fn to_pkcs8_der<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], Error> {
let _entry = Entry::new_secret();
let mut private_key_buf = [0u8; 34];
let private_key_len = asn1::OctetString::new(self.0.as_seed_bytes())
.encode(&mut asn1::Encoder::new(&mut private_key_buf))
.map_err(|_| Error::WrongLength)?;
assert_eq!(private_key_len, private_key_buf.len());
let public_key = self.public_key().as_bytes();
match pkcs8::Key::construct(
&private_key_buf[..],
Some(&public_key[..]),
asn1::oid::id_ed25519.clone(),
None,
)
.encode(output)
{
Ok(bytes) => {
ct::public_slice(bytes);
Ok(bytes)
}
Err(e) => Err(e),
}
}
pub(crate) fn from_bytes(seed: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_secret();
seed.try_into()
.map(|seed| Self(ed25519::SigningKey::from_seed(&seed)))
.map_err(|_| KeyFormatError::WrongLength.into())
}
pub(crate) fn seed(&self) -> &[u8; 32] {
self.0.as_seed_bytes()
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn pairwise() {
for _ in 0..100 {
let k = Ed25519SigningKey::generate().unwrap();
let pk = k.public_key();
let mut msg = [0u8; 128];
SystemRandom.fill(&mut msg).unwrap();
let sig = k.sign(&msg);
pk.verify(&sig, &msg).unwrap();
}
}
#[test]
fn decode_pkcs8_v1() {
let bytes = include_bytes!("asn1/testdata/ed25519-p8v1.bin");
let key = Ed25519SigningKey::from_pkcs8_der(bytes).unwrap();
let mut buf = vec![0; 128];
let buf = key.to_pkcs8_der(&mut buf).unwrap();
assert_ne!(bytes, buf);
assert!(bytes.len() < buf.len());
}
#[test]
fn round_trip_pkcs8_v2() {
let bytes = include_bytes!("asn1/testdata/ed25519-p8v2.bin");
let key = Ed25519SigningKey::from_pkcs8_der(bytes).unwrap();
let mut buf = vec![0; bytes.len()];
assert_eq!(
key.to_pkcs8_der(&mut buf[..bytes.len() - 1]),
Err(Error::WrongLength)
);
let buf = key.to_pkcs8_der(&mut buf).unwrap();
assert_eq!(bytes, buf);
}
#[test]
fn spki_encode_length() {
let pk = Ed25519SigningKey::generate().unwrap().public_key();
assert_eq!(
pk.to_spki_der(&mut [0u8; 32]).unwrap_err(),
Error::WrongLength
);
}
#[test]
fn pkcs8_public_key_wrong() {
let mut bytes = include_bytes!("asn1/testdata/ed25519-p8v2.bin").to_vec();
bytes[52] ^= 0x01;
assert_eq!(
Ed25519SigningKey::from_pkcs8_der(&bytes).err(),
Some(KeyFormatError::MismatchedPkcs8PublicKey.into())
);
}
#[test]
fn verifying_key_from_bytes() {
const GOOD: &[u8] = &[
0x53, 0x0e, 0x81, 0x33, 0x75, 0x16, 0x14, 0xbe, 0x84, 0x26, 0x71, 0x59, 0x50, 0xc2,
0x49, 0x71, 0x67, 0x0c, 0xb5, 0xd9, 0x89, 0x14, 0xc0, 0xf0, 0xbd, 0xb4, 0xd9, 0x49,
0x05, 0xee, 0x0d, 0x9e,
];
assert!(Ed25519VerifyingKey::from_bytes(GOOD).is_ok());
assert_eq!(
Ed25519VerifyingKey::from_bytes(&[0xff; 32]).err(),
Some(KeyFormatError::NotOnCurve.into())
);
let encode = |y: [u8; 32], negative: bool| {
let mut bytes = y;
bytes[31] |= u8::from(negative) << 7;
bytes
};
let mut y_one = [0; 32];
y_one[0] = 1;
let mut y_minus_one = [0xff; 32];
y_minus_one[0] = 0xec;
y_minus_one[31] = 0x7f;
let mut y_p = y_minus_one;
y_p[0] = 0xed;
let mut y_two = [0; 32];
y_two[0] = 2;
for (y, negative, ok) in [
(y_one, false, true),
(y_one, true, false),
(y_minus_one, false, true),
(y_minus_one, true, false),
(y_p, false, false),
(y_two, false, false),
] {
let result = Ed25519VerifyingKey::from_bytes(&encode(y, negative));
assert_eq!(
result.err(),
(!ok).then_some(KeyFormatError::NotOnCurve.into()),
"{y:x?} {negative}"
);
}
assert_eq!(
Ed25519VerifyingKey::from_bytes(&[0; 31]).err(),
Some(KeyFormatError::WrongLength.into())
);
assert_eq!(
Ed25519VerifyingKey::from_bytes(&[0; 33]).err(),
Some(KeyFormatError::WrongLength.into())
);
}
}