#![allow(warnings)]
use crate::{
key_bundle,
password_encryption::{self, PwHashConfig},
utils, CODEC_HCK0, CODEC_HCS0, SEED_SIZE, SIGNATURE_SIZE,
};
use hcid::*;
use holochain_core_types::{agent::Base32, error::HcResult};
use lib3h_sodium::{kx, secbuf::SecBuf, sign};
use serde_json::json;
use std::str;
pub trait KeyPair {
fn public(&self) -> Base32;
fn private(&mut self) -> &mut SecBuf;
fn new_from_seed(seed: &mut SecBuf) -> HcResult<Self>
where
Self: Sized;
fn new_from_self(&mut self) -> HcResult<Self>
where
Self: Sized;
fn codec<'a>() -> &'a HcidEncoding;
fn encode_pub_key(pub_key_sec: &mut SecBuf) -> Base32 {
utils::encode_pub_key(pub_key_sec, &Self::codec()).expect("Public key encoding failed.")
}
fn decode_pub_key(&self) -> Vec<u8> {
Self::codec()
.decode(&self.public())
.expect("Public key decoding failed. Key was not properly encoded.")
}
fn decode_pub_key_into_secbuf(&self) -> SecBuf {
utils::decode_pub_key(self.public(), Self::codec())
.expect("Public key decoding failed. Key was not properly encoded.")
}
fn is_same(&mut self, other: &mut Self) -> bool {
self.public() == other.public() && self.private().compare(other.private()) == 0
}
}
pub struct SigningKeyPair {
pub public: Base32,
pub private: SecBuf,
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
impl KeyPair for SigningKeyPair {
fn public(&self) -> String {
self.public.clone()
}
fn private(&mut self) -> &mut SecBuf {
&mut self.private
}
fn codec<'a>() -> &'a HcidEncoding {
&CODEC_HCS0
}
fn new_from_seed(seed: &mut SecBuf) -> HcResult<Self> {
assert_eq!(seed.len(), SEED_SIZE);
let mut pub_sec_buf = SecBuf::with_insecure(sign::PUBLICKEYBYTES);
let mut priv_sec_buf = SecBuf::with_secure(sign::SECRETKEYBYTES);
lib3h_sodium::sign::seed_keypair(&mut pub_sec_buf, &mut priv_sec_buf, seed)?;
let pub_key_b32 = utils::encode_pub_key(&mut pub_sec_buf, Self::codec())?;
Ok(SigningKeyPair::new(pub_key_b32, priv_sec_buf))
}
fn new_from_self(&mut self) -> HcResult<Self> {
Ok(SigningKeyPair::new(self.public(), self.private.clone()))
}
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
impl SigningKeyPair {
pub fn new(public: Base32, private: SecBuf) -> Self {
Self { public, private }
}
pub fn new_with_raw_key(pub_key_sec: &mut SecBuf, private: SecBuf) -> Self {
let public = Self::encode_pub_key(pub_key_sec);
Self { public, private }
}
pub fn sign(&mut self, data: &mut SecBuf) -> HcResult<SecBuf> {
let mut signature = SecBuf::with_insecure(SIGNATURE_SIZE);
lib3h_sodium::sign::sign(data, &mut self.private, &mut signature)?;
Ok(signature)
}
pub fn verify(&mut self, data: &mut SecBuf, signature: &mut SecBuf) -> bool {
let mut pub_key = self.decode_pub_key_into_secbuf();
lib3h_sodium::sign::verify(signature, data, &mut pub_key)
}
}
pub struct EncryptingKeyPair {
pub public: Base32,
pub private: SecBuf,
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
impl KeyPair for EncryptingKeyPair {
fn public(&self) -> String {
self.public.clone()
}
fn private(&mut self) -> &mut SecBuf {
&mut self.private
}
fn codec<'a>() -> &'a HcidEncoding {
&CODEC_HCK0
}
fn new_from_seed(seed: &mut SecBuf) -> HcResult<Self> {
assert_eq!(seed.len(), SEED_SIZE);
let mut pub_sec_buf = SecBuf::with_insecure(kx::PUBLICKEYBYTES);
let mut priv_sec_buf = SecBuf::with_secure(kx::SECRETKEYBYTES);
lib3h_sodium::kx::seed_keypair(&mut pub_sec_buf, &mut priv_sec_buf, seed)?;
let pub_key_b32 = utils::encode_pub_key(&mut pub_sec_buf, Self::codec())?;
Ok(EncryptingKeyPair::new(pub_key_b32, priv_sec_buf))
}
fn new_from_self(&mut self) -> HcResult<Self> {
Ok(EncryptingKeyPair::new(self.public(), self.private.clone()))
}
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
impl EncryptingKeyPair {
pub fn new(public: String, private: SecBuf) -> Self {
Self { public, private }
}
pub fn new_with_secbuf(pub_key_sec: &mut SecBuf, private: SecBuf) -> Self {
let public = Self::encode_pub_key(pub_key_sec);
Self { public, private }
}
pub fn encrypt(&mut self, data: &mut SecBuf, encrypted_data: &mut SecBuf) -> HcResult<()> {
let mut nonce = SecBuf::with_insecure(lib3h_sodium::aead::NONCEBYTES);
nonce.randomize();
let cipher_length = data.len() + lib3h_sodium::aead::ABYTES;
let mut cipher = SecBuf::with_insecure(cipher_length);
lib3h_sodium::aead::enc(data, &mut self.private, None, &mut nonce, &mut cipher)?;
let cipher_slice = &**cipher.read_lock();
let nonce_slice = &**nonce.read_lock();
let cipher_with_nonce_slice = cipher_slice
.iter()
.cloned()
.chain(nonce_slice.iter().cloned())
.collect::<Vec<u8>>();
encrypted_data.from_array(&cipher_with_nonce_slice);
Ok(())
}
pub fn decrypt(
&mut self,
cipher: &mut SecBuf,
mut decrypted_message: &mut SecBuf,
) -> HcResult<()> {
let cipher_length = cipher.len() - lib3h_sodium::aead::NONCEBYTES;
let mut cipher_slice = &**cipher.read_lock();
let mut nonce = SecBuf::with_insecure(lib3h_sodium::aead::NONCEBYTES);
let nonce_slice_from_cipher = cipher_slice
.iter()
.skip(cipher_length)
.cloned()
.collect::<Vec<u8>>();
nonce.from_array(&nonce_slice_from_cipher)?;
let cipher_no_nonce_slice = cipher_slice
.iter()
.cloned()
.take(cipher_length)
.collect::<Vec<u8>>();
let mut cipher_no_nonce = SecBuf::with_insecure(cipher_length);
cipher_no_nonce.from_array(&cipher_no_nonce_slice)?;
lib3h_sodium::aead::dec(
&mut decrypted_message,
&mut self.private,
None,
&mut nonce,
&mut cipher_no_nonce,
)?;
Ok(())
}
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
pub fn generate_random_sign_keypair() -> HcResult<SigningKeyPair> {
let mut seed = utils::generate_random_seed_buf();
SigningKeyPair::new_from_seed(&mut seed)
}
#[holochain_tracing_macros::newrelic_autotrace(HOLOCHAIN_DPKI)]
pub fn generate_random_enc_keypair() -> HcResult<EncryptingKeyPair> {
let mut seed = utils::generate_random_seed_buf();
EncryptingKeyPair::new_from_seed(&mut seed)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::SEED_SIZE;
pub fn test_generate_random_sign_keypair() -> SigningKeyPair {
generate_random_sign_keypair().unwrap()
}
pub fn test_generate_random_enc_keypair() -> EncryptingKeyPair {
generate_random_enc_keypair().unwrap()
}
#[test]
fn keypair_should_construct_and_clone_sign() {
let mut keys = test_generate_random_sign_keypair();
println!("sign_keys.public = {:?}", keys.public);
assert_eq!(63, keys.public.len());
let prefix: String = keys.public.chars().skip(0).take(3).collect();
assert_eq!("HcS", prefix);
assert_eq!(64, keys.private.len());
assert!(keys.new_from_self().unwrap().is_same(&mut keys));
}
#[test]
fn keypair_should_construct_and_clone_enc() {
let mut keys = test_generate_random_enc_keypair();
println!("enc_keys.public = {:?}", keys.public);
assert_eq!(63, keys.public.len());
let prefix: String = keys.public.chars().skip(0).take(3).collect();
assert_eq!("HcK", prefix);
assert_eq!(32, keys.private.len());
assert!(keys.new_from_self().unwrap().is_same(&mut keys));
}
#[test]
fn keypair_should_sign_message_and_verify() {
let mut sign_keys = test_generate_random_sign_keypair();
let mut message = SecBuf::with_insecure(16);
message.randomize();
let mut signature = sign_keys.sign(&mut message).unwrap();
println!("signature = {:?}", signature);
let succeeded = sign_keys.verify(&mut message, &mut signature);
assert!(succeeded);
let mut random_signature = SecBuf::with_insecure(SIGNATURE_SIZE);
random_signature.randomize();
let succeeded = sign_keys.verify(&mut message, &mut random_signature);
assert!(!succeeded);
message.randomize();
let succeeded = sign_keys.verify(&mut message, &mut signature);
assert!(!succeeded);
}
}