Browse Source

x3dh: Document hkdf and hmac.

Luther Blissett 3 years ago
parent
commit
d513af596d
3 changed files with 32 additions and 11 deletions
  1. 1 0
      script/research/x3dh/Cargo.toml
  2. 21 4
      script/research/x3dh/src/hkdf.rs
  3. 10 7
      script/research/x3dh/src/hmac.rs

+ 1 - 0
script/research/x3dh/Cargo.toml

@@ -8,6 +8,7 @@ edition = "2021"
 [dependencies]
 anyhow = "1.0.56"
 sha2 = "0.10.6"
+digest = "0.10.5"
 rand = "0.7.3"
 crypto_api_chachapoly = "0.5.0"
 curve25519-dalek = "3.2.1"

+ 21 - 4
script/research/x3dh/src/hkdf.rs

@@ -1,12 +1,14 @@
+//! HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
 //! https://tools.ietf.org/html/rfc5869
 use core::fmt;
-use sha2::{
-    digest::{crypto_common::BlockSizeUser, typenum::Unsigned, Output, OutputSizeUser, Update},
-    Digest,
+
+use digest::{
+    crypto_common::BlockSizeUser, typenum::Unsigned, Digest, Output, OutputSizeUser, Update,
 };
 
 use super::hmac::Hmac;
 
+/// Structure for InvalidPrkLength, used for output error handling.
 #[derive(Copy, Clone, Debug)]
 pub struct InvalidPrkLength;
 
@@ -16,7 +18,7 @@ impl fmt::Display for InvalidPrkLength {
     }
 }
 
-// Structure for InvalidLength, used for output error handling.
+/// Structure for InvalidLength, used for output error handling.
 #[derive(Copy, Clone, Debug)]
 pub struct InvalidLength;
 
@@ -26,20 +28,26 @@ impl fmt::Display for InvalidLength {
     }
 }
 
+/// HKDF-Extract for arbitrary hash functions implementing `Digest`
+/// and `BlockSizeUser` traits.
 #[derive(Clone)]
 pub struct HkdfExtract<H: Digest + BlockSizeUser + Clone> {
     hmac: Hmac<H>,
 }
 
 impl<H: Digest + BlockSizeUser + Clone> HkdfExtract<H> {
+    /// Iniitialize a new `HkdfExtract` with the given salt.
     pub fn new(salt: &[u8]) -> Self {
         Self { hmac: Hmac::<H>::new_from_slice(salt) }
     }
 
+    /// Feeds in additional input key material to the HKDF-Extract context.
     pub fn input_ikm(&mut self, ikm: &[u8]) {
         self.hmac.update(ikm);
     }
 
+    /// Completes the HKDF-Extract operation, returning both the generated
+    /// pseudorandom key and `Hkdf` struct for expanding.
     pub fn finalize(self) -> (Output<H>, Hkdf<H>) {
         let prk = self.hmac.finalize();
         let hkdf = Hkdf::from_prk(&prk).expect("PRK size is correct");
@@ -47,23 +55,30 @@ impl<H: Digest + BlockSizeUser + Clone> HkdfExtract<H> {
     }
 }
 
+/// Structure representing the HKDF, capable of HKDF-Expand
+/// and HKDF-Extract operations.
 #[derive(Clone)]
 pub struct Hkdf<H: Digest + BlockSizeUser + Clone> {
     hmac: Hmac<H>,
 }
 
 impl<H: Digest + BlockSizeUser + Clone> Hkdf<H> {
+    /// Convenience method for `extract` when the generated pseudorandom
+    /// key can be ignored and only the HKDF-Expand operation is needed.
     pub fn new(salt: &[u8], ikm: &[u8]) -> Self {
         let (_, hkdf) = Self::extract(salt, ikm);
         hkdf
     }
 
+    /// HKDF-Extract operation returning both the generated pseudorandom
+    /// key and `Hkdf` struct for expanding.
     pub fn extract(salt: &[u8], ikm: &[u8]) -> (Output<H>, Self) {
         let mut extract_ctx = HkdfExtract::new(salt);
         extract_ctx.input_ikm(ikm);
         extract_ctx.finalize()
     }
 
+    /// Create `Hkdf` from an already cryptographically strong pseudorandom key.
     pub fn from_prk(prk: &[u8]) -> Result<Self, InvalidPrkLength> {
         if prk.len() < <H as OutputSizeUser>::OutputSize::to_usize() {
             return Err(InvalidPrkLength)
@@ -72,6 +87,8 @@ impl<H: Digest + BlockSizeUser + Clone> Hkdf<H> {
         Ok(Self { hmac: Hmac::<H>::new_from_slice(prk) })
     }
 
+    /// HKDF-Expand operation. If you don't have any `info` to pass, use
+    /// an empty slice.
     pub fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
         self.expand_multi_info(&[info], okm)
     }

+ 10 - 7
script/research/x3dh/src/hmac.rs

@@ -1,10 +1,8 @@
 //! HMAC simplementation.
-use sha2::{
-    digest::{
-        core_api::Block, crypto_common::BlockSizeUser, Digest, FixedOutput, Output, OutputSizeUser,
-        Update,
-    },
-    Sha256,
+//! https://en.wikipedia.org/wiki/Hmac
+use digest::{
+    core_api::Block, crypto_common::BlockSizeUser, Digest, FixedOutput, Output, OutputSizeUser,
+    Update,
 };
 
 const IPAD: u8 = 0x36;
@@ -21,7 +19,7 @@ fn get_der_key<D: Digest + BlockSizeUser + Clone>(key: &[u8]) -> Block<D> {
         return der_key
     }
 
-    let hash = Sha256::digest(key);
+    let hash = D::digest(key);
     // All commonly used hash functions have block size bigger than
     // output hash size, but to be extra rigorous we handle the
     // potential uncommon cases as well. The condition is calculated
@@ -36,6 +34,8 @@ fn get_der_key<D: Digest + BlockSizeUser + Clone>(key: &[u8]) -> Block<D> {
     der_key
 }
 
+/// HMAC for arbitrary hash functions that implement `Digest`
+/// and `BlockSizeUser` traits.
 #[derive(Clone)]
 pub struct Hmac<D: Digest + BlockSizeUser + Clone> {
     digest: D,
@@ -43,6 +43,7 @@ pub struct Hmac<D: Digest + BlockSizeUser + Clone> {
 }
 
 impl<D: Digest + BlockSizeUser + Clone> Hmac<D> {
+    /// Initialize a new `Hmac` with the given key.
     #[inline]
     pub fn new_from_slice(key: &[u8]) -> Self {
         let der_key = get_der_key::<D>(key);
@@ -63,6 +64,7 @@ impl<D: Digest + BlockSizeUser + Clone> Hmac<D> {
         Self { digest, opad_key }
     }
 
+    /// Finalize the HMAC
     pub fn finalize(self) -> Output<D> {
         Output::<D>::clone_from_slice(&self.finalize_fixed())
     }
@@ -82,6 +84,7 @@ impl<D: Digest + BlockSizeUser + Clone> OutputSizeUser for Hmac<D> {
 }
 
 impl<D: Digest + BlockSizeUser + Clone> Update for Hmac<D> {
+    /// Update the HMAC with the given data.
     fn update(&mut self, data: &[u8]) {
         self.digest.update(data);
     }