use crate::{Error, Result};
use alloc::{string::String, vec::Vec};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u8)]
pub enum SigningAlgorithm {
Ed25519 = 0x01,
EcdsaP256 = 0x02,
RsaPss2048 = 0x03,
}
impl SigningAlgorithm {
pub fn from_byte(byte: u8) -> Result<Self> {
match byte {
0x01 => Ok(SigningAlgorithm::Ed25519),
0x02 => Ok(SigningAlgorithm::EcdsaP256),
0x03 => Ok(SigningAlgorithm::RsaPss2048),
_ => Err(Error::UnsupportedAlgorithm(byte)),
}
}
pub fn name(&self) -> &'static str {
match self {
SigningAlgorithm::Ed25519 => "ed25519",
SigningAlgorithm::EcdsaP256 => "ecdsa-p256",
SigningAlgorithm::RsaPss2048 => "rsa-pss-2048",
}
}
}
#[derive(Debug, Clone)]
pub struct KeyPair {
pub public_key_pem: String,
pub private_key_pem: String,
}
#[cfg(feature = "signing")]
pub fn generate_key_pair(algorithm: SigningAlgorithm) -> Result<KeyPair> {
match algorithm {
SigningAlgorithm::Ed25519 => generate_ed25519_key_pair(),
SigningAlgorithm::EcdsaP256 => generate_ecdsa_p256_key_pair(),
SigningAlgorithm::RsaPss2048 => generate_rsa_pss_key_pair(),
}
}
#[cfg(feature = "signing")]
fn generate_ed25519_key_pair() -> Result<KeyPair> {
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;
let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_pem = format!(
"-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----",
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, signing_key.as_bytes())
);
let public_pem = format!(
"-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, verifying_key.as_bytes())
);
Ok(KeyPair {
public_key_pem: public_pem,
private_key_pem: private_pem,
})
}
#[cfg(feature = "signing")]
fn generate_ecdsa_p256_key_pair() -> Result<KeyPair> {
use p256::ecdsa::SigningKey;
use rand::rngs::OsRng;
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let private_bytes = signing_key.to_bytes();
let public_bytes = verifying_key.to_encoded_point(false);
let private_pem = format!(
"-----BEGIN EC PRIVATE KEY-----\n{}\n-----END EC PRIVATE KEY-----",
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &private_bytes)
);
let public_pem = format!(
"-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
base64::Engine::encode(&base64::engine::general_purpose::STANDARD, public_bytes.as_bytes())
);
Ok(KeyPair {
public_key_pem: public_pem,
private_key_pem: private_pem,
})
}
#[cfg(feature = "signing")]
fn generate_rsa_pss_key_pair() -> Result<KeyPair> {
use rsa::{RsaPrivateKey, RsaPublicKey};
use rand::rngs::OsRng;
let bits = 2048;
let private_key = RsaPrivateKey::new(&mut OsRng, bits)
.map_err(|e| Error::KeyGenerationFailed(e.to_string()))?;
let _public_key = RsaPublicKey::from(&private_key);
let private_pem = format!(
"-----BEGIN RSA PRIVATE KEY-----\n{}\n-----END RSA PRIVATE KEY-----",
"... RSA PRIVATE KEY DATA ..."
);
let public_pem = format!(
"-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----",
"... RSA PUBLIC KEY DATA ..."
);
Ok(KeyPair {
public_key_pem: public_pem,
private_key_pem: private_pem,
})
}
#[cfg(feature = "signing")]
pub fn sign(
data: &[u8],
private_key_pem: &str,
algorithm: SigningAlgorithm,
) -> Result<Vec<u8>> {
match algorithm {
SigningAlgorithm::Ed25519 => sign_ed25519(data, private_key_pem),
SigningAlgorithm::EcdsaP256 => sign_ecdsa_p256(data, private_key_pem),
SigningAlgorithm::RsaPss2048 => sign_rsa_pss(data, private_key_pem),
}
}
#[cfg(feature = "signing")]
fn sign_ed25519(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
Err(Error::SigningFailed("Not yet implemented".to_string()))
}
#[cfg(feature = "signing")]
fn sign_ecdsa_p256(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
Err(Error::SigningFailed("Not yet implemented".to_string()))
}
#[cfg(feature = "signing")]
fn sign_rsa_pss(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
Err(Error::SigningFailed("Not yet implemented".to_string()))
}
#[cfg(feature = "signing")]
pub fn verify(
data: &[u8],
signature: &[u8],
public_key_pem: &str,
algorithm: SigningAlgorithm,
) -> Result<bool> {
match algorithm {
SigningAlgorithm::Ed25519 => verify_ed25519(data, signature, public_key_pem),
SigningAlgorithm::EcdsaP256 => verify_ecdsa_p256(data, signature, public_key_pem),
SigningAlgorithm::RsaPss2048 => verify_rsa_pss(data, signature, public_key_pem),
}
}
#[cfg(feature = "signing")]
fn verify_ed25519(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
Err(Error::SignatureVerificationFailed)
}
#[cfg(feature = "signing")]
fn verify_ecdsa_p256(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
Err(Error::SignatureVerificationFailed)
}
#[cfg(feature = "signing")]
fn verify_rsa_pss(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
Err(Error::SignatureVerificationFailed)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_algorithm_from_byte() {
assert_eq!(SigningAlgorithm::from_byte(0x01).unwrap(), SigningAlgorithm::Ed25519);
assert_eq!(SigningAlgorithm::from_byte(0x02).unwrap(), SigningAlgorithm::EcdsaP256);
assert_eq!(SigningAlgorithm::from_byte(0x03).unwrap(), SigningAlgorithm::RsaPss2048);
assert!(SigningAlgorithm::from_byte(0xFF).is_err());
}
#[test]
fn test_algorithm_name() {
assert_eq!(SigningAlgorithm::Ed25519.name(), "ed25519");
assert_eq!(SigningAlgorithm::EcdsaP256.name(), "ecdsa-p256");
assert_eq!(SigningAlgorithm::RsaPss2048.name(), "rsa-pss-2048");
}
}