use crate::types::{ECDSACurve, ExportKeyFormat, SHAFamily};
use generic_array::GenericArray;
use p256::ecdsa::{SigningKey, VerifyingKey};
use rand_core::OsRng;
use signature::{Signer, Verifier};
pub struct ECDSA;
impl ECDSA {
pub async fn generate_key_pair(
curve: Option<ECDSACurve>,
) -> Result<(Vec<u8>, Vec<u8>), Box<dyn std::error::Error>> {
let curve = curve.unwrap_or(ECDSACurve::P256);
match curve {
ECDSACurve::P256 => {
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_key = signing_key.to_bytes().to_vec();
let public_key = verifying_key.to_encoded_point(false).as_bytes().to_vec();
Ok((private_key, public_key))
}
_ => Err("Currently only P-256 curve is supported".into()),
}
}
pub async fn import_private_key(
private_key: impl AsRef<[u8]>,
curve: ECDSACurve,
_extractable: bool,
) -> Result<SigningKey, Box<dyn std::error::Error>> {
match curve {
ECDSACurve::P256 => {
let bytes = private_key.as_ref();
let array_ref = GenericArray::from_slice(bytes);
let key = SigningKey::from_bytes(array_ref)?;
Ok(key)
}
_ => Err("Currently only P-256 curve is supported".into()),
}
}
pub async fn import_public_key(
public_key: impl AsRef<[u8]>,
curve: ECDSACurve,
_extractable: bool,
) -> Result<VerifyingKey, Box<dyn std::error::Error>> {
match curve {
ECDSACurve::P256 => {
let key = VerifyingKey::from_sec1_bytes(public_key.as_ref())?;
Ok(key)
}
_ => Err("Currently only P-256 curve is supported".into()),
}
}
pub async fn sign(
private_key: &SigningKey,
data: impl AsRef<[u8]>,
hash: Option<SHAFamily>,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let hash = hash.unwrap_or(SHAFamily::SHA256);
match hash {
SHAFamily::SHA256 => {
let signature: p256::ecdsa::Signature = private_key.sign(data.as_ref());
Ok(signature.to_vec())
}
_ => Err("Currently only SHA-256 is supported for signing".into()),
}
}
pub async fn verify(
public_key: &VerifyingKey,
signature: impl AsRef<[u8]>,
data: impl AsRef<[u8]>,
hash: Option<SHAFamily>,
) -> Result<bool, Box<dyn std::error::Error>> {
let hash = hash.unwrap_or(SHAFamily::SHA256);
match hash {
SHAFamily::SHA256 => {
let sig = p256::ecdsa::Signature::from_slice(signature.as_ref())?;
Ok(public_key.verify(data.as_ref(), &sig).is_ok())
}
_ => Err("Currently only SHA-256 is supported for verification".into()),
}
}
pub async fn export_key(
key: &(impl AsRef<[u8]> + ?Sized),
format: ExportKeyFormat,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
match format {
ExportKeyFormat::SPKI => {
if let Ok(public_key) = VerifyingKey::from_sec1_bytes(key.as_ref()) {
Ok(public_key.to_encoded_point(false).as_bytes().to_vec())
} else {
Err("Key is not a valid public key".into())
}
}
ExportKeyFormat::PKCS8 => {
let array_ref = GenericArray::from_slice(key.as_ref());
if let Ok(private_key) = SigningKey::from_bytes(array_ref) {
Ok(private_key.to_bytes().to_vec())
} else {
Err("Key is not a valid private key".into())
}
}
_ => Err("Unsupported export format".into()),
}
}
pub async fn export_key_private(
key: &SigningKey,
format: ExportKeyFormat,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
match format {
ExportKeyFormat::PKCS8 => Ok(key.to_bytes().to_vec()),
_ => Err("Unsupported export format for private key".into()),
}
}
pub async fn export_key_public(
key: &VerifyingKey,
format: ExportKeyFormat,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
match format {
ExportKeyFormat::SPKI => Ok(key.to_encoded_point(false).as_bytes().to_vec()),
_ => Err("Unsupported export format for public key".into()),
}
}
}