use super::asn1::{self, Type};
use super::curve::{
Curve, MAX_SCALAR_LEN, MAX_UNCOMPRESSED_PUBLIC_KEY_LEN, PrivateKey, PublicKey, Scalar,
};
use super::hash::{Hash, SignatureHash};
use super::hmac_drbg::HmacDrbg;
use super::pkcs8;
use crate::error::{Error, KeyFormatError};
use crate::low::{Entry, ct};
use crate::mid::rng::{RandomSource, SystemRandom};
pub(crate) struct SigningKey<C: Curve> {
private_key: C::PrivateKey,
public_key: [u8; MAX_UNCOMPRESSED_PUBLIC_KEY_LEN],
public_key_len: usize,
}
impl<C: Curve> SigningKey<C> {
fn new(private_key: C::PrivateKey) -> Result<Self, Error> {
let mut public_key = [0u8; MAX_UNCOMPRESSED_PUBLIC_KEY_LEN];
let public_key_len = private_key
.public_key_encode_uncompressed(&mut public_key)?
.len();
Ok(Self {
private_key,
public_key,
public_key_len,
})
}
pub(crate) fn generate() -> Result<Self, Error> {
let _entry = Entry::new_secret();
Self::new(C::generate_random_key(&mut SystemRandom)?)
}
pub(crate) fn from_pkcs8_der(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_secret();
pkcs8::Key::decode(
bytes,
&asn1::oid::id_ecPublicKey,
Some(asn1::Any::ObjectId(C::oid())),
)
.and_then(|k| Self::from_sec1_der(k.v1_private_key()?))
}
pub(crate) fn to_pkcs8_der<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], Error> {
let _entry = Entry::new_secret();
let mut sec1_buf = [0u8; MAX_SCALAR_LEN + MAX_UNCOMPRESSED_PUBLIC_KEY_LEN + 128];
let sec1 = self.to_sec1_der_detail(None, &mut sec1_buf)?;
pkcs8::Key::construct(
sec1,
None,
asn1::oid::id_ecPublicKey.clone(),
Some(asn1::Any::ObjectId(C::oid())),
)
.encode(output)
}
pub(crate) fn from_sec1_der(bytes: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_secret();
let ecpk = asn1::pkix::EcPrivateKey::from_bytes(bytes).map_err(KeyFormatError::Asn1)?;
match ecpk.parameters.inner() {
Some(x) if x == &C::oid() => {}
None => {}
_ => return Err(KeyFormatError::MismatchedSec1Curve.into()),
}
let key = Self::new(C::PrivateKey::from_bytes(ecpk.privateKey.as_octets())?)?;
if let Some(expected_public_key) = ecpk.publicKey.inner()
&& !key.is_public_key(expected_public_key.as_octets())
{
return Err(KeyFormatError::MismatchedSec1PublicKey.into());
}
Ok(key)
}
pub(crate) fn from_private_key_and_public_key(
private_key: &[u8],
public_key: &[u8],
) -> Result<Self, Error> {
let _entry = Entry::new_secret();
if private_key.len() != C::Scalar::LEN_BYTES {
return Err(KeyFormatError::WrongLength.into());
}
let key = Self::new(C::PrivateKey::from_bytes(private_key)?)?;
match key.is_public_key(public_key) {
true => Ok(key),
false => Err(KeyFormatError::MismatchedPublicKey.into()),
}
}
fn is_public_key(&self, encoded: &[u8]) -> bool {
let Some((_, xy)) = self.public_key_uncompressed().split_first() else {
return false;
};
let (x, y) = xy.split_at(xy.len() / 2);
match encoded.split_first() {
Some((&tag @ (0x02 | 0x03), compressed)) => {
compressed == x && y.last().is_some_and(|y| tag == 0x02 | (y & 1))
}
_ => encoded == self.public_key_uncompressed(),
}
}
pub(crate) fn to_scalar<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], Error> {
let _entry = Entry::new_secret();
self.private_key.encode(output)
}
pub(crate) fn public_key_uncompressed(&self) -> &[u8] {
&self.public_key[..self.public_key_len]
}
fn to_sec1_der_detail<'a>(
&self,
parameters: Option<asn1::ObjectId>,
output: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let mut encoded_private_key_buf = [0u8; MAX_SCALAR_LEN];
let encoded_private_key = self.private_key.encode(&mut encoded_private_key_buf)?;
let ecpk = asn1::pkix::EcPrivateKey {
version: asn1::pkix::EcPrivateKeyVer::ecPrivkeyVer1,
privateKey: asn1::OctetString::new(encoded_private_key),
parameters: match parameters {
Some(x) => x.into(),
None => asn1::Context::absent(),
},
publicKey: asn1::BitString::new(self.public_key_uncompressed()).into(),
};
let used = ecpk
.encode(&mut asn1::Encoder::new(output))
.map_err(|_| Error::WrongLength)?;
let output = output.get(..used).ok_or(Error::WrongLength)?;
ct::public_slice(output);
Ok(output)
}
pub(crate) fn to_spki_der<'a>(&self, output: &'a mut [u8]) -> Result<&'a [u8], Error> {
let spki = asn1::pkix::SubjectPublicKeyInfo {
algorithm: asn1::pkix::AlgorithmIdentifier {
algorithm: asn1::oid::id_ecPublicKey.clone(),
parameters: Some(asn1::Any::ObjectId(C::oid())),
},
subjectPublicKey: asn1::BitString::new(self.public_key_uncompressed()),
};
let len = spki
.encode(&mut asn1::Encoder::new(output))
.map_err(|_| Error::WrongLength)?;
Ok(&output[..len])
}
pub(crate) fn sign<'a, H: SignatureHash>(
&self,
message: &[u8],
signature: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let _entry = Entry::new_secret();
let mut random = [0u8; 16];
SystemRandom.fill(&mut random)?;
self.rfc6979_sign_with_random::<H>(message, &random, signature)
}
pub(crate) fn sign_asn1<'a, H: SignatureHash>(
&self,
message: &[u8],
asn1_signature: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let _entry = Entry::new_secret();
let mut fixed_sig = [0u8; MAX_SCALAR_LEN * 2];
let fixed_sig = self.sign::<H>(message, &mut fixed_sig)?;
Self::fixed_to_asn1(fixed_sig, asn1_signature)
}
fn fixed_to_asn1<'a>(
fixed_signature: &[u8],
asn1_signature: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let mut r = [0u8; MAX_SCALAR_LEN + 1];
let mut s = [0u8; MAX_SCALAR_LEN + 1];
let r = asn1::Integer::new_positive(&mut r, &fixed_signature[..C::Scalar::LEN_BYTES]);
let s = asn1::Integer::new_positive(&mut s, &fixed_signature[C::Scalar::LEN_BYTES..]);
let sig = asn1::pkix::EcdsaSigValue { r, s };
let sig_len = sig
.encode(&mut asn1::Encoder::new(asn1_signature))
.map_err(|_| Error::WrongLength)?;
Ok(&asn1_signature[..sig_len])
}
fn rfc6979_sign_with_random<'a, H: Hash>(
&self,
message: &[u8],
random: &[u8],
signature: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let output = signature
.get_mut(..C::Scalar::LEN_BYTES * 2)
.ok_or(Error::WrongLength)?;
let hash = H::hash(message);
let mut encoded_private_key_buf = [0u8; MAX_SCALAR_LEN];
let encoded_private_key = self.private_key.encode(&mut encoded_private_key_buf)?;
let e = hash_to_scalar::<C>(hash.as_ref())?;
let mut e_bytes = [0u8; MAX_SCALAR_LEN];
e.write_bytes(&mut e_bytes[..C::Scalar::LEN_BYTES]);
let mut rng = HmacDrbg::<H>::new(
encoded_private_key,
&e_bytes[..C::Scalar::LEN_BYTES],
random,
);
let (k, r) = loop {
let k = C::generate_random_key(&mut rng)?;
let x = k.public_key_x_scalar();
if !x.is_zero() {
break (k, x);
}
};
let s = self.private_key.raw_ecdsa_sign(&k, &e, &r);
r.write_bytes(&mut output[..C::Scalar::LEN_BYTES]);
s.write_bytes(&mut output[C::Scalar::LEN_BYTES..]);
Ok(&output[..C::Scalar::LEN_BYTES * 2])
}
}
pub(crate) struct VerifyingKey<C: Curve> {
public_key: C::PublicKey,
}
impl<C: Curve> Clone for VerifyingKey<C>
where
C::PublicKey: Clone,
{
fn clone(&self) -> Self {
Self {
public_key: self.public_key.clone(),
}
}
}
impl<C: Curve> VerifyingKey<C> {
pub(crate) fn from_x962_uncompressed(encoded: &[u8]) -> Result<Self, Error> {
let _entry = Entry::new_public();
C::PublicKey::from_x962_uncompressed(encoded).map(|public_key| Self { public_key })
}
pub(crate) fn verify<H: SignatureHash>(
&self,
message: &[u8],
signature: &[u8],
) -> Result<(), Error> {
let _entry = Entry::new_public();
if signature.len() != C::Scalar::LEN_BYTES * 2 {
return Err(Error::BadSignature);
}
let r = C::Scalar::from_bytes_checked(&signature[..C::Scalar::LEN_BYTES])
.map_err(|_| Error::BadSignature)?;
let s = C::Scalar::from_bytes_checked(&signature[C::Scalar::LEN_BYTES..])
.map_err(|_| Error::BadSignature)?;
let hash = H::hash(message);
let e = hash_to_scalar::<C>(hash.as_ref())?;
self.public_key.raw_ecdsa_verify(&r, &s, &e)
}
pub(crate) fn verify_asn1<H: SignatureHash>(
&self,
message: &[u8],
signature: &[u8],
) -> Result<(), Error> {
let _entry = Entry::new_public();
let sig =
asn1::pkix::EcdsaSigValue::from_bytes(signature).map_err(|_| Error::BadSignature)?;
if sig.r.is_negative() || sig.s.is_negative() {
return Err(Error::BadSignature);
}
let fixed = &mut [0u8; MAX_SCALAR_LEN * 2][..C::Scalar::LEN_BYTES * 2];
write_fixed(&mut fixed[..C::Scalar::LEN_BYTES], sig.r.as_ref())?;
write_fixed(&mut fixed[C::Scalar::LEN_BYTES..], sig.s.as_ref())?;
self.verify::<H>(message, fixed)
}
}
fn hash_to_scalar<C: Curve>(hash: &[u8]) -> Result<C::Scalar, Error> {
let hash = if hash.len() > C::Scalar::LEN_BYTES {
&hash[..C::Scalar::LEN_BYTES]
} else {
hash
};
Ok(C::Scalar::from_bytes_reduced(hash))
}
fn write_fixed(out: &mut [u8], mut value: &[u8]) -> Result<(), Error> {
if !value.is_empty() && value[0] == 0x00 {
value = &value[1..];
}
if out.len() < value.len() {
return Err(Error::BadSignature);
}
let (prefix, suffix) = out.split_at_mut(out.len() - value.len());
prefix.fill(0x00);
suffix.copy_from_slice(value);
Ok(())
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
use crate::high::curve::Curve;
use crate::high::{curve, hash};
use crate::mid::rng::SliceRandomSource;
use crate::test::*;
#[test]
fn smoke_test_loading_keys() {
check_sign_verify::<curve::P256>(
SigningKey::<curve::P256>::from_pkcs8_der(include_bytes!("ecdsa/secp256r1.pkcs8.der"))
.unwrap()
.private_key,
);
check_pairwise_pkcs8::<curve::P256>(include_bytes!("ecdsa/secp256r1.pkcs8.der"));
check_sign_verify::<curve::P256>(
SigningKey::<curve::P256>::from_sec1_der(include_bytes!("ecdsa/secp256r1.der"))
.unwrap()
.private_key,
);
check_pairwise_sec1::<curve::P256>(include_bytes!("ecdsa/secp256r1.der"));
assert_eq!(
SigningKey::<curve::P256>::from_sec1_der(include_bytes!("ecdsa/secp384r1.der")).err(),
Some(KeyFormatError::MismatchedSec1Curve.into()),
);
assert_eq!(
SigningKey::<curve::P256>::from_sec1_der(include_bytes!(
"ecdsa/secp256r1.wrong-public-key.der"
))
.err(),
Some(KeyFormatError::MismatchedSec1PublicKey.into()),
);
assert_eq!(
SigningKey::<curve::P256>::from_sec1_der(include_bytes!(
"ecdsa/secp256r1.wrong-version.der"
))
.err(),
Some(KeyFormatError::Asn1(asn1::Error::UnhandledEnumValue).into()),
);
check_sign_verify::<curve::P384>(
SigningKey::<curve::P384>::from_pkcs8_der(include_bytes!("ecdsa/secp384r1.pkcs8.der"))
.unwrap()
.private_key,
);
check_pairwise_pkcs8::<curve::P384>(include_bytes!("ecdsa/secp384r1.pkcs8.der"));
check_sign_verify::<curve::P384>(
SigningKey::<curve::P384>::from_sec1_der(include_bytes!("ecdsa/secp384r1.der"))
.unwrap()
.private_key,
);
check_pairwise_sec1::<curve::P384>(include_bytes!("ecdsa/secp384r1.der"));
assert_eq!(
SigningKey::<curve::P384>::from_sec1_der(include_bytes!("ecdsa/secp256r1.der")).err(),
Some(KeyFormatError::MismatchedSec1Curve.into()),
);
check_sign_verify::<curve::P521>(
SigningKey::<curve::P521>::from_pkcs8_der(include_bytes!("ecdsa/secp521r1.pkcs8.der"))
.unwrap()
.private_key,
);
check_pairwise_pkcs8::<curve::P521>(include_bytes!("ecdsa/secp521r1.pkcs8.der"));
check_sign_verify::<curve::P521>(
SigningKey::<curve::P521>::from_sec1_der(include_bytes!("ecdsa/secp521r1.der"))
.unwrap()
.private_key,
);
check_pairwise_sec1::<curve::P521>(include_bytes!("ecdsa/secp521r1.der"));
assert_eq!(
SigningKey::<curve::P521>::from_sec1_der(include_bytes!("ecdsa/secp384r1.der")).err(),
Some(KeyFormatError::MismatchedSec1Curve.into()),
);
}
#[test]
fn smoke_test_ecdsa_sign() {
let k = SigningKey::<curve::P256>::generate().unwrap();
check_sign_verify::<curve::P256>(k.private_key);
let k = SigningKey::<curve::P384>::generate().unwrap();
check_sign_verify::<curve::P384>(k.private_key);
let k = SigningKey::<curve::P521>::generate().unwrap();
check_sign_verify::<curve::P521>(k.private_key);
}
fn check_sign_verify<C: Curve>(private_key: C::PrivateKey) {
let mut public_key = [0u8; MAX_UNCOMPRESSED_PUBLIC_KEY_LEN];
let public_key = private_key
.public_key_encode_uncompressed(&mut public_key)
.unwrap();
let sk = SigningKey::<C>::new(private_key).unwrap();
let vk = VerifyingKey::<C> {
public_key: C::PublicKey::from_x962_uncompressed(public_key).unwrap(),
};
let mut buffer = [0u8; 256];
let message = b"hello world";
let signature = sk.sign::<hash::Sha256>(message, &mut buffer).unwrap();
vk.verify::<hash::Sha256>(message, signature).unwrap();
let signature = sk.sign::<hash::Sha384>(message, &mut buffer).unwrap();
vk.verify::<hash::Sha384>(message, signature).unwrap();
let signature = sk.sign::<hash::Sha512>(message, &mut buffer).unwrap();
vk.verify::<hash::Sha512>(message, signature).unwrap();
if std::env::var_os("SLOW_TESTS").is_some() {
for _ in 0..1024 {
let signature = sk.sign_asn1::<hash::Sha256>(message, &mut buffer).unwrap();
vk.verify_asn1::<hash::Sha256>(message, signature).unwrap();
}
}
let signature = sk.sign_asn1::<hash::Sha384>(message, &mut buffer).unwrap();
vk.verify_asn1::<hash::Sha384>(message, signature).unwrap();
let signature = sk.sign_asn1::<hash::Sha512>(message, &mut buffer).unwrap();
vk.verify_asn1::<hash::Sha512>(message, signature).unwrap();
assert_eq!(
sk.sign_asn1::<hash::Sha256>(message, &mut [0u8; 8]),
Err(Error::WrongLength)
);
assert_eq!(sk.to_spki_der(&mut [0u8; 8]), Err(Error::WrongLength));
}
fn check_pairwise_sec1<C: Curve>(sec1_der: &[u8]) {
let loaded = SigningKey::<C>::from_sec1_der(sec1_der).unwrap();
let mut buf = [0u8; 256];
assert!(buf.len() > sec1_der.len());
let encoded = loaded.to_sec1_der_detail(Some(C::oid()), &mut buf).unwrap();
assert_eq!(sec1_der, encoded);
assert_eq!(
loaded.to_sec1_der_detail(Some(C::oid()), &mut buf[..sec1_der.len() - 1]),
Err(Error::WrongLength)
);
}
fn check_pairwise_pkcs8<C: Curve>(pkcs8_der: &[u8]) {
let loaded = SigningKey::<C>::from_pkcs8_der(pkcs8_der).unwrap();
let mut buf = [0u8; 256];
assert!(buf.len() > pkcs8_der.len());
let encoded = loaded.to_pkcs8_der(&mut buf).unwrap();
assert_eq!(pkcs8_der, encoded);
assert_eq!(
loaded.to_pkcs8_der(&mut buf[..pkcs8_der.len() - 1]),
Err(Error::WrongLength)
);
}
#[test]
fn rejects_invalid_asn1_sigs() {
let private_key =
SigningKey::<curve::P256>::from_pkcs8_der(include_bytes!("ecdsa/secp256r1.pkcs8.der"))
.unwrap()
.private_key;
let mut public_key_buf = [0u8; 128];
let public_key_buf = private_key
.public_key_encode_uncompressed(&mut public_key_buf)
.unwrap();
let verify = VerifyingKey::<curve::P256> {
public_key: <curve::P256 as curve::Curve>::PublicKey::from_x962_uncompressed(
public_key_buf,
)
.unwrap(),
};
verify
.verify_asn1::<hash::Sha256>(
b"hello",
&[
0x30, 0x43, 0x02, 0x1f, 0x40, 0x1a, 0x29, 0x85, 0xde, 0xb3, 0x75, 0xd4, 0x81,
0x70, 0x6f, 0x6c, 0x26, 0xea, 0x70, 0x44, 0x30, 0xcd, 0xf5, 0x94, 0x9a, 0x3c,
0xe3, 0x44, 0x18, 0xe9, 0xd6, 0x73, 0xf9, 0xb0, 0xe6, 0x02, 0x20, 0x4d, 0xd1,
0x81, 0x3c, 0xa2, 0xaa, 0x52, 0xc4, 0xff, 0xe0, 0xd6, 0x02, 0xf4, 0xde, 0x4e,
0x30, 0x85, 0x2a, 0xfd, 0x31, 0x87, 0xa6, 0x0f, 0xe4, 0xbc, 0x6d, 0x40, 0xff,
0x6c, 0x31, 0xb1, 0x9b,
],
)
.unwrap();
assert_eq!(
verify
.verify_asn1::<hash::Sha256>(
b"hello",
&[
0x30, 0x44, 0x02, 0x20, 0x00, 0x40, 0x1a, 0x29, 0x85, 0xde, 0xb3, 0x75,
0xd4, 0x81, 0x70, 0x6f, 0x6c, 0x26, 0xea, 0x70, 0x44, 0x30, 0xcd, 0xf5,
0x94, 0x9a, 0x3c, 0xe3, 0x44, 0x18, 0xe9, 0xd6, 0x73, 0xf9, 0xb0, 0xe6,
0x02, 0x20, 0x4d, 0xd1, 0x81, 0x3c, 0xa2, 0xaa, 0x52, 0xc4, 0xff, 0xe0,
0xd6, 0x02, 0xf4, 0xde, 0x4e, 0x30, 0x85, 0x2a, 0xfd, 0x31, 0x87, 0xa6,
0x0f, 0xe4, 0xbc, 0x6d, 0x40, 0xff, 0x6c, 0x31, 0xb1, 0x9b,
],
)
.unwrap_err(),
Error::BadSignature,
);
}
#[test]
fn rfc6979_test_vectors() {
let mut rng = SliceRandomSource(b"\xC9\xAF\xA9\xD8\x45\xBA\x75\x16\x6B\x5C\x21\x57\x67\xB1\xD6\x93\x4E\x50\xC3\xDB\x36\xE8\x9B\x12\x7B\x8A\x62\x2B\x12\x0F\x67\x21");
let private_key = curve::P256::generate_random_key(&mut rng).unwrap();
let mut public_key = [0u8; 128];
let public_key = private_key
.public_key_encode_uncompressed(&mut public_key)
.unwrap();
let k = SigningKey::<curve::P256>::new(private_key).unwrap();
let v = VerifyingKey::<curve::P256> {
public_key: <curve::P256 as curve::Curve>::PublicKey::from_x962_uncompressed(
public_key,
)
.unwrap(),
};
let mut signature = [0u8; 64];
k.rfc6979_sign_with_random::<hash::Sha256>(b"sample", &[], &mut signature)
.unwrap();
assert_eq!(
signature,
[
0xef, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd, 0x11, 0x40, 0xdd, 0x9c, 0xd4, 0x5e,
0x81, 0xd6, 0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, 0xf9, 0x91, 0xc3, 0x4d, 0x0e, 0xa8,
0x4e, 0xaf, 0x37, 0x16, 0xf7, 0xcb, 0x1c, 0x94, 0x2d, 0x65, 0x7c, 0x41, 0xd4, 0x36,
0xc7, 0xa1, 0xb6, 0xe2, 0x9f, 0x65, 0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, 0x06,
0x4d, 0xc4, 0xab, 0x2f, 0x84, 0x3a, 0xcd, 0xa8,
]
);
v.verify::<hash::Sha256>(b"sample", &signature).unwrap();
let mut asn1_sig = [0u8; 128];
let asn1_sig = SigningKey::<curve::P256>::fixed_to_asn1(&signature, &mut asn1_sig).unwrap();
v.verify_asn1::<hash::Sha256>(b"sample", asn1_sig).unwrap();
k.rfc6979_sign_with_random::<hash::Sha256>(b"test", &[], &mut signature)
.unwrap();
assert_eq!(
signature,
[
0xf1, 0xab, 0xb0, 0x23, 0x51, 0x83, 0x51, 0xcd, 0x71, 0xd8, 0x81, 0x56, 0x7b, 0x1e,
0xa6, 0x63, 0xed, 0x3e, 0xfc, 0xf6, 0xc5, 0x13, 0x2b, 0x35, 0x4f, 0x28, 0xd3, 0xb0,
0xb7, 0xd3, 0x83, 0x67, 0x01, 0x9f, 0x41, 0x13, 0x74, 0x2a, 0x2b, 0x14, 0xbd, 0x25,
0x92, 0x6b, 0x49, 0xc6, 0x49, 0x15, 0x5f, 0x26, 0x7e, 0x60, 0xd3, 0x81, 0x4b, 0x4c,
0x0c, 0xc8, 0x42, 0x50, 0xe4, 0x6f, 0x00, 0x83,
]
);
v.verify::<hash::Sha256>(b"test", &signature).unwrap();
let mut asn1_sig = [0u8; 128];
let asn1_sig = SigningKey::<curve::P256>::fixed_to_asn1(&signature, &mut asn1_sig).unwrap();
v.verify_asn1::<hash::Sha256>(b"test", asn1_sig).unwrap();
k.rfc6979_sign_with_random::<hash::Sha512>(b"sample", &[], &mut signature)
.unwrap();
assert_eq!(
signature,
[
0x84, 0x96, 0xa6, 0x0b, 0x5e, 0x9b, 0x47, 0xc8, 0x25, 0x48, 0x88, 0x27, 0xe0, 0x49,
0x5b, 0x0e, 0x3f, 0xa1, 0x09, 0xec, 0x45, 0x68, 0xfd, 0x3f, 0x8d, 0x10, 0x97, 0x67,
0x8e, 0xb9, 0x7f, 0x00, 0x23, 0x62, 0xab, 0x1a, 0xdb, 0xe2, 0xb8, 0xad, 0xf9, 0xcb,
0x9e, 0xda, 0xb7, 0x40, 0xea, 0x60, 0x49, 0xc0, 0x28, 0x11, 0x4f, 0x24, 0x60, 0xf9,
0x65, 0x54, 0xf6, 0x1f, 0xae, 0x33, 0x02, 0xfe,
]
);
v.verify::<hash::Sha512>(b"sample", &signature).unwrap();
let mut asn1_sig = [0u8; 128];
let asn1_sig = SigningKey::<curve::P256>::fixed_to_asn1(&signature, &mut asn1_sig).unwrap();
v.verify_asn1::<hash::Sha512>(b"sample", asn1_sig).unwrap();
k.rfc6979_sign_with_random::<hash::Sha512>(b"test", &[], &mut signature)
.unwrap();
assert_eq!(
signature,
[
0x46, 0x1d, 0x93, 0xf3, 0x1b, 0x65, 0x40, 0x89, 0x47, 0x88, 0xfd, 0x20, 0x6c, 0x07,
0xcf, 0xa0, 0xcc, 0x35, 0xf4, 0x6f, 0xa3, 0xc9, 0x18, 0x16, 0xff, 0xf1, 0x04, 0x0a,
0xd1, 0x58, 0x1a, 0x04, 0x39, 0xaf, 0x9f, 0x15, 0xde, 0x0d, 0xb8, 0xd9, 0x7e, 0x72,
0x71, 0x9c, 0x74, 0x82, 0x0d, 0x30, 0x4c, 0xe5, 0x22, 0x6e, 0x32, 0xde, 0xda, 0xe6,
0x75, 0x19, 0xe8, 0x40, 0xd1, 0x19, 0x4e, 0x55,
]
);
v.verify::<hash::Sha512>(b"test", &signature).unwrap();
let mut asn1_sig = [0u8; 128];
let asn1_sig = SigningKey::<curve::P256>::fixed_to_asn1(&signature, &mut asn1_sig).unwrap();
v.verify_asn1::<hash::Sha512>(b"test", asn1_sig).unwrap();
k.rfc6979_sign_with_random::<hash::Sha256>(b"wv[vnX", &[], &mut signature)
.unwrap();
assert_eq!(
signature,
[
0xef, 0xd9, 0x07, 0x3b, 0x65, 0x2e, 0x76, 0xda, 0x1b, 0x5a, 0x01, 0x9c, 0x0e, 0x4a,
0x2e, 0x3f, 0xa5, 0x29, 0xb0, 0x35, 0xa6, 0xab, 0xb9, 0x1e, 0xf6, 0x7f, 0x0e, 0xd7,
0xa1, 0xf2, 0x12, 0x34, 0x3d, 0xb4, 0x70, 0x6c, 0x9d, 0x9f, 0x4a, 0x4f, 0xe1, 0x3b,
0xb5, 0xe0, 0x8e, 0xf0, 0xfa, 0xb5, 0x3a, 0x57, 0xdb, 0xab, 0x20, 0x61, 0xc8, 0x3a,
0x35, 0xfa, 0x41, 0x1c, 0x68, 0xd2, 0xba, 0x33
]
);
v.verify::<hash::Sha256>(b"wv[vnX", &signature).unwrap();
}
#[test]
fn rfc6979_p521_test_vectors() {
let private_key = <curve::P521 as curve::Curve>::PrivateKey::from_bytes(&hex::decode("00fad06daa62ba3b25d2fb40133da757205de67f5bb0018fee8c86e1b68c7e75caa896eb32f1f47c70855836a6d16fcc1466f6d8fbec67db89ec0c08b0e996b83538").unwrap()).unwrap();
let mut public_key = [0u8; MAX_UNCOMPRESSED_PUBLIC_KEY_LEN];
let public_key = private_key
.public_key_encode_uncompressed(&mut public_key)
.unwrap();
let v = VerifyingKey::<curve::P521> {
public_key: <curve::P521 as curve::Curve>::PublicKey::from_x962_uncompressed(
public_key,
)
.unwrap(),
};
let k = SigningKey::<curve::P521>::new(private_key).unwrap();
let mut signature = [0u8; 132];
k.rfc6979_sign_with_random::<hash::Sha256>(b"sample", &[], &mut signature)
.unwrap();
assert_eq!(
hex::encode(signature),
"01511bb4d675114fe266fc4372b87682baecc01d3cc62cf2303c92b3526012659d16876e25c7c1e57648f23b73564d67f61c6f14d527d54972810421e7d87589e1a7004a171143a83163d6df460aaf61522695f207a58b95c0644d87e52aa1a347916e4f7a72930b1bc06dbe22ce3f58264afd23704cbb63b29b931f7de6c9d949a7ecfc"
);
v.verify::<hash::Sha256>(b"sample", &signature).unwrap();
k.rfc6979_sign_with_random::<hash::Sha512>(b"sample", &[], &mut signature)
.unwrap();
assert_eq!(
hex::encode(signature),
"00c328fafcbd79dd77850370c46325d987cb525569fb63c5d3bc53950e6d4c5f174e25a1ee9017b5d450606add152b534931d7d4e8455cc91f9b15bf05ec36e377fa00617cce7cf5064806c467f678d3b4080d6f1cc50af26ca209417308281b68af282623eaa63e5b5c0723d8b8c37ff0777b1a20f8ccb1dccc43997f1ee0e44da4a67a"
);
v.verify::<hash::Sha512>(b"sample", &signature).unwrap();
let mut asn1_sig = [0u8; 160];
let asn1_sig = SigningKey::<curve::P521>::fixed_to_asn1(&signature, &mut asn1_sig).unwrap();
v.verify_asn1::<hash::Sha512>(b"sample", asn1_sig).unwrap();
k.rfc6979_sign_with_random::<hash::Sha256>(b"test", &[], &mut signature)
.unwrap();
assert_eq!(
hex::encode(signature),
"000e871c4a14f993c6c7369501900c4bc1e9c7b0b4ba44e04868b30b41d8071042eb28c4c250411d0ce08cd197e4188ea4876f279f90b3d8d74a3c76e6f1e4656aa800cd52dbaa33b063c3a6cd8058a1fb0a46a4754b034fcc644766ca14da8ca5ca9fde00e88c1ad60ccba759025299079d7a427ec3cc5b619bfbc828e7769bcd694e86"
);
v.verify::<hash::Sha256>(b"test", &signature).unwrap();
k.rfc6979_sign_with_random::<hash::Sha512>(b"test", &[], &mut signature)
.unwrap();
assert_eq!(
hex::encode(signature),
"013e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d08725f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945babd47ee6d01fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b155e2de4dce3"
);
v.verify::<hash::Sha512>(b"test", &signature).unwrap();
}
#[test]
fn cavp_sigver() {
#[derive(Debug, Default)]
struct State {
param: String,
msg: Vec<u8>,
px: Vec<u8>,
py: Vec<u8>,
r: Vec<u8>,
s: Vec<u8>,
}
impl CavpSink for State {
fn on_meta(&mut self, meta: &str) {
self.param = meta.to_string();
}
fn on_value(&mut self, name: &str, value: Value<'_>) {
match name {
"Msg" => self.msg = value.bytes(),
"Qx" => self.px = value.bytes(),
"Qy" => self.py = value.bytes(),
"R" => self.r = value.bytes(),
"S" => self.s = value.bytes(),
"Result" => {
match self.param.as_ref() {
"P-256,SHA-256" | "P-256,SHA-384" | "P-256,SHA-512" => {
pad(&mut self.px, 32);
pad(&mut self.py, 32);
pad(&mut self.r, 32);
pad(&mut self.s, 32);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);
let mut sig = vec![];
sig.extend_from_slice(&self.r);
sig.extend_from_slice(&self.s);
let vkey =
VerifyingKey::<curve::P256>::from_x962_uncompressed(&point)
.unwrap();
let result = match self.param.as_ref() {
"P-256,SHA-256" => vkey.verify::<hash::Sha256>(&self.msg, &sig),
"P-256,SHA-384" => vkey.verify::<hash::Sha384>(&self.msg, &sig),
"P-256,SHA-512" => vkey.verify::<hash::Sha512>(&self.msg, &sig),
_ => todo!("unhandled param"),
};
match value.str().chars().next() {
Some('F') => {
result.unwrap_err();
}
Some('P') => {
result.unwrap();
}
_ => todo!("unrecognised Result {:?}", value.str()),
};
println!("PASS: {}", value.str());
}
"P-384,SHA-256" | "P-384,SHA-384" | "P-384,SHA-512" => {
pad(&mut self.px, 48);
pad(&mut self.py, 48);
pad(&mut self.r, 48);
pad(&mut self.s, 48);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);
let mut sig = vec![];
sig.extend_from_slice(&self.r);
sig.extend_from_slice(&self.s);
let vkey =
VerifyingKey::<curve::P384>::from_x962_uncompressed(&point)
.unwrap();
let result = match self.param.as_ref() {
"P-384,SHA-256" => vkey.verify::<hash::Sha256>(&self.msg, &sig),
"P-384,SHA-384" => vkey.verify::<hash::Sha384>(&self.msg, &sig),
"P-384,SHA-512" => vkey.verify::<hash::Sha512>(&self.msg, &sig),
_ => todo!("unhandled param"),
};
match value.str().chars().next() {
Some('F') => {
result.unwrap_err();
}
Some('P') => {
result.unwrap();
}
_ => todo!("unrecognised Result {:?}", value.str()),
};
println!("PASS: {}", value.str());
}
"P-521,SHA-256" | "P-521,SHA-384" | "P-521,SHA-512" => {
pad(&mut self.px, 66);
pad(&mut self.py, 66);
pad(&mut self.r, 66);
pad(&mut self.s, 66);
let mut point = vec![0x04];
point.extend_from_slice(&self.px);
point.extend_from_slice(&self.py);
let mut sig = vec![];
sig.extend_from_slice(&self.r);
sig.extend_from_slice(&self.s);
let vkey =
VerifyingKey::<curve::P521>::from_x962_uncompressed(&point)
.unwrap();
let result = match self.param.as_ref() {
"P-521,SHA-256" => vkey.verify::<hash::Sha256>(&self.msg, &sig),
"P-521,SHA-384" => vkey.verify::<hash::Sha384>(&self.msg, &sig),
"P-521,SHA-512" => vkey.verify::<hash::Sha512>(&self.msg, &sig),
_ => todo!("unhandled param"),
};
match value.str().chars().next() {
Some('F') => {
result.unwrap_err();
}
Some('P') => {
result.unwrap();
}
_ => todo!("unrecognised Result {:?}", value.str()),
};
println!("PASS: {}", value.str());
}
_ => {
println!("unhandled params {}", self.param);
}
};
}
_ => {}
}
}
}
process_cavp("../thirdparty/cavp/ecdsa/SigVer.rsp", &mut State::default());
}
fn pad(v: &mut Vec<u8>, l: usize) {
while v.len() < l {
v.insert(0, 0x00);
}
}
}