use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use base64::Engine;
use ed25519_dalek::{
Signature, Signer, SigningKey, Verifier, VerifyingKey, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH,
SIGNATURE_LENGTH,
};
use rand::rngs::OsRng;
use crate::error::{LicenseError, Result};
#[derive(Debug)]
pub struct KeyPair {
signing_key: SigningKey,
}
impl KeyPair {
pub fn generate() -> Result<Self> {
let mut csprng = OsRng;
let signing_key = SigningKey::generate(&mut csprng);
Ok(Self { signing_key })
}
pub fn from_private_key_base64(private_key_base64: &str) -> Result<Self> {
let private_key_bytes = BASE64_STANDARD.decode(private_key_base64).map_err(|e| {
LicenseError::InvalidPrivateKey {
reason: format!("invalid base64 encoding: {}", e),
}
})?;
if private_key_bytes.len() != SECRET_KEY_LENGTH {
return Err(LicenseError::InvalidPrivateKey {
reason: format!(
"invalid key length: expected {} bytes, got {}",
SECRET_KEY_LENGTH,
private_key_bytes.len()
),
});
}
let key_bytes: [u8; SECRET_KEY_LENGTH] =
private_key_bytes
.try_into()
.map_err(|_| LicenseError::InvalidPrivateKey {
reason: "failed to convert key bytes".to_string(),
})?;
let signing_key = SigningKey::from_bytes(&key_bytes);
Ok(Self { signing_key })
}
pub fn from_private_key_bytes(private_key_bytes: &[u8]) -> Result<Self> {
if private_key_bytes.len() != SECRET_KEY_LENGTH {
return Err(LicenseError::InvalidPrivateKey {
reason: format!(
"invalid key length: expected {} bytes, got {}",
SECRET_KEY_LENGTH,
private_key_bytes.len()
),
});
}
let key_bytes: [u8; SECRET_KEY_LENGTH] =
private_key_bytes
.try_into()
.map_err(|_| LicenseError::InvalidPrivateKey {
reason: "failed to convert key bytes".to_string(),
})?;
let signing_key = SigningKey::from_bytes(&key_bytes);
Ok(Self { signing_key })
}
pub fn public_key(&self) -> PublicKey {
PublicKey {
verifying_key: self.signing_key.verifying_key(),
}
}
pub fn private_key_bytes(&self) -> [u8; SECRET_KEY_LENGTH] {
self.signing_key.to_bytes()
}
pub fn private_key_base64(&self) -> String {
BASE64_STANDARD.encode(self.signing_key.to_bytes())
}
pub fn public_key_base64(&self) -> String {
self.public_key().to_base64()
}
pub fn sign(&self, data: &[u8]) -> [u8; SIGNATURE_LENGTH] {
let signature = self.signing_key.sign(data);
signature.to_bytes()
}
pub fn sign_base64(&self, data: &[u8]) -> String {
BASE64_STANDARD.encode(self.sign(data))
}
}
#[derive(Debug, Clone)]
pub struct PublicKey {
verifying_key: VerifyingKey,
}
impl PublicKey {
pub fn from_base64(public_key_base64: &str) -> Result<Self> {
let public_key_bytes = BASE64_STANDARD.decode(public_key_base64).map_err(|e| {
LicenseError::InvalidPublicKey {
reason: format!("invalid base64 encoding: {}", e),
}
})?;
Self::from_bytes(&public_key_bytes)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(LicenseError::InvalidPublicKey {
reason: format!(
"invalid key length: expected {} bytes, got {}",
PUBLIC_KEY_LENGTH,
bytes.len()
),
});
}
let key_bytes: [u8; PUBLIC_KEY_LENGTH] =
bytes
.try_into()
.map_err(|_| LicenseError::InvalidPublicKey {
reason: "failed to convert key bytes".to_string(),
})?;
let verifying_key =
VerifyingKey::from_bytes(&key_bytes).map_err(|e| LicenseError::InvalidPublicKey {
reason: format!("invalid public key: {}", e),
})?;
Ok(Self { verifying_key })
}
pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
self.verifying_key.to_bytes()
}
pub fn to_base64(&self) -> String {
BASE64_STANDARD.encode(self.verifying_key.to_bytes())
}
pub fn verify(&self, data: &[u8], signature_bytes: &[u8]) -> Result<()> {
if signature_bytes.len() != SIGNATURE_LENGTH {
return Err(LicenseError::InvalidSignature);
}
let sig_bytes: [u8; SIGNATURE_LENGTH] = signature_bytes
.try_into()
.map_err(|_| LicenseError::InvalidSignature)?;
let signature = Signature::from_bytes(&sig_bytes);
self.verifying_key
.verify(data, &signature)
.map_err(|_| LicenseError::InvalidSignature)
}
pub fn verify_base64(&self, data: &[u8], signature_base64: &str) -> Result<()> {
let signature_bytes = BASE64_STANDARD
.decode(signature_base64)
.map_err(|_| LicenseError::InvalidSignature)?;
self.verify(data, &signature_bytes)
}
}
pub fn generate_key_pair_base64() -> Result<(String, String)> {
let key_pair = KeyPair::generate()?;
Ok((key_pair.private_key_base64(), key_pair.public_key_base64()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_pair_generation() {
let key_pair = KeyPair::generate().expect("Key generation should succeed");
assert_eq!(key_pair.private_key_bytes().len(), SECRET_KEY_LENGTH);
assert_eq!(key_pair.public_key().to_bytes().len(), PUBLIC_KEY_LENGTH);
}
#[test]
fn test_key_pair_from_private_key() {
let original = KeyPair::generate().expect("Key generation should succeed");
let private_key_base64 = original.private_key_base64();
let restored =
KeyPair::from_private_key_base64(&private_key_base64).expect("Should restore key pair");
assert_eq!(
original.public_key().to_bytes(),
restored.public_key().to_bytes()
);
}
#[test]
fn test_public_key_from_base64() {
let key_pair = KeyPair::generate().expect("Key generation should succeed");
let public_key_base64 = key_pair.public_key_base64();
let public_key =
PublicKey::from_base64(&public_key_base64).expect("Should parse public key");
assert_eq!(public_key.to_bytes(), key_pair.public_key().to_bytes());
}
#[test]
fn test_sign_and_verify() {
let key_pair = KeyPair::generate().expect("Key generation should succeed");
let data = b"This is the license payload data";
let signature = key_pair.sign(data);
let public_key = key_pair.public_key();
public_key
.verify(data, &signature)
.expect("Signature should be valid");
}
#[test]
fn test_sign_and_verify_base64() {
let key_pair = KeyPair::generate().expect("Key generation should succeed");
let data = b"This is the license payload data";
let signature_base64 = key_pair.sign_base64(data);
let public_key = key_pair.public_key();
public_key
.verify_base64(data, &signature_base64)
.expect("Signature should be valid");
}
#[test]
fn test_verify_invalid_signature() {
let key_pair = KeyPair::generate().expect("Key generation should succeed");
let data = b"This is the license payload data";
let wrong_data = b"This is different data";
let signature = key_pair.sign(data);
let public_key = key_pair.public_key();
assert!(public_key.verify(wrong_data, &signature).is_err());
}
#[test]
fn test_verify_with_wrong_key() {
let key_pair_1 = KeyPair::generate().expect("Key generation should succeed");
let key_pair_2 = KeyPair::generate().expect("Key generation should succeed");
let data = b"This is the license payload data";
let signature = key_pair_1.sign(data);
let public_key_2 = key_pair_2.public_key();
assert!(public_key_2.verify(data, &signature).is_err());
}
#[test]
fn test_invalid_private_key_length() {
let invalid_key = BASE64_STANDARD.encode(vec![0u8; 16]); let result = KeyPair::from_private_key_base64(&invalid_key);
assert!(result.is_err());
}
#[test]
fn test_invalid_public_key_length() {
let invalid_key = BASE64_STANDARD.encode(vec![0u8; 16]); let result = PublicKey::from_base64(&invalid_key);
assert!(result.is_err());
}
#[test]
fn test_invalid_base64_encoding() {
let result = KeyPair::from_private_key_base64("not valid base64!!!");
assert!(result.is_err());
let result = PublicKey::from_base64("not valid base64!!!");
assert!(result.is_err());
}
#[test]
fn test_generate_key_pair_base64_convenience() {
let (private_key, public_key) =
generate_key_pair_base64().expect("Key generation should succeed");
let key_pair = KeyPair::from_private_key_base64(&private_key)
.expect("Should create key pair from private key");
assert_eq!(key_pair.public_key_base64(), public_key);
}
}