use aws_lc_rs::signature::{
EcdsaKeyPair, Ed25519KeyPair, UnparsedPublicKey, ECDSA_P256_SHA256_FIXED,
ECDSA_P256_SHA256_FIXED_SIGNING, ED25519,
};
use oxicrypto_core::{CryptoError, Signer, Verifier};
#[derive(Debug, Default, Clone, Copy)]
pub struct AwsLcEd25519Signer;
#[derive(Debug, Default, Clone, Copy)]
pub struct AwsLcEd25519Verifier;
impl Signer for AwsLcEd25519Signer {
fn name(&self) -> &'static str {
"Ed25519 (aws-lc-rs)"
}
fn signature_len(&self) -> usize {
64
}
fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
if sig_out.len() < 64 {
return Err(CryptoError::BufferTooSmall);
}
let kp = Ed25519KeyPair::from_seed_unchecked(sk).map_err(|_| CryptoError::InvalidKey)?;
let sig = kp.sign(msg);
sig_out[..64].copy_from_slice(sig.as_ref());
Ok(64)
}
}
impl Verifier for AwsLcEd25519Verifier {
fn name(&self) -> &'static str {
"Ed25519 (aws-lc-rs)"
}
fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
let unparsed = UnparsedPublicKey::new(&ED25519, pk);
unparsed
.verify(msg, sig)
.map_err(|_| CryptoError::InvalidTag)
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct AwsLcEcdsaP256Signer;
#[derive(Debug, Default, Clone, Copy)]
pub struct AwsLcEcdsaP256Verifier;
impl Signer for AwsLcEcdsaP256Signer {
fn name(&self) -> &'static str {
"ECDSA-P256-SHA256 (aws-lc-rs)"
}
fn signature_len(&self) -> usize {
64
}
fn sign(&self, sk: &[u8], msg: &[u8], sig_out: &mut [u8]) -> Result<usize, CryptoError> {
if sig_out.len() < 64 {
return Err(CryptoError::BufferTooSmall);
}
if sk.len() != 32 {
return Err(CryptoError::InvalidKey);
}
let der = build_p256_sec1_der(sk)?;
let rng = aws_lc_rs::rand::SystemRandom::new();
let kp = EcdsaKeyPair::from_private_key_der(&ECDSA_P256_SHA256_FIXED_SIGNING, &der)
.map_err(|_| CryptoError::InvalidKey)?;
let sig = kp.sign(&rng, msg).map_err(|_| CryptoError::Sign)?;
let sig_bytes = sig.as_ref();
if sig_bytes.len() != 64 {
return Err(CryptoError::Internal(
"unexpected ECDSA-P256 signature length",
));
}
sig_out[..64].copy_from_slice(sig_bytes);
Ok(64)
}
}
impl Verifier for AwsLcEcdsaP256Verifier {
fn name(&self) -> &'static str {
"ECDSA-P256-SHA256 (aws-lc-rs)"
}
fn verify(&self, pk: &[u8], msg: &[u8], sig: &[u8]) -> Result<(), CryptoError> {
let unparsed = UnparsedPublicKey::new(&ECDSA_P256_SHA256_FIXED, pk);
unparsed
.verify(msg, sig)
.map_err(|_| CryptoError::InvalidTag)
}
}
fn build_p256_sec1_der(private_key: &[u8]) -> Result<Vec<u8>, CryptoError> {
if private_key.len() != 32 {
return Err(CryptoError::InvalidKey);
}
let octet_string: Vec<u8> = {
let mut v = vec![0x04u8, 0x20]; v.extend_from_slice(private_key);
v
};
let named_curve: Vec<u8> = vec![
0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, ];
let version: Vec<u8> = vec![0x02, 0x01, 0x01];
let mut contents: Vec<u8> = Vec::new();
contents.extend_from_slice(&version);
contents.extend_from_slice(&octet_string);
contents.extend_from_slice(&named_curve);
let content_len = contents.len();
let mut der: Vec<u8> = Vec::new();
der.push(0x30); encode_der_length(&mut der, content_len);
der.extend_from_slice(&contents);
Ok(der)
}
fn encode_der_length(buf: &mut Vec<u8>, len: usize) {
if len < 0x80 {
buf.push(len as u8);
} else if len < 0x100 {
buf.push(0x81);
buf.push(len as u8);
} else {
buf.push(0x82);
buf.push((len >> 8) as u8);
buf.push((len & 0xff) as u8);
}
}
#[cfg(test)]
mod tests {
use super::*;
use aws_lc_rs::signature::KeyPair;
#[test]
fn ed25519_sign_verify_round_trip() {
let seed = [0x5au8; 32];
let kp = Ed25519KeyPair::from_seed_unchecked(&seed).expect("kp");
let pk = kp.public_key().as_ref().to_vec();
let signer = AwsLcEd25519Signer;
let verifier = AwsLcEd25519Verifier;
let msg = b"test message from aws-lc adapter";
let mut sig = [0u8; 64];
let n = signer.sign(&seed, msg, &mut sig).expect("sign");
assert_eq!(n, 64);
verifier.verify(&pk, msg, &sig).expect("verify");
}
#[test]
fn ed25519_wrong_sig_fails() {
let seed = [0x5au8; 32];
let kp = Ed25519KeyPair::from_seed_unchecked(&seed).expect("kp");
let pk = kp.public_key().as_ref().to_vec();
let signer = AwsLcEd25519Signer;
let verifier = AwsLcEd25519Verifier;
let msg = b"test message";
let mut sig = [0u8; 64];
signer.sign(&seed, msg, &mut sig).expect("sign");
sig[0] ^= 0xff;
assert_eq!(
verifier.verify(&pk, msg, &sig),
Err(CryptoError::InvalidTag)
);
}
#[test]
fn ecdsa_p256_sign_verify_round_trip() {
let kp = EcdsaKeyPair::generate(&ECDSA_P256_SHA256_FIXED_SIGNING).expect("kp generate");
let pk = kp.public_key().as_ref().to_vec();
let sk_der = kp.to_pkcs8v1().expect("pkcs8");
let rng = aws_lc_rs::rand::SystemRandom::new();
let msg = b"ecdsa p256 test message";
let sig = kp.sign(&rng, msg).expect("sign");
let sig_bytes = sig.as_ref();
let verifier = AwsLcEcdsaP256Verifier;
verifier.verify(&pk, msg, sig_bytes).expect("verify");
let mut bad_sig = sig_bytes.to_vec();
bad_sig[0] ^= 0x01;
assert_eq!(
verifier.verify(&pk, msg, &bad_sig),
Err(CryptoError::InvalidTag)
);
let _ = sk_der;
}
}