use crate::{CryptoError, CryptoResult, KEY_SIZE};
use argon2::{password_hash::SaltString, Argon2, PasswordHasher};
use ed25519_dalek::{SigningKey, VerifyingKey};
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct MasterKey {
key: [u8; KEY_SIZE],
}
impl MasterKey {
pub fn derive_from_password(password: &str, salt: &[u8]) -> CryptoResult<Self> {
let argon2 = Argon2::default();
let salt_string = SaltString::encode_b64(salt)
.map_err(|e| CryptoError::KeyDerivation(e.to_string()))?;
let hash = argon2
.hash_password(password.as_bytes(), &salt_string)
.map_err(|e| CryptoError::KeyDerivation(e.to_string()))?;
let hash_bytes = hash.hash.ok_or_else(|| {
CryptoError::KeyDerivation("No hash output".to_string())
})?;
let mut key = [0u8; KEY_SIZE];
key.copy_from_slice(&hash_bytes.as_bytes()[..KEY_SIZE]);
Ok(Self { key })
}
pub fn generate() -> CryptoResult<Self> {
let mut key = [0u8; KEY_SIZE];
rand::RngCore::fill_bytes(&mut OsRng, &mut key);
Ok(Self { key })
}
pub fn as_bytes(&self) -> &[u8; KEY_SIZE] {
&self.key
}
pub fn generate_salt() -> [u8; 16] {
let mut salt = [0u8; 16];
rand::RngCore::fill_bytes(&mut OsRng, &mut salt);
salt
}
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct DerivedKeys {
pub kek: [u8; KEY_SIZE],
pub auth_key: [u8; KEY_SIZE],
}
impl DerivedKeys {
pub fn derive_from_master(master: &MasterKey) -> Self {
let kek = *blake3::keyed_hash(master.as_bytes(), b"firecloud-kek-v1").as_bytes();
let auth_key = *blake3::keyed_hash(master.as_bytes(), b"firecloud-auth-v1").as_bytes();
Self { kek, auth_key }
}
}
#[derive(Clone)]
pub struct KeyPair {
signing_key: SigningKey,
}
impl KeyPair {
pub fn generate() -> Self {
let signing_key = SigningKey::generate(&mut OsRng);
Self { signing_key }
}
pub fn from_seed(seed: &[u8; 32]) -> Self {
let signing_key = SigningKey::from_bytes(seed);
Self { signing_key }
}
pub fn public_key(&self) -> VerifyingKey {
self.signing_key.verifying_key()
}
pub fn public_key_bytes(&self) -> [u8; 32] {
self.public_key().to_bytes()
}
pub fn sign(&self, message: &[u8]) -> [u8; 64] {
use ed25519_dalek::Signer;
self.signing_key.sign(message).to_bytes()
}
pub fn verify(&self, message: &[u8], signature: &[u8; 64]) -> CryptoResult<()> {
use ed25519_dalek::{Signature, Verifier};
let sig = Signature::from_bytes(signature);
self.public_key()
.verify(message, &sig)
.map_err(|_| CryptoError::SignatureVerification)
}
pub fn to_bytes(&self) -> [u8; 32] {
self.signing_key.to_bytes()
}
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
Self {
signing_key: SigningKey::from_bytes(bytes),
}
}
}
pub fn generate_dek() -> [u8; KEY_SIZE] {
let mut dek = [0u8; KEY_SIZE];
rand::RngCore::fill_bytes(&mut OsRng, &mut dek);
dek
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptedDek {
pub ciphertext: Vec<u8>,
pub nonce: [u8; 24],
}