use base64::{engine::general_purpose, Engine as _};
use p256::{
ecdsa::{signature::Signer, signature::Verifier, Signature, SigningKey, VerifyingKey},
pkcs8::{spki, DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
PublicKey, SecretKey,
};
use rand::rngs::OsRng;
use sha2::{Digest, Sha256};
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug)]
pub enum Error {
Ecdsa(String),
Pkcs8(p256::pkcs8::Error),
Spki(spki::Error),
Base64(base64::DecodeError),
Signature(String),
InvalidKeyFormat,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Ecdsa(e) => write!(f, "ECDSA error: {}", e),
Error::Pkcs8(e) => write!(f, "PKCS#8 error: {}", e),
Error::Spki(e) => write!(f, "SPKI error: {}", e),
Error::Base64(e) => write!(f, "Base64 error: {}", e),
Error::Signature(e) => write!(f, "Signature error: {}", e),
Error::InvalidKeyFormat => write!(f, "Invalid key format"),
}
}
}
impl StdError for Error {}
impl From<p256::pkcs8::Error> for Error {
fn from(err: p256::pkcs8::Error) -> Self {
Error::Pkcs8(err)
}
}
impl From<spki::Error> for Error {
fn from(err: spki::Error) -> Self {
Error::Spki(err)
}
}
impl From<base64::DecodeError> for Error {
fn from(err: base64::DecodeError) -> Self {
Error::Base64(err)
}
}
#[derive(Debug, Clone)]
pub struct KeyPair {
pub private_key_pem: String,
pub public_key_pem: String,
}
pub fn generate_key_pair() -> Result<KeyPair, Error> {
let mut rng = OsRng;
let secret_key = SecretKey::random(&mut rng);
let public_key = secret_key.public_key();
let private_key_pem = secret_key
.to_pkcs8_pem(p256::pkcs8::LineEnding::LF)?
.to_string();
let public_key_pem = public_key.to_public_key_pem(p256::pkcs8::LineEnding::LF)?;
Ok(KeyPair {
private_key_pem,
public_key_pem,
})
}
pub fn sign_data(private_key_pem: &str, data: &[u8]) -> Result<String, Error> {
let secret_key = SecretKey::from_pkcs8_pem(private_key_pem)?;
let signing_key = SigningKey::from(secret_key);
let signature: p256::ecdsa::Signature = signing_key.sign(data);
Ok(general_purpose::STANDARD.encode(signature.to_der()))
}
pub fn verify_signature(public_key_pem: &str, data: &[u8], signature: &str) -> Result<bool, Error> {
let public_key = PublicKey::from_public_key_pem(public_key_pem)?;
let verifying_key = VerifyingKey::from(public_key);
let signature_bytes = general_purpose::STANDARD.decode(signature)?;
let signature_obj =
Signature::from_der(&signature_bytes).map_err(|_| Error::InvalidKeyFormat)?;
match verifying_key.verify(data, &signature_obj) {
Ok(()) => Ok(true),
Err(_) => Ok(false),
}
}
pub fn calculate_key_id(public_key_pem: &str) -> Result<String, Error> {
let public_key = PublicKey::from_public_key_pem(public_key_pem)?;
let der_bytes = public_key.to_public_key_der()?;
let mut hasher = Sha256::new();
hasher.update(der_bytes.as_bytes());
let hash = hasher.finalize();
Ok(format!("sha256:{}", hex::encode(hash)))
}
pub struct KeyManager;
impl KeyManager {
pub fn generate_keypair() -> Result<(SecretKey, PublicKey), Error> {
let mut rng = OsRng;
let secret_key = SecretKey::random(&mut rng);
let public_key = secret_key.public_key();
Ok((secret_key, public_key))
}
pub fn export_private_key_pem(private_key: &SecretKey) -> Result<String, Error> {
Ok(private_key
.to_pkcs8_pem(p256::pkcs8::LineEnding::LF)?
.to_string())
}
pub fn export_public_key_pem(public_key: &PublicKey) -> Result<String, Error> {
Ok(public_key.to_public_key_pem(p256::pkcs8::LineEnding::LF)?)
}
pub fn load_private_key_pem(pem_data: &str) -> Result<SecretKey, Error> {
Ok(SecretKey::from_pkcs8_pem(pem_data)?)
}
pub fn load_public_key_pem(pem_data: &str) -> Result<PublicKey, Error> {
Ok(PublicKey::from_public_key_pem(pem_data)?)
}
pub fn calculate_key_fingerprint(public_key: &PublicKey) -> Result<String, Error> {
let der_bytes = public_key.to_public_key_der()?;
let mut hasher = Sha256::new();
hasher.update(der_bytes.as_bytes());
let hash = hasher.finalize();
Ok(format!("sha256:{}", hex::encode(hash)))
}
pub fn calculate_key_fingerprint_from_pem(public_key_pem: &str) -> Result<String, Error> {
let public_key = Self::load_public_key_pem(public_key_pem)?;
Self::calculate_key_fingerprint(&public_key)
}
}
pub struct SignatureManager;
impl SignatureManager {
pub fn sign_hash(hash_bytes: &[u8], private_key: &SecretKey) -> Result<String, Error> {
let signing_key = SigningKey::from(private_key.clone());
let signature: p256::ecdsa::Signature = signing_key.sign(hash_bytes);
Ok(general_purpose::STANDARD.encode(signature.to_der()))
}
pub fn verify_signature(
hash_bytes: &[u8],
signature_b64: &str,
public_key: &PublicKey,
) -> Result<bool, Error> {
let verifying_key = VerifyingKey::from(*public_key);
let signature_bytes = general_purpose::STANDARD.decode(signature_b64)?;
let signature_obj =
Signature::from_der(&signature_bytes).map_err(|_| Error::InvalidKeyFormat)?;
match verifying_key.verify(hash_bytes, &signature_obj) {
Ok(()) => Ok(true),
Err(_) => Ok(false),
}
}
pub fn sign_schema_hash(schema_hash: &[u8], private_key: &SecretKey) -> Result<String, Error> {
Self::sign_hash(schema_hash, private_key)
}
pub fn verify_schema_signature(
schema_hash: &[u8],
signature_b64: &str,
public_key: &PublicKey,
) -> Result<bool, Error> {
Self::verify_signature(schema_hash, signature_b64, public_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_key_pair() {
let key_pair = generate_key_pair().unwrap();
assert!(key_pair
.private_key_pem
.starts_with("-----BEGIN PRIVATE KEY-----"));
assert!(key_pair
.public_key_pem
.starts_with("-----BEGIN PUBLIC KEY-----"));
}
#[test]
fn test_sign_and_verify() {
let key_pair = generate_key_pair().unwrap();
let data = b"Hello, World!";
let signature = sign_data(&key_pair.private_key_pem, data).unwrap();
let is_valid = verify_signature(&key_pair.public_key_pem, data, &signature).unwrap();
assert!(is_valid);
let wrong_data = b"Wrong data";
let is_invalid =
verify_signature(&key_pair.public_key_pem, wrong_data, &signature).unwrap();
assert!(!is_invalid);
}
#[test]
fn test_calculate_key_id() {
let key_pair = generate_key_pair().unwrap();
let key_id = calculate_key_id(&key_pair.public_key_pem).unwrap();
assert!(key_id.starts_with("sha256:"));
assert_eq!(key_id.len(), 71);
let key_id2 = calculate_key_id(&key_pair.public_key_pem).unwrap();
assert_eq!(key_id, key_id2);
}
#[test]
fn test_key_manager_api() {
let (private_key, public_key) = KeyManager::generate_keypair().unwrap();
let private_key_pem = KeyManager::export_private_key_pem(&private_key).unwrap();
let public_key_pem = KeyManager::export_public_key_pem(&public_key).unwrap();
let loaded_private = KeyManager::load_private_key_pem(&private_key_pem).unwrap();
let loaded_public = KeyManager::load_public_key_pem(&public_key_pem).unwrap();
assert_eq!(private_key.to_bytes(), loaded_private.to_bytes());
let test_data = b"test data";
let sig1 = SignatureManager::sign_hash(test_data, &private_key).unwrap();
assert!(SignatureManager::verify_signature(test_data, &sig1, &public_key).unwrap());
assert!(SignatureManager::verify_signature(test_data, &sig1, &loaded_public).unwrap());
}
#[test]
fn test_signature_manager_api() {
let (private_key, public_key) = KeyManager::generate_keypair().unwrap();
let data = b"Test data for signature";
let signature = SignatureManager::sign_hash(data, &private_key).unwrap();
let is_valid = SignatureManager::verify_signature(data, &signature, &public_key).unwrap();
assert!(is_valid);
}
}