use std::borrow::Borrow;
use std::ops::{Deref, DerefMut};
use chacha20poly1305::aead::rand_core::RngCore;
use hmac::Mac;
use crate::crypto::{Decryptor, DefaultEncryptor, Encryptor, MacaroonHmac};
pub const NONCE_BYTES: usize = 12usize;
pub const KEY_BYTES: usize = 32usize;
const KEY_GENERATOR: MacaroonKey = MacaroonKey(*b"macaroons-key-generator\0\0\0\0\0\0\0\0\0");
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MacaroonKey(pub [u8; KEY_BYTES]);
impl AsRef<[u8; KEY_BYTES]> for MacaroonKey {
fn as_ref(&self) -> &[u8; KEY_BYTES] {
&self.0
}
}
impl AsRef<[u8]> for MacaroonKey {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Borrow<[u8; KEY_BYTES]> for MacaroonKey {
fn borrow(&self) -> &[u8; KEY_BYTES] {
&self.0
}
}
impl Deref for MacaroonKey {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for MacaroonKey {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<[u8; KEY_BYTES]> for MacaroonKey {
fn from(b: [u8; KEY_BYTES]) -> Self {
MacaroonKey(b)
}
}
impl From<&[u8; KEY_BYTES]> for MacaroonKey {
fn from(b: &[u8; KEY_BYTES]) -> Self {
MacaroonKey(*b)
}
}
impl From<Vec<u8>> for MacaroonKey {
fn from(bytes: Vec<u8>) -> Self {
if bytes.len() < KEY_BYTES {
panic!("invalid key size {} != {}", bytes.len(), KEY_BYTES)
}
let mut ret: [u8; KEY_BYTES] = [0; KEY_BYTES];
for (i, b) in bytes.iter().enumerate() {
if i == KEY_BYTES {
break;
}
ret[i] = *b;
}
MacaroonKey(ret)
}
}
impl MacaroonKey {
pub fn generate_random() -> Self {
let mut rng = rand::thread_rng();
let mut key: [u8; KEY_BYTES] = [0; KEY_BYTES];
rng.fill_bytes(&mut key);
MacaroonKey(key)
}
pub fn generate(seed: &[u8]) -> Self {
generate_derived_key(seed)
}
}
fn generate_derived_key(key: &[u8]) -> MacaroonKey {
hmac(&KEY_GENERATOR, key)
}
pub fn hmac<T, U>(key: &T, text: &U) -> MacaroonKey
where
T: AsRef<[u8; KEY_BYTES]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
let mut mac = <MacaroonHmac as Mac>::new_from_slice(key.as_ref())
.expect("could not create Hmac");
mac.update(text.as_ref());
let bytes = mac.finalize().into_bytes().to_vec();
bytes.into()
}
pub fn hmac2<T, U>(key: &T, text1: &U, text2: &U) -> MacaroonKey
where
T: AsRef<[u8; KEY_BYTES]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
let MacaroonKey(tmp1) = hmac(key, text1);
let MacaroonKey(tmp2) = hmac(key, text2);
let tmp = [tmp1, tmp2].concat();
hmac(key, &tmp)
}
pub fn encrypt_key<T>(key: &T, plaintext: &T) -> Vec<u8>
where
T: AsRef<[u8; KEY_BYTES]> + ?Sized
{
DefaultEncryptor::encrypt(key, plaintext.as_ref()).unwrap()
}
pub fn decrypt_key<T, U>(key: &T, data: &U) -> crate::Result<MacaroonKey>
where
T: AsRef<[u8; KEY_BYTES]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
DefaultEncryptor::decrypt(key, data.as_ref())
}