extern crate rand;
extern crate ring;
use anyhow::Result;
use hkdf::Hkdf;
use ring::agreement::{agree_ephemeral, EphemeralPrivateKey, PublicKey, UnparsedPublicKey, X25519};
use ring::rand::SystemRandom;
use ring::{aead::AES_128_GCM, rand::SecureRandom};
use scrypt::{scrypt, Params};
use sha2::Sha256;
use crate::exceptions::Exception;
pub fn generate_key_pair() -> (EphemeralPrivateKey, PublicKey) {
let rng = SystemRandom::new();
let private_key = EphemeralPrivateKey::generate(&X25519, &rng).unwrap();
let public_key = private_key.compute_public_key().unwrap();
(private_key, public_key)
}
pub struct SharedKey {
shared_key: Vec<u8>,
}
impl SharedKey {
pub fn new(
private_key: EphemeralPrivateKey,
public_key: &UnparsedPublicKey<Vec<u8>>,
) -> Result<Self> {
match agree_ephemeral(private_key, public_key, |key| key.to_vec()) {
Ok(shared_key) => Ok(Self { shared_key }),
Err(error) => Err(Exception::DecryptError { error }.into()),
}
}
pub fn scrypt(&mut self, salt: &[u8]) -> Result<Vec<u8>> {
let mut aes_key = [0u8; 16];
match scrypt(
&self.shared_key,
salt,
&Params::new(12, 8, 1, 16).unwrap(),
&mut aes_key,
) {
Ok(()) => Ok(aes_key.to_vec()),
Err(error) => Err(Exception::InvalidOutputLen { error }.into()),
}
}
pub fn hkdf(&mut self, salt: &[u8]) -> [u8; 16] {
let key = Hkdf::<Sha256>::new(Some(salt), &self.shared_key);
let mut aes_key = [0u8; 16];
key.expand(&[], &mut aes_key).unwrap();
aes_key
}
}
pub fn generate_random_salt() -> Vec<u8> {
let rng = SystemRandom::new();
let mut key_bytes = vec![0; AES_128_GCM.key_len()];
rng.fill(&mut key_bytes).unwrap();
key_bytes
}