Skip to content

Commit

Permalink
use signer and verifier traits
Browse files Browse the repository at this point in the history
  • Loading branch information
junkurihara committed Jan 11, 2024
1 parent d1beec7 commit 9ab5b31
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 56 deletions.
49 changes: 35 additions & 14 deletions src/crypto/asymmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
match &self {
Self::EcdsaP256Sha256(sk) => {
let sk = ecdsa::SigningKey::from(sk);
let mut digest = Sha256::default();
let mut digest = <Sha256 as Digest>::new();
digest.update(data);
let sig: ecdsa::Signature<NistP256> = 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 = <Sha384 as Digest>::new();
digest.update(data);
let sig: ecdsa::Signature<NistP384> = sk.sign_digest(digest);
Ok(sig.to_bytes().to_vec())
Expand All @@ -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()
}
}

Expand Down Expand Up @@ -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::<NistP256>::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 = <Sha256 as Digest>::new();
digest.update(data);
vk.verify_digest(digest, &signature)
.map_err(|e| anyhow!("Error verifying signature: {}", e))
Expand All @@ -199,7 +218,7 @@ impl PublicKey {
let signature = ecdsa::Signature::<NistP384>::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 = <Sha384 as Digest>::new();
digest.update(data);
vk.verify_digest(digest, &signature)
.map_err(|e| anyhow!("Error verifying signature: {}", e))
Expand All @@ -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 {
Expand Down Expand Up @@ -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";
Expand All @@ -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());
Expand Down
16 changes: 13 additions & 3 deletions src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<u8>>;
fn key_id(&self) -> String;
}

/// Verifier trait
pub trait Verifier {
fn verify(&self, data: &[u8], signature: &[u8]) -> anyhow::Result<()>;
fn key_id(&self) -> String;
}
54 changes: 23 additions & 31 deletions src/crypto/symmetric.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,38 @@
use super::MINIMUM_SYMMETRIC_KEY_LENGTH;
use anyhow::Result;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};

type HmacSha256 = hmac::Hmac<sha2::Sha256>;

/* -------------------------------- */
/// 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<u8>),
}

/// Symmetric key
pub struct SymmetricKey {
/// Key value
pub inner: Vec<u8>,
}

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<Vec<u8>> {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
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;
<Self as 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(())
Expand All @@ -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 = <Sha256 as Digest>::new();
hasher.update(&key.inner);
hasher.update(&key);
let hash = hasher.finalize();
general_purpose::URL_SAFE_NO_PAD.encode(hash)
}
Expand All @@ -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();
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod crypto;
use crypto::{PublicKey, SecretKey};
use crypto::{PublicKey, SecretKey, Signer, Verifier};
pub fn test() {
println!("Hello, world!");
}
Expand Down
8 changes: 1 addition & 7 deletions src/signer.rs
Original file line number Diff line number Diff line change
@@ -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?
Expand Down

0 comments on commit 9ab5b31

Please sign in to comment.