use super::error::DecodingError;
use core::cmp;
use core::fmt;
use core::hash;
use p256::{
ecdsa::{
signature::{Signer, Verifier},
Signature, SigningKey, VerifyingKey,
},
EncodedPoint,
};
use void::Void;
#[derive(Clone)]
pub struct Keypair {
secret: SecretKey,
public: PublicKey,
}
impl Keypair {
pub fn generate() -> Keypair {
Keypair::from(SecretKey::generate())
}
pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
self.secret.sign(msg)
}
pub fn public(&self) -> &PublicKey {
&self.public
}
pub fn secret(&self) -> &SecretKey {
&self.secret
}
}
impl fmt::Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Keypair")
.field("public", &self.public())
.finish()
}
}
impl From<SecretKey> for Keypair {
fn from(secret: SecretKey) -> Keypair {
let public = PublicKey(VerifyingKey::from(&secret.0));
Keypair { secret, public }
}
}
impl From<Keypair> for SecretKey {
fn from(kp: Keypair) -> SecretKey {
kp.secret
}
}
#[derive(Clone)]
pub struct SecretKey(SigningKey);
impl SecretKey {
pub fn generate() -> SecretKey {
SecretKey(SigningKey::random(&mut rand::thread_rng()))
}
pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
let signature: p256::ecdsa::DerSignature = self.0.sign(msg);
signature.as_bytes().to_owned()
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
#[deprecated(
since = "0.2.0",
note = "This method name does not follow Rust naming conventions, use `SecretKey::try_from_bytes` instead"
)]
pub fn from_bytes(buf: &[u8]) -> Result<Self, DecodingError> {
Self::try_from_bytes(buf)
}
pub fn try_from_bytes(buf: impl AsRef<[u8]>) -> Result<SecretKey, DecodingError> {
SigningKey::from_bytes(buf.as_ref())
.map_err(|err| DecodingError::failed_to_parse("ecdsa p256 secret key", err))
.map(SecretKey)
}
}
impl fmt::Debug for SecretKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SecretKey")
}
}
#[derive(Clone, Eq, PartialOrd, Ord)]
pub struct PublicKey(VerifyingKey);
impl PublicKey {
pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
let sig = match Signature::from_der(sig) {
Ok(sig) => sig,
Err(_) => return false,
};
self.0.verify(msg, &sig).is_ok()
}
#[deprecated(
since = "0.2.0",
note = "This method name does not follow Rust naming conventions, use `PublicKey::try_from_bytes` instead."
)]
pub fn from_bytes(k: &[u8]) -> Result<PublicKey, DecodingError> {
Self::try_from_bytes(k)
}
pub fn try_from_bytes(k: &[u8]) -> Result<PublicKey, DecodingError> {
let enc_pt = EncodedPoint::from_bytes(k)
.map_err(|e| DecodingError::failed_to_parse("ecdsa p256 encoded point", e))?;
VerifyingKey::from_encoded_point(&enc_pt)
.map_err(|err| DecodingError::failed_to_parse("ecdsa p256 public key", err))
.map(PublicKey)
}
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_encoded_point(false).as_bytes().to_owned()
}
pub fn encode_der(&self) -> Vec<u8> {
let buf = self.to_bytes();
Self::add_asn1_header(&buf)
}
#[deprecated(
since = "0.2.0",
note = "This method name does not follow Rust naming conventions, use `PublicKey::try_decode_der` instead."
)]
pub fn decode_der(k: &[u8]) -> Result<PublicKey, DecodingError> {
Self::try_decode_der(k)
}
pub fn try_decode_der(k: &[u8]) -> Result<PublicKey, DecodingError> {
let buf = Self::del_asn1_header(k).ok_or_else(|| {
DecodingError::failed_to_parse::<Void, _>("ASN.1-encoded ecdsa p256 public key", None)
})?;
Self::try_from_bytes(buf)
}
const EC_PUBLIC_KEY_OID: [u8; 9] = [0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
const SECP_256_R1_OID: [u8; 10] = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
fn add_asn1_header(key_buf: &[u8]) -> Vec<u8> {
let mut asn1_buf = vec![
0x30,
0x00,
0x30,
(Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len()) as u8,
];
asn1_buf.extend_from_slice(&Self::EC_PUBLIC_KEY_OID);
asn1_buf.extend_from_slice(&Self::SECP_256_R1_OID);
asn1_buf.extend_from_slice(&[0x03, (key_buf.len() + 1) as u8, 0x00]);
asn1_buf.extend_from_slice(key_buf);
asn1_buf[1] = (asn1_buf.len() - 2) as u8;
asn1_buf
}
fn del_asn1_header(asn1_buf: &[u8]) -> Option<&[u8]> {
let oids_len = Self::EC_PUBLIC_KEY_OID.len() + Self::SECP_256_R1_OID.len();
let asn1_head = asn1_buf.get(..4)?;
let oids_buf = asn1_buf.get(4..4 + oids_len)?;
let bitstr_head = asn1_buf.get(4 + oids_len..4 + oids_len + 3)?;
if asn1_head[0] != 0x30
|| asn1_head[2] != 0x30
|| asn1_head[3] as usize != oids_len
|| oids_buf[..Self::EC_PUBLIC_KEY_OID.len()] != Self::EC_PUBLIC_KEY_OID
|| oids_buf[Self::EC_PUBLIC_KEY_OID.len()..] != Self::SECP_256_R1_OID
|| bitstr_head[0] != 0x03
|| bitstr_head[2] != 0x00
{
return None;
}
let key_len = bitstr_head[1].checked_sub(1)? as usize;
let key_buf = asn1_buf.get(4 + oids_len + 3..4 + oids_len + 3 + key_len)?;
Some(key_buf)
}
}
impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PublicKey(asn.1 uncompressed): ")?;
for byte in &self.encode_der() {
write!(f, "{byte:x}")?;
}
Ok(())
}
}
impl cmp::PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes().eq(&other.to_bytes())
}
}
impl hash::Hash for PublicKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.to_bytes().hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sign_verify() {
let pair = Keypair::generate();
let pk = pair.public();
let msg = "hello world".as_bytes();
let sig = pair.sign(msg);
assert!(pk.verify(msg, &sig));
let mut invalid_sig = sig.clone();
invalid_sig[3..6].copy_from_slice(&[10, 23, 42]);
assert!(!pk.verify(msg, &invalid_sig));
let invalid_msg = "h3ll0 w0rld".as_bytes();
assert!(!pk.verify(invalid_msg, &sig));
}
}