//! Symmetric cypher stuff use ::zeroize::Zeroize; /// Secret, used for keys. /// Grants that on drop() we will zero out memory #[derive(Zeroize)] #[zeroize(drop)] #[allow(missing_debug_implementations)] pub struct Secret { secret: [u8; 32], } impl Secret { /// return a reference to the secret pub fn as_ref(&self) -> &[u8; 32] { &self.secret } } impl From<::x25519_dalek::SharedSecret> for Secret { fn from(shared_secret: ::x25519_dalek::SharedSecret) -> Self { Self { secret: shared_secret.to_bytes(), } } } /// List of possible Ciphers #[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)] #[repr(u8)] pub enum CipherKind { /// Chaha20_Poly1305 Chacha20Poly1305 = 0, } impl CipherKind { /// required length of the nonce pub fn nonce_len(&self) -> usize { ::ring::aead::CHACHA20_POLY1305.nonce_len() } /// required length of the key pub fn key_len(&self) -> usize { ::ring::aead::CHACHA20_POLY1305.key_len() } /// Length of the authentication tag pub fn tag_len(&self) -> usize { ::ring::aead::CHACHA20_POLY1305.tag_len() } } /// actual ciphers #[derive(Debug)] pub enum Cipher { /// Cipher Chaha20_Poly1305 Chacha20Poly1305(Chacha20Poly1305), } impl Cipher { /// Build a new Cipher pub fn new(kind: CipherKind, secret: Secret) -> Self { match kind { CipherKind::Chacha20Poly1305 => { Self::Chacha20Poly1305(Chacha20Poly1305::new(secret)) } } } } /// Chacha20Poly1305 cipher #[derive(Debug)] pub struct Chacha20Poly1305 { cipher: ::ring::aead::OpeningKey, } impl Chacha20Poly1305 { /// Initialize the cipher with the given nonce pub fn with_nonce(key: Secret, nonce: Nonce) -> Self { let unbound_key = ::ring::aead::UnboundKey::new( &::ring::aead::CHACHA20_POLY1305, key.as_ref(), ) .unwrap(); use ::ring::aead::BoundKey; Self { cipher: ::ring::aead::OpeningKey::::new(unbound_key, nonce), } } /// Initialize a new ChachaPoly20 cipher with a random nonce pub fn new(key: Secret) -> Self { Self::with_nonce(key, Nonce::new()) } } #[derive(Debug, Copy, Clone)] #[repr(C)] #[allow(missing_debug_implementations)] struct NonceNum { high: u32, low: u64, } /// Nonce with sequence for chach20_apoly1305 #[repr(C)] pub union Nonce { num: NonceNum, // ring::aead::Nonce does not implement 'Copy' // even though it's just [u8;12] raw: ::core::mem::ManuallyDrop<::ring::aead::Nonce>, easy_from: [u8; 12], } impl ::core::fmt::Debug for Nonce { fn fmt( &self, f: &mut core::fmt::Formatter<'_>, ) -> Result<(), ::std::fmt::Error> { // use the Debug from NonceNum #[allow(unsafe_code)] unsafe { core::fmt::Debug::fmt(&self.num, f) } } } impl Nonce { // FIXME: nonces should be random! /// Generate a new random Nonce pub fn new() -> Self { #[allow(unsafe_code)] unsafe { Self { num: NonceNum { high: 42, low: 69 }, } } } /// Create Nonce from array pub fn from_slice(raw: [u8; 12]) -> Self { #[allow(unsafe_code)] unsafe { Self { easy_from: raw } } } } impl Clone for Nonce { fn clone(&self) -> Self { #[allow(unsafe_code)] unsafe { Self { num: self.num } } } } impl ::ring::aead::NonceSequence for Nonce { fn advance( &mut self, ) -> Result<::ring::aead::Nonce, ::ring::error::Unspecified> { #[allow(unsafe_code)] unsafe { let old_low = self.num.low; self.num.low = self.num.low + 1; if self.num.low < old_low { self.num.high = self.num.high; } Ok(::core::mem::ManuallyDrop::take(&mut self.raw)) } } }