use crate::CryptoString;
use crate::base::{CryptoInfo, PublicKey, PrivateKey, KeyUsage, Sign, VerifySignature};
use sodiumoxide::crypto::sign;
use crate::error::EzNaclError;
pub struct SigningPair {
verkey: CryptoString,
signkey: CryptoString,
}
impl SigningPair {
pub fn from(verkey: CryptoString, signkey: CryptoString) -> SigningPair {
SigningPair { verkey, signkey }
}
pub fn from_strings(verstr: &str, signstr: &str) -> Option<SigningPair> {
let vercs = match CryptoString::from(verstr) {
Some(cs) => cs,
None => return None
};
let signcs = match CryptoString::from(signstr) {
Some(cs) => cs,
None => return None
};
Some(SigningPair { verkey: vercs, signkey: signcs })
}
pub fn generate() -> Option<SigningPair> {
let (raw_vkey, raw_skey) = sign::gen_keypair();
let verkey = CryptoString::from_bytes("ED25519", &raw_vkey[..])?;
let signkey = CryptoString::from_bytes("ED25519", &raw_skey[..32])?;
Some(SigningPair { verkey, signkey })
}
}
impl CryptoInfo for SigningPair {
fn get_usage(&self) -> KeyUsage {
KeyUsage::SignVerify
}
fn get_algorithm(&self) -> String {
String::from("ED25519")
}
}
impl PublicKey for SigningPair {
fn get_public_key(&self) -> CryptoString {
self.verkey.clone()
}
fn get_public_str(&self) -> String {
String::from(self.verkey.as_str())
}
fn get_public_bytes(&self) -> Vec<u8> {
Vec::from(self.verkey.as_bytes())
}
}
impl PrivateKey for SigningPair {
fn get_private_key(&self) -> CryptoString {
self.signkey.clone()
}
fn get_private_str(&self) -> String {
String::from(self.signkey.as_str())
}
fn get_private_bytes(&self) -> Vec<u8> {
Vec::from(self.signkey.as_bytes())
}
}
impl Sign for SigningPair {
fn sign(&self, data: &[u8]) -> Result<CryptoString, EzNaclError> {
let mut fullkey = self.signkey.as_raw();
fullkey.append(&mut self.verkey.as_raw());
let skey = match sign::ed25519::SecretKey::from_slice(&fullkey) {
Some(v) => v,
None => return Err(EzNaclError::KeyError)
};
let signature = sign::sign_detached(data, &skey);
match CryptoString::from_bytes("ED25519", &signature.to_bytes()) {
Some(cs) => Ok(cs),
_ => Err(EzNaclError::EncodingError)
}
}
}
impl VerifySignature for SigningPair {
fn verify(&self, data: &[u8], signature: &CryptoString) -> Result<bool, EzNaclError> {
let vkey = match sign::ed25519::PublicKey::from_slice(&self.verkey.as_raw()) {
Some(v) => v,
None => return Err(EzNaclError::KeyError)
};
let rawsig = match sign::ed25519::Signature::from_bytes(&signature.as_raw()) {
Ok(s) => s,
_ => return Err(EzNaclError::SignatureError),
};
Ok(sign::verify_detached(&rawsig, data, &vkey))
}
}
pub struct VerificationKey {
verkey: CryptoString,
}
impl VerificationKey {
pub fn from(verkey: CryptoString) -> VerificationKey {
VerificationKey { verkey }
}
pub fn from_string(verstr: &str) -> Option<VerificationKey> {
let vercs = match CryptoString::from(verstr) {
Some(cs) => cs,
None => return None
};
Some(VerificationKey { verkey: vercs })
}
}
impl CryptoInfo for VerificationKey {
fn get_usage(&self) -> KeyUsage {
KeyUsage::SignVerify
}
fn get_algorithm(&self) -> String {
String::from("ED25519")
}
}
impl PublicKey for VerificationKey {
fn get_public_key(&self) -> CryptoString {
self.verkey.clone()
}
fn get_public_str(&self) -> String {
String::from(self.verkey.as_str())
}
fn get_public_bytes(&self) -> Vec<u8> {
Vec::from(self.verkey.as_bytes())
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn sign_verify_test() {
let keypair = match crate::SigningPair::from_strings(
"ED25519:PnY~pK2|;AYO#1Z;B%T$2}E$^kIpL=>>VzfMKsDx",
"ED25519:{^A@`5N*T%5ybCU%be892x6%*Rb2rnYd=SGeO4jF") {
Some(kp) => kp,
None => panic!("sign_verify_test failed to create keypair")
};
let testdata = "This is some signing test data";
let signature = match keypair.sign(testdata.as_bytes()) {
Ok(cs) => cs,
Err(_) => panic!("sign_verify_test signing failure")
};
match keypair.verify(&testdata.as_bytes(), &signature) {
Ok(v) => assert!(v, "sign_verify_test failure to verify signature"),
Err(_) => panic!("sign_verify_test verify() error")
};
}
}