// Copyright (C) 2017 The Runiter Project Developers. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //! Provide wrappers around ed25519 keys and signatures //! //! Key pairs can be generated with [`KeyPairGenerator`]. //! //! [`KeyPairGenerator`]: struct.KeyPairGenerator.html extern crate serde; use self::serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use self::serde::ser::{Serialize, SerializeSeq, Serializer}; use super::{BaseConvertionError, PrivateKey as PrivateKeyMethods, PublicKey as PublicKeyMethods}; use base58::{FromBase58, FromBase58Error, ToBase58}; use base64; use base64::DecodeError; use crypto; use std::collections::hash_map::DefaultHasher; use std::fmt::{self, Debug, Display, Error, Formatter}; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; /// Store a ed25519 signature. #[derive(Clone, Copy)] pub struct Signature(pub [u8; 64]); impl Hash for Signature { fn hash(&self, _state: &mut H) { let mut hasher = DefaultHasher::new(); Hash::hash_slice(&self.0, &mut hasher); } } impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut seq = serializer.serialize_seq(Some(64))?; for e in self.0.iter() { seq.serialize_element(e)?; } seq.end() } } struct SignatureVisitor { marker: PhantomData Signature>, } impl SignatureVisitor { fn new() -> Self { SignatureVisitor { marker: PhantomData, } } } impl<'de> Visitor<'de> for SignatureVisitor { // The type that our Visitor is going to produce. type Value = Signature; // Format a message stating what data this Visitor expects to receive. fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("Signature datas") } // Deserialize Signature from an abstract "map" provided by the // Deserializer. The MapAccess input is a callback provided by // the Deserializer to let us see each entry in the map. fn visit_seq(self, mut access: M) -> Result where M: SeqAccess<'de>, { let mut map = Vec::with_capacity(access.size_hint().unwrap_or(0)); // While there are entries remaining in the input, add them // into our map. while let Some(value) = access.next_element()? { map.push(value); } let mut sig_datas: [u8; 64] = [0; 64]; sig_datas.copy_from_slice(&map[0..64]); Ok(Signature(sig_datas)) } } // This is the trait that informs Serde how to deserialize Signature. impl<'de> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { // Instantiate our Visitor and ask the Deserializer to drive // it over the input data, resulting in an instance of Signature. deserializer.deserialize_seq(SignatureVisitor::new()) } } impl super::Signature for Signature { fn from_base64(base64_data: &str) -> Result { match base64::decode(base64_data) { Ok(result) => { if result.len() == 64 { let mut u8_array = [0; 64]; u8_array[..64].clone_from_slice(&result[..64]); Ok(Signature(u8_array)) } else { Err(BaseConvertionError::InvalidKeyLendth(result.len(), 64)) } } Err(DecodeError::InvalidByte(pos, byte)) => { Err(BaseConvertionError::InvalidCharacter(byte as char, pos)) } Err(DecodeError::InvalidLength) => { Err(BaseConvertionError::InvalidBaseConverterLength()) } } } fn to_bytes_vector(&self) -> Vec { self.0.to_vec() } fn to_base64(&self) -> String { base64::encode(&self.0[..]) // need to take a slice for required trait `AsRef<[u8]>` } } impl Display for Signature { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { use super::Signature; write!(f, "{}", self.to_base64()) } } impl Debug for Signature { // Signature { 1eubHHb... } fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "Signature {{ {} }}", self) } } impl PartialEq for Signature { fn eq(&self, other: &Signature) -> bool { // No PartialEq for [u8;64], need to use 2 [u8;32] self.0[0..32] == other.0[0..32] && self.0[32..64] == other.0[32..64] } } impl Eq for Signature {} /// Store a Ed25519 public key. /// /// Can be generated with [`KeyPairGenerator`]. /// /// [`KeyPairGenerator`]: struct.KeyPairGenerator.html #[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Serialize)] pub struct PublicKey(pub [u8; 32]); impl ToBase58 for PublicKey { fn to_base58(&self) -> String { self.0.to_base58() } } impl Display for PublicKey { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "{}", self.to_base58()) } } impl Debug for PublicKey { // PublicKey { DNann1L... } fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "PublicKey {{ {} }}", self) } } impl super::PublicKey for PublicKey { type Signature = Signature; fn from_base58(base58_data: &str) -> Result { match base58_data.from_base58() { Ok(result) => { if result.len() == 32 { let mut u8_array = [0; 32]; u8_array[..32].clone_from_slice(&result[..32]); Ok(PublicKey(u8_array)) } else { Err(BaseConvertionError::InvalidKeyLendth(result.len(), 32)) } } Err(FromBase58Error::InvalidBase58Character(character, pos)) => { Err(BaseConvertionError::InvalidCharacter(character, pos)) } Err(FromBase58Error::InvalidBase58Length) => { Err(BaseConvertionError::InvalidBaseConverterLength()) } } } fn to_bytes_vector(&self) -> Vec { self.0.to_vec() } fn verify(&self, message: &[u8], signature: &Self::Signature) -> bool { crypto::ed25519::verify(message, &self.0, &signature.0) } } /// Store a Ed25519 private key. /// /// Can be generated with [`KeyPairGenerator`]. /// /// [`KeyPairGenerator`]: struct.KeyPairGenerator.html #[derive(Copy, Clone)] pub struct PrivateKey(pub [u8; 64]); impl ToBase58 for PrivateKey { fn to_base58(&self) -> String { self.0.to_base58() } } impl Display for PrivateKey { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "{}", self.to_base58()) } } impl Debug for PrivateKey { // PrivateKey { 468Q1XtT... } fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "PrivateKey {{ {} }}", self) } } impl PartialEq for PrivateKey { fn eq(&self, other: &PrivateKey) -> bool { // No PartialEq for [u8;64], need to use 2 [u8;32] self.0[0..32] == other.0[0..32] && self.0[32..64] == other.0[32..64] } } impl Eq for PrivateKey {} impl super::PrivateKey for PrivateKey { type Signature = Signature; fn from_base58(base58_data: &str) -> Result { match base58_data.from_base58() { Ok(result) => { if result.len() == 64 { let mut u8_array = [0; 64]; u8_array[..64].clone_from_slice(&result[..64]); Ok(PrivateKey(u8_array)) } else { Err(BaseConvertionError::InvalidKeyLendth(result.len(), 64)) } } Err(FromBase58Error::InvalidBase58Character(character, pos)) => { Err(BaseConvertionError::InvalidCharacter(character, pos)) } Err(FromBase58Error::InvalidBase58Length) => { Err(BaseConvertionError::InvalidBaseConverterLength()) } } } /// Sign a message with this private key. fn sign(&self, message: &[u8]) -> Self::Signature { Signature(crypto::ed25519::signature(message, &self.0)) } } /// Store a ed25519 cryptographic key pair (`PublicKey` + `PrivateKey`) #[derive(Debug, Copy, Clone, Eq)] pub struct KeyPair { /// Store a Ed25519 public key. pub pubkey: PublicKey, /// Store a Ed25519 private key. pub privkey: PrivateKey, } impl Display for KeyPair { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "({}, hidden)", self.pubkey.to_base58()) } } impl PartialEq for KeyPair { fn eq(&self, other: &KeyPair) -> bool { self.pubkey.eq(&other.pubkey) && self.privkey.eq(&other.privkey) } } impl super::KeyPair for KeyPair { type Signature = Signature; type PublicKey = PublicKey; type PrivateKey = PrivateKey; fn public_key(&self) -> PublicKey { self.pubkey } fn private_key(&self) -> PrivateKey { self.privkey } fn sign(&self, message: &[u8]) -> Signature { self.private_key().sign(message) } fn verify(&self, message: &[u8], signature: &Self::Signature) -> bool { self.public_key().verify(message, signature) } } /// Keypair generator with given parameters for `scrypt` keypair function. #[derive(Debug, Copy, Clone)] pub struct KeyPairFromSaltedPasswordGenerator { /// The log2 of the Scrypt parameter `N`. log_n: u8, /// The Scrypt parameter `r` r: u32, /// The Scrypt parameter `p` p: u32, } impl KeyPairFromSaltedPasswordGenerator { /// Create a `KeyPairGenerator` with default arguments `(log_n: 12, r: 16, p: 1)` pub fn with_default_parameters() -> KeyPairFromSaltedPasswordGenerator { KeyPairFromSaltedPasswordGenerator { log_n: 12, r: 16, p: 1, } } /// Create a `KeyPairFromSaltedPasswordGenerator` with given arguments. /// /// # Arguments /// /// - log_n - The log2 of the Scrypt parameter N /// - r - The Scrypt parameter r /// - p - The Scrypt parameter p pub fn with_parameters(log_n: u8, r: u32, p: u32) -> KeyPairFromSaltedPasswordGenerator { KeyPairFromSaltedPasswordGenerator { log_n, r, p } } /// Create a keypair based on a given password and salt. /// /// The [`PublicKey`](struct.PublicKey.html) will be able to verify messaged signed with /// the [`PrivateKey`](struct.PrivateKey.html). pub fn generate(&self, password: &[u8], salt: &[u8]) -> KeyPair { let mut seed = [0u8; 32]; crypto::scrypt::scrypt( salt, password, &crypto::scrypt::ScryptParams::new(self.log_n, self.r, self.p), &mut seed, ); let (private, public) = crypto::ed25519::keypair(&seed); KeyPair { pubkey: PublicKey(public), privkey: PrivateKey(private), } } } #[cfg(test)] mod tests { use super::*; use keys::{KeyPair, Signature}; #[test] fn base58_private_key() { let private58 = "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9r\ qnXuW3iAfZACm7"; let private_key = super::PrivateKey::from_base58(private58).unwrap(); let private_raw = private58.from_base58().unwrap(); for (key, raw) in private_key.0.iter().zip(private_raw.iter()) { assert_eq!(key, raw); } assert_eq!(private_key.to_base58(), private58); assert_eq!( private_key, super::PrivateKey::from_base58(private58).unwrap() ); assert_eq!( super::PrivateKey::from_base58( "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iA\ fZACm7djh", ).unwrap_err(), BaseConvertionError::InvalidKeyLendth(67, 64) ); assert_eq!( super::PrivateKey::from_base58( "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9", ).unwrap_err(), BaseConvertionError::InvalidKeyLendth(53, 64) ); assert_eq!( super::PrivateKey::from_base58( "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt5GiERP7ySs3wM8myLccbAAGejgMRC9<<", ).unwrap_err(), BaseConvertionError::InvalidCharacter('<', 73) ); } #[test] fn base58_public_key() { let public58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"; let public_key = super::PublicKey::from_base58(public58).unwrap(); let public_raw = public58.from_base58().unwrap(); for (key, raw) in public_key.0.iter().zip(public_raw.iter()) { assert_eq!(key, raw); } assert_eq!(public_key.to_base58(), public58); assert_eq!(public_key, super::PublicKey::from_base58(public58).unwrap()); assert_eq!( super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLVdjq") .unwrap_err(), BaseConvertionError::InvalidKeyLendth(35, 32) ); assert_eq!( super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd") .unwrap_err(), BaseConvertionError::InvalidKeyLendth(31, 32) ); assert_eq!( super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<") .unwrap_err(), BaseConvertionError::InvalidCharacter('<', 42) ); } #[test] fn base64_signature() { let signature64 = "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\ MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg=="; let signature = super::Signature::from_base64(signature64).unwrap(); let signature_raw = base64::decode(signature64).unwrap(); for (sig, raw) in signature.0.iter().zip(signature_raw.iter()) { assert_eq!(sig, raw); } assert_eq!( super::Signature::from_base64("YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2U=").unwrap_err(), BaseConvertionError::InvalidKeyLendth(29, 64) ); assert_eq!( super::Signature::from_base64( "YmhlaW9iaHNlcGlvaGVvaXNlcGl2ZXBvdm5pc2V2c2JlaW9idmVpb3Zqc\ 2V2Z3BpaHNlamVwZ25qZXNqb2dwZWpnaW9zZXNkdnNic3JicmJyZGJyZGI=", ).unwrap_err(), BaseConvertionError::InvalidKeyLendth(86, 64) ); assert_eq!( super::Signature::from_base64( "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\ mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAgdha<<", ).unwrap_err(), BaseConvertionError::InvalidCharacter('<', 89) ); } #[test] fn message_sign_verify() { let pubkey = super::PublicKey::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV").unwrap(); let prikey = super::PrivateKey::from_base58( "468Q1XtTq7h84NorZdWBZFJrGkB18CbmbHr9tkp9snt\ 5GiERP7ySs3wM8myLccbAAGejgMRC9rqnXuW3iAfZACm7", ).unwrap(); let expected_signature = super::Signature::from_base64( "1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FG\ MMmQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==", ).unwrap(); let message = "Version: 10 Type: Identity Currency: duniter_unit_test_currency Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV UniqueID: tic Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 "; let sig = prikey.sign(message.as_bytes()); assert_eq!(sig, expected_signature); assert!(pubkey.verify(message.as_bytes(), &sig)); } #[test] fn keypair_generate_() { let keypair = KeyPairFromSaltedPasswordGenerator::with_default_parameters().generate( "JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV".as_bytes(), "JhxtHB7UcsDbA9wMSyMKXUzBZUQvqVyB32KwzS9SWoLkjrUhHV_".as_bytes(), ); assert_eq!( keypair.pubkey.to_string(), "7iMV3b6j2hSj5WtrfchfvxivS9swN3opDgxudeHq64fb" ); } #[test] fn keypair_generate_sign_and_verify() { let keypair = KeyPairFromSaltedPasswordGenerator::with_default_parameters() .generate("password".as_bytes(), "salt".as_bytes()); let message = "Version: 10 Type: Identity Currency: duniter_unit_test_currency Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV UniqueID: tic Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 "; let sig = keypair.sign(message.as_bytes()); assert!(keypair.verify(message.as_bytes(), &sig)); } }