diff --git a/src/crypto/asymmetric.rs b/src/crypto/asymmetric.rs index fa142bc..ed3a63c 100644 --- a/src/crypto/asymmetric.rs +++ b/src/crypto/asymmetric.rs @@ -90,19 +90,30 @@ impl SecretKey { Self::from_der(doc.as_bytes()) } + /// Get public key from secret key + pub fn public_key(&self) -> PublicKey { + match &self { + Self::EcdsaP256Sha256(key) => PublicKey::EcdsaP256Sha256(key.public_key()), + Self::EcdsaP384Sha384(key) => PublicKey::EcdsaP384Sha384(key.public_key()), + Self::Ed25519(key) => PublicKey::Ed25519(key.public_key()), + } + } +} + +impl super::Signer for SecretKey { /// Sign data - pub fn sign(&self, data: &[u8]) -> Result> { + fn sign(&self, data: &[u8]) -> Result> { match &self { Self::EcdsaP256Sha256(sk) => { let sk = ecdsa::SigningKey::from(sk); - let mut digest = Sha256::default(); + let mut digest = ::new(); digest.update(data); let sig: ecdsa::Signature = sk.sign_digest(digest); Ok(sig.to_bytes().to_vec()) } Self::EcdsaP384Sha384(sk) => { let sk = ecdsa::SigningKey::from(sk); - let mut digest = Sha384::default(); + let mut digest = ::new(); digest.update(data); let sig: ecdsa::Signature = sk.sign_digest(digest); Ok(sig.to_bytes().to_vec()) @@ -114,13 +125,19 @@ impl SecretKey { } } - /// Get public key from secret key - pub fn public_key(&self) -> PublicKey { - match &self { - Self::EcdsaP256Sha256(key) => PublicKey::EcdsaP256Sha256(key.public_key()), - Self::EcdsaP384Sha384(key) => PublicKey::EcdsaP384Sha384(key.public_key()), - Self::Ed25519(key) => PublicKey::Ed25519(key.public_key()), - } + fn key_id(&self) -> String { + use super::Verifier; + self.public_key().key_id() + } +} + +impl super::Verifier for SecretKey { + fn verify(&self, data: &[u8], signature: &[u8]) -> Result<()> { + self.public_key().verify(data, signature) + } + + fn key_id(&self) -> String { + self.public_key().key_id() } } @@ -182,15 +199,17 @@ impl PublicKey { _ => bail!("Unsupported algorithm that supports PEM format keys"), } } +} +impl super::Verifier for PublicKey { /// Verify signature - pub fn verify(&self, data: &[u8], signature: &[u8]) -> Result<()> { + fn verify(&self, data: &[u8], signature: &[u8]) -> Result<()> { match self { Self::EcdsaP256Sha256(pk) => { let signature = ecdsa::Signature::::from_bytes(signature.into()) .map_err(|e| anyhow!("Error decoding signature: {}", e))?; let vk = ecdsa::VerifyingKey::from(pk); - let mut digest = Sha256::default(); + let mut digest = ::new(); digest.update(data); vk.verify_digest(digest, &signature) .map_err(|e| anyhow!("Error verifying signature: {}", e)) @@ -199,7 +218,7 @@ impl PublicKey { let signature = ecdsa::Signature::::from_bytes(signature.into()) .map_err(|e| anyhow!("Error decoding signature: {}", e))?; let vk = ecdsa::VerifyingKey::from(pk); - let mut digest = Sha384::default(); + let mut digest = ::new(); digest.update(data); vk.verify_digest(digest, &signature) .map_err(|e| anyhow!("Error verifying signature: {}", e)) @@ -214,7 +233,7 @@ impl PublicKey { } /// Create key id - pub fn key_id(&self) -> String { + fn key_id(&self) -> String { use base64::{engine::general_purpose, Engine as _}; let bytes = match self { @@ -288,6 +307,7 @@ MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0= #[test] fn test_sign_verify() { + use super::super::{Signer, Verifier}; let sk = SecretKey::from_pem(P256_SECERT_KEY).unwrap(); let pk = PublicKey::from_pem(P256_PUBLIC_KEY).unwrap(); let data = b"hello world"; @@ -312,6 +332,7 @@ MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0= #[test] fn test_kid() -> Result<()> { + use super::super::Verifier; let sk = SecretKey::from_pem(P256_SECERT_KEY)?; let pk = PublicKey::from_pem(P256_PUBLIC_KEY)?; assert_eq!(sk.public_key().key_id(), pk.key_id()); diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index e6978c0..e9a3ce5 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -1,7 +1,17 @@ mod asymmetric; mod symmetric; -pub(crate) const MINIMUM_SYMMETRIC_KEY_LENGTH: usize = 32; - pub use asymmetric::{PublicKey, SecretKey}; -pub use symmetric::SymmetricKey; +pub use symmetric::SharedKey; + +/// Signer trait +pub trait Signer { + fn sign(&self, data: &[u8]) -> anyhow::Result>; + fn key_id(&self) -> String; +} + +/// Verifier trait +pub trait Verifier { + fn verify(&self, data: &[u8], signature: &[u8]) -> anyhow::Result<()>; + fn key_id(&self) -> String; +} diff --git a/src/crypto/symmetric.rs b/src/crypto/symmetric.rs index e3fd411..950f565 100644 --- a/src/crypto/symmetric.rs +++ b/src/crypto/symmetric.rs @@ -1,4 +1,3 @@ -use super::MINIMUM_SYMMETRIC_KEY_LENGTH; use anyhow::Result; use hmac::{Hmac, Mac}; use sha2::{Digest, Sha256}; @@ -6,41 +5,34 @@ use sha2::{Digest, Sha256}; type HmacSha256 = hmac::Hmac; /* -------------------------------- */ -/// Secret key for http signature +/// Shared key for http signature /// Name conventions follow [the IETF draft](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-6.2.2) -pub enum SecretKey { +pub enum SharedKey { /// hmac-sha256 - HmacSha256(SymmetricKey), + HmacSha256(Vec), } -/// Symmetric key -pub struct SymmetricKey { - /// Key value - pub inner: Vec, -} - -impl From<&[u8]> for SymmetricKey { - fn from(value: &[u8]) -> Self { - if value.len() < MINIMUM_SYMMETRIC_KEY_LENGTH { - panic!("Key length is too short (minimum: {})", MINIMUM_SYMMETRIC_KEY_LENGTH); - } - SymmetricKey { inner: value.to_vec() } - } -} - -impl SecretKey { +impl super::Signer for SharedKey { /// Sign the data - pub fn sign(&self, data: &[u8]) -> Result> { + fn sign(&self, data: &[u8]) -> Result> { match self { - SecretKey::HmacSha256(key) => { - let mut mac = HmacSha256::new_from_slice(&key.inner).unwrap(); + SharedKey::HmacSha256(key) => { + let mut mac = HmacSha256::new_from_slice(key).unwrap(); mac.update(data); Ok(mac.finalize().into_bytes().to_vec()) } } } + /// Get the key id + fn key_id(&self) -> String { + use super::Verifier; + ::key_id(self) + } +} +impl super::Verifier for SharedKey { /// Verify the mac - pub fn verify(&self, data: &[u8], expected_mac: &[u8]) -> Result<()> { + fn verify(&self, data: &[u8], expected_mac: &[u8]) -> Result<()> { + use super::Signer; let calcurated_mac = self.sign(data)?; if calcurated_mac == expected_mac { Ok(()) @@ -50,12 +42,12 @@ impl SecretKey { } /// Get the key id - pub fn key_id(&self) -> String { + fn key_id(&self) -> String { use base64::{engine::general_purpose, Engine as _}; match self { - SecretKey::HmacSha256(key) => { + SharedKey::HmacSha256(key) => { let mut hasher = ::new(); - hasher.update(&key.inner); + hasher.update(&key); let hash = hasher.finalize(); general_purpose::URL_SAFE_NO_PAD.encode(hash) } @@ -69,11 +61,11 @@ mod tests { #[test] fn symmetric_key_works() { + use super::super::{Signer, Verifier}; let inner = b"01234567890123456789012345678901"; - let key = SymmetricKey::from(inner.as_slice()); - let sk = SecretKey::HmacSha256(key); + let key = SharedKey::HmacSha256(inner.to_vec()); let data = b"hello"; - let signature = sk.sign(data).unwrap(); - sk.verify(data, &signature).unwrap(); + let signature = key.sign(data).unwrap(); + key.verify(data, &signature).unwrap(); } } diff --git a/src/lib.rs b/src/lib.rs index e043b3f..3f84c8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ mod crypto; -use crypto::{PublicKey, SecretKey}; +use crypto::{PublicKey, SecretKey, Signer, Verifier}; pub fn test() { println!("Hello, world!"); } diff --git a/src/signer.rs b/src/signer.rs index 968ca9a..9d0ef7b 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -1,10 +1,4 @@ -// image: -// let signer = HttpSignatureSignerBuilder::default() -// .secret_key(SecretKey::HmacSha256(SymmetricKey::from(b"secret"))) -// .xxx() -// .yyy() -// .build(); -// or +// API design: // let signature_params = SignatureParamsBuilder::default() // .created(1618884473) // .key_id("test-key-ed25519") // Should key_id be set at signer builder?