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 {}
#[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 {
pub(crate) fn from_hashables<'a, I>(hashables: I) -> Self
where
I: IntoIterator<Item = &'a [u8]>,
{
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()
}
}