t-rust-less-lib 0.2.23

Password manager library
Documentation
use super::{Cipher, PrivateData, PrivateKey, PublicData, PublicKey, SealKey};
use crate::memguard::SecretBytes;
use crate::secrets_store::{SecretStoreError, SecretStoreResult};
use crate::secrets_store_capnp::{block, KeyType};
use openssl::rsa::{Padding, Rsa};
use openssl::symm;
use rand::{thread_rng, RngCore};

const RSA_KEY_BITS: u32 = 4096;

const TAG_LENGTH: usize = 16;

pub static OPEN_SSL_RSA_AES_GCM: OpenSslRsaAesGcmCipher = OpenSslRsaAesGcmCipher();
pub struct OpenSslRsaAesGcmCipher();

impl Cipher for OpenSslRsaAesGcmCipher {
  fn key_type(&self) -> KeyType {
    KeyType::RsaAesGcm
  }

  fn name(&self) -> String {
    "OpenSslRsaAesGcmCipher".to_string()
  }

  fn generate_key_pair(&self) -> SecretStoreResult<(PublicKey, PrivateKey)> {
    let private = Rsa::generate(RSA_KEY_BITS)?;
    let private_der = SecretBytes::from(private.private_key_to_der()?);
    let public_der = private.public_key_to_der()?;

    Ok((public_der, private_der))
  }

  fn seal_key_length(&self) -> usize {
    32
  }

  fn seal_min_nonce_length(&self) -> usize {
    12
  }

  fn seal_private_key(
    &self,
    seal_key: &SealKey,
    nonce: &[u8],
    private_key: &PrivateKey,
  ) -> SecretStoreResult<PublicData> {
    let mut tag = [0u8; TAG_LENGTH];
    let mut result = symm::encrypt_aead(
      symm::Cipher::aes_256_gcm(),
      &seal_key.borrow(),
      Some(&nonce[0..12]),
      &[],
      &private_key.borrow(),
      &mut tag,
    )?;
    result.extend_from_slice(&tag);

    Ok(result)
  }

  fn open_private_key(&self, seal_key: &SealKey, nonce: &[u8], crypted_key: &[u8]) -> SecretStoreResult<PrivateKey> {
    if crypted_key.len() < TAG_LENGTH {
      return Err(SecretStoreError::Cipher("Data too short".to_string()));
    }
    let tag_offset = crypted_key.len() - TAG_LENGTH;
    let decrypted = symm::decrypt_aead(
      symm::Cipher::aes_256_gcm(),
      &seal_key.borrow(),
      Some(&nonce[0..12]),
      &[],
      &crypted_key[0..tag_offset],
      &crypted_key[tag_offset..],
    )?;

    Ok(SecretBytes::from(decrypted))
  }

  fn encrypt(
    &self,
    recipients: &[(&str, PublicKey)],
    data: &PrivateData,
    mut header_builder: block::header::Builder,
  ) -> SecretStoreResult<PublicData> {
    let mut rng = thread_rng();
    let mut tag = [0u8; TAG_LENGTH];
    let seal_key = SecretBytes::random(&mut rng, 32);
    let mut nonce = [0u8; 12];

    rng.fill_bytes(&mut nonce[..]);

    let mut public_data = symm::encrypt_aead(
      symm::Cipher::aes_256_gcm(),
      &seal_key.borrow(),
      Some(&nonce[..]),
      &[],
      &data.borrow(),
      &mut tag[..],
    )?;
    public_data.extend_from_slice(&tag);

    header_builder.set_type(self.key_type());
    header_builder
      .reborrow()
      .init_common_key(12)
      .copy_from_slice(&nonce[..]);

    let mut recipient_keys = header_builder.init_recipients(recipients.len() as u32);

    for (idx, (recipient_id, recipient_public_key)) in recipients.iter().enumerate() {
      let public_key = Rsa::public_key_from_der(recipient_public_key)?;
      let mut crypled_key_buffer = vec![0u8; public_key.size() as usize];

      let crypted_len = public_key.public_encrypt(&seal_key.borrow(), &mut crypled_key_buffer, Padding::PKCS1_OAEP)?;

      let mut recipient_key = recipient_keys.reborrow().get(idx as u32);

      recipient_key.set_id(recipient_id);
      recipient_key
        .init_crypted_key(crypted_len as u32)
        .copy_from_slice(&crypled_key_buffer[..crypted_len]);
    }

    Ok(public_data)
  }

  fn decrypt(
    &self,
    user: (&str, &PrivateKey),
    header: block::header::Reader,
    crypted: &[u8],
  ) -> SecretStoreResult<PrivateData> {
    if header.get_type()? != self.key_type() {
      return Err(SecretStoreError::Cipher("Invalid block header".to_string()));
    }
    if crypted.len() < TAG_LENGTH {
      return Err(SecretStoreError::Cipher("Data too short".to_string()));
    }
    let nonce = header.get_common_key()?;

    if nonce.len() != 12 {
      return Err(SecretStoreError::Cipher("Invalid nonce".to_string()));
    }

    for recipient in header.get_recipients()?.iter() {
      if user.0 != recipient.get_id()? {
        continue;
      }
      let crypted_key = recipient.get_crypted_key()?;
      let private_key = Rsa::private_key_from_der(&user.1.borrow())?;
      let mut seal_key = SecretBytes::zeroed(crypted_key.len());
      let seal_key_len =
        private_key.private_decrypt(&crypted_key, seal_key.borrow_mut().as_mut(), Padding::PKCS1_OAEP)?;

      if seal_key_len != 32 {
        return Err(SecretStoreError::Cipher("Decrypt seal key failed".to_string()));
      }

      let tag_offset = crypted.len() - TAG_LENGTH;
      let decrypted = symm::decrypt_aead(
        symm::Cipher::aes_256_gcm(),
        &seal_key.borrow()[..32],
        Some(nonce),
        &[],
        &crypted[0..tag_offset],
        &crypted[tag_offset..],
      )?;
      return Ok(SecretBytes::from(decrypted));
    }
    Err(SecretStoreError::NoRecipient)
  }
}