use crate::Error;
use crate::error::KeyFormatError;
use crate::high::asn1::{self, Type, pkix};
use crate::high::pkcs8;
use crate::low::Entry;
use crate::low::zeroise;
use crate::mid::ed25519;
use crate::mid::rng::{RandomSource, SystemRandom};
#[derive(Debug)]
pub struct Ed25519VerifyingKey(ed25519::VerifyingKey);
impl Ed25519VerifyingKey {
pub fn from_spki_der(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_public();
let decoded = pkix::SubjectPublicKeyInfo::from_bytes(bytes).map_err(Error::Asn1Error)?;
if decoded.algorithm.algorithm != asn1::oid::id_ed25519 {
return Err(KeyFormatError::MismatchedSpkiAlgorithm.into());
}
Self::from_bytes(decoded.subjectPublicKey.as_octets())
}
pub 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 fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_public();
ed25519::VerifyingKey::from_bytes(bytes).map(Self)
}
pub fn as_bytes(&self) -> [u8; 32] {
self.0.as_bytes()
}
pub 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 struct Ed25519SigningKey(ed25519::SigningKey);
impl Ed25519SigningKey {
pub 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 fn sign(&self, message: &[u8]) -> [u8; 64] {
let _entry = Entry::new_secret();
self.0.sign(message)
}
pub fn public_key(&self) -> Ed25519VerifyingKey {
let _entry = Entry::new_public();
Ed25519VerifyingKey(self.0.verifying_key().clone())
}
pub 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(Error::Asn1Error)
.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 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::Asn1Error)?;
assert_eq!(private_key_len, private_key_buf.len());
let public_key = self.public_key().as_bytes();
pkcs8::Key::construct(
&private_key_buf[..],
Some(&public_key[..]),
asn1::oid::id_ed25519.clone(),
None,
)
.encode(output)
}
pub 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(|_| Error::WrongLength)
}
pub fn as_seed(&self) -> &[u8; 32] {
self.0.as_seed_bytes()
}
}
#[cfg(test)]
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 test_round_trip_seed() {
let seed = [0xff; 32];
let key = Ed25519SigningKey::from_bytes(&seed).unwrap();
assert_eq!(key.as_seed(), &seed);
}
#[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()];
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 spki_wrong_oid() {
Ed25519VerifyingKey::from_spki_der(&[
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xdd, 0x2d,
0x67, 0x8b, 0xae, 0x22, 0x2f, 0x3f, 0xb6, 0xe8, 0x27, 0x8f, 0x08, 0xcc, 0x9e, 0x1a,
0x66, 0x33, 0x9c, 0x92, 0x6c, 0x29, 0xac, 0x0a, 0x16, 0xf9, 0x71, 0x7f, 0x5e, 0xe1,
0x8c, 0xd8,
])
.unwrap();
let e = Ed25519VerifyingKey::from_spki_der(&[
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x64, 0x70, 0x03, 0x21, 0x00, 0xdd, 0x2d,
0x67, 0x8b, 0xae, 0x22, 0x2f, 0x3f, 0xb6, 0xe8, 0x27, 0x8f, 0x08, 0xcc, 0x9e, 0x1a,
0x66, 0x33, 0x9c, 0x92, 0x6c, 0x29, 0xac, 0x0a, 0x16, 0xf9, 0x71, 0x7f, 0x5e, 0xe1,
0x8c, 0xd8,
])
.unwrap_err();
assert_eq!(e, KeyFormatError::MismatchedSpkiAlgorithm.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(Error::NotOnCurve)
);
assert_eq!(
Ed25519VerifyingKey::from_bytes(&[0; 31]).err(),
Some(Error::WrongLength)
);
assert_eq!(
Ed25519VerifyingKey::from_bytes(&[0; 33]).err(),
Some(Error::WrongLength)
);
}
}