t-rust-less-lib 0.2.16

Password manager library
Documentation
use rand::{distributions, thread_rng, Rng};
use spectral::prelude::*;
use std::iter;

use crate::memguard::SecretBytes;
use crate::secrets_store::cipher::RUST_X25519CHA_CHA20POLY1305;
use crate::secrets_store_capnp::block;

use super::Cipher;

fn assert_slices_equal(actual: &[u8], expected: &[u8]) {
  assert!(actual == expected)
}

fn common_chiper_tests<T>(cipher: &T)
where
  T: Cipher,
{
  common_private_seal_open(cipher);
  common_data_encrypt_decrypt(cipher);
}

fn common_private_seal_open<T>(cipher: &T)
where
  T: Cipher,
{
  let (public_key, private_key) = cipher.generate_key_pair().unwrap();

  assert_that(&public_key.len()).is_greater_than_or_equal_to(30);

  let mut rng = thread_rng();
  let nonce = iter::repeat(())
    .map(|_| rng.sample(distributions::Standard))
    .take(cipher.seal_min_nonce_length())
    .collect::<Vec<u8>>();
  let seal_key = SecretBytes::random(&mut rng, cipher.seal_key_length());

  let crypted_private = cipher.seal_private_key(&seal_key, &nonce, &private_key).unwrap();
  let decrypted_private = cipher.open_private_key(&seal_key, &nonce, &crypted_private).unwrap();

  assert_slices_equal(&decrypted_private.borrow(), &private_key.borrow());
}

fn common_data_encrypt_decrypt<T>(cipher: &T)
where
  T: Cipher,
{
  let mut rng = thread_rng();
  let private_data = SecretBytes::random(&mut rng, 1234);

  let id1 = "recipient1";
  let id2 = "recipient2";
  let (public_key1, private_key1) = cipher.generate_key_pair().unwrap();
  let (public_key2, private_key2) = cipher.generate_key_pair().unwrap();

  let mut message = capnp::message::Builder::new_default();

  let mut block = message.init_root::<block::Builder>();
  let headers = block.reborrow().init_headers(1);

  let crypted_data = cipher
    .encrypt(&[(id1, public_key1), (id2, public_key2)], &private_data, headers.get(0))
    .unwrap();
  block.set_content(&crypted_data);

  let mut message_payload: &[u8] = &capnp::serialize::write_message_to_words(&message);

  let message_reader =
    capnp::serialize::read_message_from_flat_slice(&mut message_payload, capnp::message::ReaderOptions::new()).unwrap();
  let block_reader = message_reader.get_root::<block::Reader>().unwrap();
  let cryped_content = block_reader.get_content().unwrap();

  assert_slices_equal(cryped_content, &crypted_data);

  let decrypted1 = cipher
    .decrypt(
      (id1, &private_key1),
      block_reader.get_headers().unwrap().get(0),
      cryped_content,
    )
    .unwrap();

  assert_slices_equal(&decrypted1.borrow(), &private_data.borrow());

  let decrypted2 = cipher
    .decrypt(
      (id2, &private_key2),
      block_reader.get_headers().unwrap().get(0),
      cryped_content,
    )
    .unwrap();

  assert_slices_equal(&decrypted2.borrow(), &private_data.borrow());
}

#[test]
#[cfg(feature = "openssl")]
fn test_openssl_rsa_aes_gcm() {
  common_chiper_tests(&crate::secrets_store::cipher::OPEN_SSL_RSA_AES_GCM);
}

#[test]
fn test_rust_x25519_chacha20_poly1305() {
  common_chiper_tests(&RUST_X25519CHA_CHA20POLY1305);
}

#[test]
#[cfg(feature = "rust_crypto")]
#[cfg_attr(debug_assertions, ignore)]
fn test_rust_rsa_aes_gcm() {
  common_chiper_tests(&crate::secrets_store::cipher::RUST_RSA_AES_GCM);
}