use crate::base::*;
use crate::error::EzNaclError;
use crate::CryptoString;
use sodiumoxide::crypto::sign;
pub fn get_supported_signing_algorithms() -> Vec<String> {
vec![String::from("ED25519")]
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "use_serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SigningPair {
verkey: CryptoString,
signkey: CryptoString,
}
impl SigningPair {
pub fn from(verkey: &CryptoString, signkey: &CryptoString) -> Result<SigningPair, EzNaclError> {
if verkey.prefix() != signkey.prefix() {
return Err(EzNaclError::KeyError);
}
if !is_supported_algorithm(verkey.prefix()) {
return Err(EzNaclError::UnsupportedAlgorithm);
}
Ok(SigningPair {
verkey: verkey.clone(),
signkey: signkey.clone(),
})
}
pub fn from_strings(verstr: &str, signstr: &str) -> Result<SigningPair, EzNaclError> {
let vercs = match CryptoString::from(verstr) {
Some(cs) => cs,
None => return Err(EzNaclError::KeyError),
};
let signcs = match CryptoString::from(signstr) {
Some(cs) => cs,
None => return Err(EzNaclError::KeyError),
};
SigningPair::from(&vercs, &signcs)
}
pub fn generate(algorithm: &str) -> Result<SigningPair, EzNaclError> {
if algorithm != "ED25519" {
return Err(EzNaclError::UnsupportedAlgorithm);
}
let (raw_vkey, raw_skey) = sign::gen_keypair();
let verkey = match CryptoString::from_bytes("ED25519", &raw_vkey[..]) {
Some(cs) => cs,
None => return Err(EzNaclError::KeyError),
};
let signkey = match CryptoString::from_bytes("ED25519", &raw_skey[..32]) {
Some(cs) => cs,
None => return Err(EzNaclError::KeyError),
};
Ok(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))
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[cfg_attr(feature = "use_serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VerificationKey {
verkey: CryptoString,
}
impl VerificationKey {
pub fn from(verkey: &CryptoString) -> VerificationKey {
VerificationKey {
verkey: verkey.clone(),
}
}
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())
}
}
impl VerifySignature for VerificationKey {
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))
}
}
#[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",
) {
Ok(kp) => kp,
Err(_) => 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"),
};
}
}