tpfs_krypt 7.1.8

An interface for accessing secrets
Documentation
use super::{create_shared_secret, decrypt_with_shared_secret, encrypt_with_shared_secret};
use crate::{
    crypto::{
        substrate::siz_thirytwo::{deconstruct_secret_string, to_secret_string},
        RawKeyPair,
    },
    errors::{KeyManagementError, Result},
    EncryptedMessage, KeyIdentifier, KeyType, Signature,
};
use base58::ToBase58;
use failure::_core::fmt::Formatter;
use rand::{thread_rng, CryptoRng, RngCore};
use secrecy::{ExposeSecret, Secret};
use sha2::{Digest, Sha256};
use std::fmt::Debug;
use x25519_dalek::StaticSecret;

type Public = x25519_dalek::PublicKey;

#[derive(Clone, Debug)]
pub struct PublicKey {
    pub(crate) key: Public,
}

impl AsRef<[u8]> for PublicKey {
    fn as_ref(&self) -> &[u8] {
        self.key.as_bytes()
    }
}

impl From<Public> for PublicKey {
    fn from(public: Public) -> PublicKey {
        PublicKey { key: public }
    }
}

impl From<[u8; 32]> for PublicKey {
    fn from(key: [u8; 32]) -> PublicKey {
        PublicKey { key: key.into() }
    }
}

pub(crate) struct DefaultSignature([u8; 64]);

impl AsRef<[u8]> for DefaultSignature {
    fn as_ref(&self) -> &[u8] {
        &self.0[..]
    }
}

impl Signature for DefaultSignature {}

/// A struct for working with the X25519KeyPair types directly that has some x25519_dalek details in
/// here, and should have all the implementations that could be needed for a key manager even though
/// a manager may not use it locally.
#[derive(Clone, Constructor)]
pub struct SharedEncryptionX25519KeyPair {
    pub(crate) static_secret: StaticSecret,
}

impl Debug for SharedEncryptionX25519KeyPair {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "SharedEncryptionX25519KeyPair({:?})",
            Public::from(&self.static_secret)
        )
    }
}

impl From<StaticSecret> for SharedEncryptionX25519KeyPair {
    fn from(ss: StaticSecret) -> Self {
        Self { static_secret: ss }
    }
}

impl SharedEncryptionX25519KeyPair {
    /// Deterministically create a new keypair from some series of byte inputs. The inputs will be
    /// cryptographically hashed together and used as entropy for the new key.
    pub(crate) fn from_hashables<'a, I>(hashables: I) -> Self
    where
        I: IntoIterator<Item = &'a [u8]>,
    {
        // hash privkey together with input
        let mut hasher = Sha256::new();
        for i in hashables.into_iter() {
            hasher.update(i);
        }
        let result = hasher.finalize();

        let mut private_key = [0u8; 32];
        private_key.copy_from_slice(&result[..32]);

        Self::new(private_key.into())
    }

    pub(crate) fn shared_encrypt(
        &self,
        other_public_key: &PublicKey,
        message: &[u8],
        ephemeral_input: &[u8],
    ) -> Result<EncryptedMessage> {
        let sender_dh_key = self.derive_ephemeral_key(ephemeral_input);

        let shared_key = create_shared_secret(
            &other_public_key.key,
            &Secret::new(sender_dh_key.static_secret.to_bytes()),
        );
        let hashables: Vec<&[u8]> = vec![shared_key.expose_secret().as_bytes()];
        let shared_derived = SharedEncryptionX25519KeyPair::from_hashables(hashables);

        let mut rng = thread_rng();
        let ciphertext = encrypt_with_shared_secret(
            &shared_derived.static_secret.to_bytes(),
            message,
            &mut rng,
        )?;
        Ok(EncryptedMessage {
            sender_key: sender_dh_key.public().key.to_bytes(),
            ciphertext,
        })
    }

    pub(crate) fn shared_decrypt(
        &self,
        other_public_key: &PublicKey,
        cipher: &[u8],
        ephemeral_input: Option<&[u8]>,
    ) -> Result<Secret<Vec<u8>>> {
        let some_ephemeral_key: SharedEncryptionX25519KeyPair;
        let decryption_key = match ephemeral_input {
            Some(input) => {
                some_ephemeral_key = self.derive_ephemeral_key(input);
                &some_ephemeral_key
            }
            None => self,
        };
        let decryption_secret = Secret::new(decryption_key.static_secret.to_bytes());
        let shared_key = create_shared_secret(&other_public_key.key, &decryption_secret);
        let hashables: Vec<&[u8]> = vec![shared_key.expose_secret().as_bytes()];
        let shared_derived = SharedEncryptionX25519KeyPair::from_hashables(hashables);

        decrypt_with_shared_secret(&shared_derived.static_secret.to_bytes(), cipher)
    }

    fn derive_ephemeral_key(&self, deterministic_input: &[u8]) -> SharedEncryptionX25519KeyPair {
        let secret = Secret::new(self.static_secret.to_bytes());
        let hashables: Vec<&[u8]> = vec![secret.expose_secret().as_ref(), deterministic_input];
        SharedEncryptionX25519KeyPair::from_hashables(hashables)
    }
}

impl RawKeyPair for SharedEncryptionX25519KeyPair {
    type PublicKey = PublicKey;
    type Signature = DefaultSignature;
    const KEY_TYPE: KeyType = KeyType::SharedEncryptionX25519;

    fn from_strings(secret: Secret<String>) -> Result<Self> {
        let (entropy, derive_paths) = deconstruct_secret_string(secret)?;

        if !derive_paths.is_empty() {
            return Err(KeyManagementError::DerivationsNotSupported {
                key_type: Self::KEY_TYPE,
            });
        }

        Ok(Self::new((*entropy.expose_secret()).into()))
    }

    fn from_secret(secret: Secret<String>) -> Result<Self> {
        Self::from_strings(secret)
    }

    fn generate_with<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self> {
        let static_secret = StaticSecret::new(rng);
        Ok(static_secret.into())
    }

    fn sign(&self, _: &[u8]) -> Result<Self::Signature> {
        Err(KeyManagementError::SigningNotSupported {
            key_type: Self::KEY_TYPE,
        })
    }

    fn identifier(&self) -> KeyIdentifier {
        KeyIdentifier {
            value: self.public().as_ref().to_base58(),
            key_type: Self::KEY_TYPE,
        }
    }

    fn to_secret(&self) -> Result<Secret<String>> {
        to_secret_string(&Secret::new(self.static_secret.to_bytes()), &[])
    }

    fn public(&self) -> Self::PublicKey {
        Public::from(&self.static_secret).into()
    }
}