mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-18 13:24:38 +03:00
chore: Move hashing functions into sodium/ciphers crate
This finishes the last step of removing sodium.rs from the rosenpass crate itself and also removes the NOTHING and NONCE0 constants. Hashing functions now use destination parameters; rosenpass_constant_time::xor now does too.
This commit is contained in:
committed by
Karolin Varner
parent
d44793e07f
commit
09aa0e027e
17
Cargo.lock
generated
17
Cargo.lock
generated
@@ -1074,6 +1074,7 @@ dependencies = [
|
|||||||
"rosenpass-ciphers",
|
"rosenpass-ciphers",
|
||||||
"rosenpass-constant-time",
|
"rosenpass-constant-time",
|
||||||
"rosenpass-sodium",
|
"rosenpass-sodium",
|
||||||
|
"rosenpass-to",
|
||||||
"rosenpass-util",
|
"rosenpass-util",
|
||||||
"serde",
|
"serde",
|
||||||
"stacker",
|
"stacker",
|
||||||
@@ -1087,12 +1088,20 @@ dependencies = [
|
|||||||
name = "rosenpass-ciphers"
|
name = "rosenpass-ciphers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"rosenpass-constant-time",
|
||||||
"rosenpass-sodium",
|
"rosenpass-sodium",
|
||||||
|
"rosenpass-to",
|
||||||
|
"static_assertions",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rosenpass-constant-time"
|
name = "rosenpass-constant-time"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rosenpass-to",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rosenpass-fuzzing"
|
name = "rosenpass-fuzzing"
|
||||||
@@ -1103,6 +1112,7 @@ dependencies = [
|
|||||||
"rosenpass",
|
"rosenpass",
|
||||||
"rosenpass-ciphers",
|
"rosenpass-ciphers",
|
||||||
"rosenpass-sodium",
|
"rosenpass-sodium",
|
||||||
|
"rosenpass-to",
|
||||||
"stacker",
|
"stacker",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1113,6 +1123,7 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"libsodium-sys-stable",
|
"libsodium-sys-stable",
|
||||||
"log",
|
"log",
|
||||||
|
"rosenpass-to",
|
||||||
"rosenpass-util",
|
"rosenpass-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1712,6 +1723,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "0.6.6"
|
version = "0.6.6"
|
||||||
|
|||||||
@@ -10,4 +10,9 @@ repository = "https://github.com/rosenpass/rosenpass"
|
|||||||
readme = "readme.md"
|
readme = "readme.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.75"
|
||||||
rosenpass-sodium = { path = "../sodium" }
|
rosenpass-sodium = { path = "../sodium" }
|
||||||
|
rosenpass-to = { path = "../to" }
|
||||||
|
rosenpass-constant-time = { path = "../constant-time" }
|
||||||
|
static_assertions = "1.1.0"
|
||||||
|
zeroize = "1.7.0"
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
|
use static_assertions::const_assert;
|
||||||
|
|
||||||
|
pub mod subtle;
|
||||||
|
|
||||||
|
pub const KEY_LEN: usize = 32;
|
||||||
|
const_assert!(KEY_LEN == aead::KEY_LEN);
|
||||||
|
const_assert!(KEY_LEN == xaead::KEY_LEN);
|
||||||
|
const_assert!(KEY_LEN == hash::KEY_LEN);
|
||||||
|
|
||||||
|
/// Authenticated encryption with associated data
|
||||||
pub mod aead {
|
pub mod aead {
|
||||||
pub use rosenpass_sodium::aead::chacha20poly1305_ietf::{
|
pub use rosenpass_sodium::aead::chacha20poly1305_ietf::{
|
||||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Authenticated encryption with associated data with a constant nonce
|
||||||
pub mod xaead {
|
pub mod xaead {
|
||||||
pub use rosenpass_sodium::aead::xchacha20poly1305_ietf::{
|
pub use rosenpass_sodium::aead::xchacha20poly1305_ietf::{
|
||||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod hash {
|
||||||
|
pub use crate::subtle::incorrect_hmac_blake2b::{
|
||||||
|
hash, KEY_LEN, KEY_MAX, KEY_MIN, OUT_MAX, OUT_MIN,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
44
ciphers/src/subtle/incorrect_hmac_blake2b.rs
Normal file
44
ciphers/src/subtle/incorrect_hmac_blake2b.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
use anyhow::ensure;
|
||||||
|
use rosenpass_constant_time::xor;
|
||||||
|
use rosenpass_sodium::hash::blake2b;
|
||||||
|
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||||
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
pub const KEY_LEN: usize = 32;
|
||||||
|
pub const KEY_MIN: usize = KEY_LEN;
|
||||||
|
pub const KEY_MAX: usize = KEY_LEN;
|
||||||
|
pub const OUT_MIN: usize = blake2b::OUT_MIN;
|
||||||
|
pub const OUT_MAX: usize = blake2b::OUT_MAX;
|
||||||
|
|
||||||
|
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||||
|
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||||
|
///
|
||||||
|
/// It accepts 32 byte keys, exclusively.
|
||||||
|
///
|
||||||
|
/// This will be replaced, likely by Kekkac at some point soon.
|
||||||
|
/// <https://github.com/rosenpass/rosenpass/pull/145>
|
||||||
|
#[inline]
|
||||||
|
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||||
|
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||||
|
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||||
|
|
||||||
|
with_destination(|out: &mut [u8]| {
|
||||||
|
// Not bothering with padding; the implementation
|
||||||
|
// uses appropriately sized keys.
|
||||||
|
ensure!(key.len() == KEY_LEN);
|
||||||
|
|
||||||
|
type Key = Zeroizing<[u8; KEY_LEN]>;
|
||||||
|
let mut tmp_key = Key::default();
|
||||||
|
|
||||||
|
copy_slice(key).to(tmp_key.as_mut());
|
||||||
|
xor(&IPAD).to(tmp_key.as_mut());
|
||||||
|
let mut outer_data = Key::default();
|
||||||
|
blake2b::hash(tmp_key.as_ref(), data).to(outer_data.as_mut())?;
|
||||||
|
|
||||||
|
copy_slice(key).to(tmp_key.as_mut());
|
||||||
|
xor(&OPAD).to(tmp_key.as_mut());
|
||||||
|
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
1
ciphers/src/subtle/mod.rs
Normal file
1
ciphers/src/subtle/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod incorrect_hmac_blake2b;
|
||||||
@@ -12,3 +12,4 @@ readme = "readme.md"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rosenpass-to = { path = "../to" }
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
/// Xors a and b element-wise and writes the result into a.
|
use rosenpass_to::{with_destination, To};
|
||||||
|
|
||||||
|
/// Xors the source into the destination
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use rosenpass_constant_time::xor_into;
|
/// use rosenpass_constant_time::xor;
|
||||||
/// let mut a = String::from("hello").into_bytes();
|
/// use rosenpass_to::To;
|
||||||
/// let b = b"world";
|
/// assert_eq!(
|
||||||
/// xor_into(&mut a, b);
|
/// xor(b"world").to_this(|| b"hello".to_vec()),
|
||||||
/// assert_eq!(&a, b"\x1f\n\x1e\x00\x0b");
|
/// b"\x1f\n\x1e\x00\x0b");
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If source and destination are of different sizes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn xor_into(a: &mut [u8], b: &[u8]) {
|
pub fn xor<'a>(src: &'a [u8]) -> impl To<[u8], ()> + 'a {
|
||||||
assert!(a.len() == b.len());
|
with_destination(|dst: &mut [u8]| {
|
||||||
for (av, bv) in a.iter_mut().zip(b.iter()) {
|
assert!(src.len() == dst.len());
|
||||||
*av ^= *bv;
|
for (dv, sv) in dst.iter_mut().zip(src.iter()) {
|
||||||
}
|
*dv ^= *sv;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ path = "../sodium"
|
|||||||
[dependencies.rosenpass-ciphers]
|
[dependencies.rosenpass-ciphers]
|
||||||
path = "../ciphers"
|
path = "../ciphers"
|
||||||
|
|
||||||
|
[dependencies.rosenpass-to]
|
||||||
|
path = "../to"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "fuzz_handle_msg"
|
name = "fuzz_handle_msg"
|
||||||
path = "fuzz_targets/handle_msg.rs"
|
path = "fuzz_targets/handle_msg.rs"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ extern crate rosenpass;
|
|||||||
|
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
|
|
||||||
use rosenpass::sodium::mac_into;
|
use rosenpass_sodium::{hash::blake2b, init as sodium_init};
|
||||||
use rosenpass_sodium::init as sodium_init;
|
use rosenpass_to::To;
|
||||||
|
|
||||||
#[derive(arbitrary::Arbitrary, Debug)]
|
#[derive(arbitrary::Arbitrary, Debug)]
|
||||||
pub struct Blake2b {
|
pub struct Blake2b {
|
||||||
@@ -18,5 +18,5 @@ fuzz_target!(|input: Blake2b| {
|
|||||||
|
|
||||||
let mut out = [0u8; 32];
|
let mut out = [0u8; 32];
|
||||||
|
|
||||||
mac_into(&mut out, &input.key, &input.data).unwrap();
|
blake2b::hash(&input.key, &input.data).to(&mut out).unwrap();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ rosenpass-util = { path = "../util" }
|
|||||||
rosenpass-constant-time = { path = "../constant-time" }
|
rosenpass-constant-time = { path = "../constant-time" }
|
||||||
rosenpass-sodium = { path = "../sodium" }
|
rosenpass-sodium = { path = "../sodium" }
|
||||||
rosenpass-ciphers = { path = "../ciphers" }
|
rosenpass-ciphers = { path = "../ciphers" }
|
||||||
|
rosenpass-to = { path = "../to" }
|
||||||
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
memoffset = "0.9.0"
|
memoffset = "0.9.0"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
//! Pseudo Random Functions (PRFs) with a tree-like label scheme which
|
//! Pseudo Random Functions (PRFs) with a tree-like label scheme which
|
||||||
//! ensures their uniqueness
|
//! ensures their uniqueness
|
||||||
|
|
||||||
use {
|
|
||||||
crate::{prftree::PrfTree, sodium::KEY_SIZE},
|
use crate::prftree::PrfTree;
|
||||||
anyhow::Result,
|
use anyhow::Result;
|
||||||
};
|
use rosenpass_ciphers::KEY_LEN;
|
||||||
|
|
||||||
pub fn protocol() -> Result<PrfTree> {
|
pub fn protocol() -> Result<PrfTree> {
|
||||||
PrfTree::zero().mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s".as_bytes())
|
PrfTree::zero().mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s".as_bytes())
|
||||||
@@ -30,7 +30,7 @@ prflabel!(protocol, _ckextract, "chaining key extract");
|
|||||||
|
|
||||||
macro_rules! prflabel_leaf {
|
macro_rules! prflabel_leaf {
|
||||||
($base:ident, $name:ident, $($lbl:expr),* ) => {
|
($base:ident, $name:ident, $($lbl:expr),* ) => {
|
||||||
pub fn $name() -> Result<[u8; KEY_SIZE]> {
|
pub fn $name() -> Result<[u8; KEY_LEN]> {
|
||||||
let t = $base()?;
|
let t = $base()?;
|
||||||
$( let t = t.mix($lbl.as_bytes())?; )*
|
$( let t = t.mix($lbl.as_bytes())?; )*
|
||||||
Ok(t.into_value())
|
Ok(t.into_value())
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#[macro_use]
|
|
||||||
pub mod sodium;
|
|
||||||
pub mod coloring;
|
pub mod coloring;
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub mod labeled_prf;
|
pub mod labeled_prf;
|
||||||
|
|||||||
@@ -17,23 +17,16 @@
|
|||||||
//!
|
//!
|
||||||
//! TODO Base the construction on a proper Dec function
|
//! TODO Base the construction on a proper Dec function
|
||||||
|
|
||||||
pub struct Iprf([u8; KEY_SIZE]);
|
use rosenpass_ciphers::{KEY_LEN, hash};
|
||||||
pub struct IprfBranch([u8; KEY_SIZE]);
|
|
||||||
pub struct SecretIprf(Secret<KEY_SIZE>);
|
|
||||||
pub struct SecretIprfBranch(Secret<KEY_SIZE>);
|
|
||||||
|
|
||||||
pub fn prf_into(out: &mut [u8], key: &[u8], data: &[u8]) {
|
pub struct Iprf([u8; KEY_LEN]);
|
||||||
// TODO: The error handling with sodium is a scurge
|
pub struct IprfBranch([u8; KEY_LEN]);
|
||||||
hmac_into(out, key, data).unwrap()
|
pub struct SecretIprf(Secret<KEY_LEN>);
|
||||||
}
|
pub struct SecretIprfBranch(Secret<KEY_LEN>);
|
||||||
|
|
||||||
pub fn prf(key: &[u8], data: &[u8]) -> [u8; KEY_SIZE] {
|
|
||||||
mutating([0u8; KEY_SIZE], |r| prf_into(r, key, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iprf {
|
impl Iprf {
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
Self([0u8; KEY_SIZE])
|
Self([0u8; KEY_LEN])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dup(self) -> IprfBranch {
|
fn dup(self) -> IprfBranch {
|
||||||
@@ -42,25 +35,25 @@ impl Iprf {
|
|||||||
|
|
||||||
// TODO: Protocol! Use domain separation to ensure that
|
// TODO: Protocol! Use domain separation to ensure that
|
||||||
fn mix(self, v: &[u8]) -> Self {
|
fn mix(self, v: &[u8]) -> Self {
|
||||||
Self(prf(&self.0, v))
|
Self(hash(&self.0, v).collect<[u8; KEY_LEN]>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mix_secret<const N: usize>(self, v: Secret<N>) -> SecretIprf {
|
fn mix_secret<const N: usize>(self, v: Secret<N>) -> SecretIprf {
|
||||||
SecretIprf::prf_invoc(&self.0, v.secret())
|
SecretIprf::prf_invoc(&self.0, v.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_value(self) -> [u8; KEY_SIZE] {
|
fn into_value(self) -> [u8; KEY_LEN] {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(self, v: &[u8], dst: &mut [u8]) {
|
fn extract(self, v: &[u8], dst: &mut [u8]) {
|
||||||
prf_into(&self.0, v, dst)
|
hash(&self.0, v).to(dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IprfBranch {
|
impl IprfBranch {
|
||||||
fn mix(&self, v: &[u8]) -> Iprf {
|
fn mix(&self, v: &[u8]) -> Iprf {
|
||||||
Iprf(prf(self.0, v))
|
Iprf(hash(self.0, v).collect<[u8; KEY_LEN]>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mix_secret<const N: usize>(&self, v: Secret<N>) -> SecretIprf {
|
fn mix_secret<const N: usize>(&self, v: Secret<N>) -> SecretIprf {
|
||||||
@@ -71,7 +64,7 @@ impl IprfBranch {
|
|||||||
impl SecretIprf {
|
impl SecretIprf {
|
||||||
fn prf_invoc(k: &[u8], d: &[u8]) -> SecretIprf {
|
fn prf_invoc(k: &[u8], d: &[u8]) -> SecretIprf {
|
||||||
mutating(SecretIprf(Secret::zero()), |r| {
|
mutating(SecretIprf(Secret::zero()), |r| {
|
||||||
prf_into(k, d, r.secret_mut())
|
hash(k, d).to(r.secret_mut())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,12 +80,12 @@ impl SecretIprf {
|
|||||||
Self::prf_invoc(self.0.secret(), v.secret())
|
Self::prf_invoc(self.0.secret(), v.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_secret(self) -> Secret<KEY_SIZE> {
|
fn into_secret(self) -> Secret<KEY_LEN> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_secret_slice(self, v: &[u8], dst: &[u8]) {
|
fn into_secret_slice(self, v: &[u8], dst: &[u8]) {
|
||||||
prf_into(self.0.secret(), v, dst)
|
hash(self.0.secret(), v).to(dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,8 @@
|
|||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use super::RosenpassError;
|
use super::RosenpassError;
|
||||||
use crate::{pqkem::*, sodium};
|
use crate::pqkem::*;
|
||||||
use rosenpass_ciphers::{aead, xaead};
|
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||||
|
|
||||||
// Macro magic ////////////////////////////////////////////////////////////////
|
// Macro magic ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -265,9 +265,9 @@ data_lense! { Envelope<M> :=
|
|||||||
payload: M::LEN,
|
payload: M::LEN,
|
||||||
/// Message Authentication Code (mac) over all bytes until (exclusive)
|
/// Message Authentication Code (mac) over all bytes until (exclusive)
|
||||||
/// `mac` itself
|
/// `mac` itself
|
||||||
mac: sodium::MAC_SIZE,
|
mac: 16,
|
||||||
/// Currently unused, TODO: do something with this
|
/// Currently unused, TODO: do something with this
|
||||||
cookie: sodium::MAC_SIZE
|
cookie: 16
|
||||||
}
|
}
|
||||||
|
|
||||||
data_lense! { InitHello :=
|
data_lense! { InitHello :=
|
||||||
@@ -320,11 +320,11 @@ data_lense! { EmptyData :=
|
|||||||
|
|
||||||
data_lense! { Biscuit :=
|
data_lense! { Biscuit :=
|
||||||
/// H(spki) – Ident ifies the initiator
|
/// H(spki) – Ident ifies the initiator
|
||||||
pidi: sodium::KEY_SIZE,
|
pidi: KEY_LEN,
|
||||||
/// The biscuit number (replay protection)
|
/// The biscuit number (replay protection)
|
||||||
biscuit_no: 12,
|
biscuit_no: 12,
|
||||||
/// Chaining key
|
/// Chaining key
|
||||||
ck: sodium::KEY_SIZE
|
ck: KEY_LEN
|
||||||
}
|
}
|
||||||
|
|
||||||
data_lense! { DataMsg :=
|
data_lense! { DataMsg :=
|
||||||
@@ -389,20 +389,17 @@ pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_constants {
|
mod test_constants {
|
||||||
use crate::{
|
use crate::msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN};
|
||||||
msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN},
|
use rosenpass_ciphers::{xaead, KEY_LEN};
|
||||||
sodium,
|
|
||||||
};
|
|
||||||
use rosenpass_ciphers::xaead;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sodium_keysize() {
|
fn sodium_keysize() {
|
||||||
assert_eq!(sodium::KEY_SIZE, 32);
|
assert_eq!(KEY_LEN, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn biscuit_pt_len() {
|
fn biscuit_pt_len() {
|
||||||
assert_eq!(BISCUIT_PT_LEN, 2 * sodium::KEY_SIZE + 12);
|
assert_eq!(BISCUIT_PT_LEN, 2 * KEY_LEN + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
//! Implementation of the tree-like structure used for the label derivation in [labeled_prf](crate::labeled_prf)
|
//! Implementation of the tree-like structure used for the label derivation in [labeled_prf](crate::labeled_prf)
|
||||||
use {
|
use crate::coloring::Secret;
|
||||||
crate::{
|
|
||||||
coloring::Secret,
|
use anyhow::Result;
|
||||||
sodium::{hmac, hmac_into, KEY_SIZE},
|
use rosenpass_ciphers::{hash, KEY_LEN};
|
||||||
},
|
use rosenpass_to::To;
|
||||||
anyhow::Result,
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO Use a proper Dec interface
|
// TODO Use a proper Dec interface
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PrfTree([u8; KEY_SIZE]);
|
pub struct PrfTree([u8; KEY_LEN]);
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct PrfTreeBranch([u8; KEY_SIZE]);
|
pub struct PrfTreeBranch([u8; KEY_LEN]);
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SecretPrfTree(Secret<KEY_SIZE>);
|
pub struct SecretPrfTree(Secret<KEY_LEN>);
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SecretPrfTreeBranch(Secret<KEY_SIZE>);
|
pub struct SecretPrfTreeBranch(Secret<KEY_LEN>);
|
||||||
|
|
||||||
impl PrfTree {
|
impl PrfTree {
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self([0u8; KEY_SIZE])
|
Self([0u8; KEY_LEN])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dup(self) -> PrfTreeBranch {
|
pub fn dup(self) -> PrfTreeBranch {
|
||||||
@@ -32,21 +30,21 @@ impl PrfTree {
|
|||||||
|
|
||||||
// TODO: Protocol! Use domain separation to ensure that
|
// TODO: Protocol! Use domain separation to ensure that
|
||||||
pub fn mix(self, v: &[u8]) -> Result<Self> {
|
pub fn mix(self, v: &[u8]) -> Result<Self> {
|
||||||
Ok(Self(hmac(&self.0, v)?))
|
Ok(Self(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretPrfTree> {
|
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretPrfTree> {
|
||||||
SecretPrfTree::prf_invoc(&self.0, v.secret())
|
SecretPrfTree::prf_invoc(&self.0, v.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_value(self) -> [u8; KEY_SIZE] {
|
pub fn into_value(self) -> [u8; KEY_LEN] {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrfTreeBranch {
|
impl PrfTreeBranch {
|
||||||
pub fn mix(&self, v: &[u8]) -> Result<PrfTree> {
|
pub fn mix(&self, v: &[u8]) -> Result<PrfTree> {
|
||||||
Ok(PrfTree(hmac(&self.0, v)?))
|
Ok(PrfTree(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretPrfTree> {
|
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretPrfTree> {
|
||||||
@@ -57,7 +55,7 @@ impl PrfTreeBranch {
|
|||||||
impl SecretPrfTree {
|
impl SecretPrfTree {
|
||||||
pub fn prf_invoc(k: &[u8], d: &[u8]) -> Result<SecretPrfTree> {
|
pub fn prf_invoc(k: &[u8], d: &[u8]) -> Result<SecretPrfTree> {
|
||||||
let mut r = SecretPrfTree(Secret::zero());
|
let mut r = SecretPrfTree(Secret::zero());
|
||||||
hmac_into(r.0.secret_mut(), k, d)?;
|
hash::hash(k, d).to(r.0.secret_mut())?;
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +67,7 @@ impl SecretPrfTree {
|
|||||||
SecretPrfTreeBranch(self.0)
|
SecretPrfTreeBranch(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn danger_from_secret(k: Secret<KEY_SIZE>) -> Self {
|
pub fn danger_from_secret(k: Secret<KEY_LEN>) -> Self {
|
||||||
Self(k)
|
Self(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +79,12 @@ impl SecretPrfTree {
|
|||||||
Self::prf_invoc(self.0.secret(), v.secret())
|
Self::prf_invoc(self.0.secret(), v.secret())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_secret(self) -> Secret<KEY_SIZE> {
|
pub fn into_secret(self) -> Secret<KEY_LEN> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
|
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
|
||||||
hmac_into(self.0.secret_mut(), v, dst)
|
hash::hash(v, dst).to(self.0.secret_mut())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +100,7 @@ impl SecretPrfTreeBranch {
|
|||||||
// TODO: This entire API is not very nice; we need this for biscuits, but
|
// TODO: This entire API is not very nice; we need this for biscuits, but
|
||||||
// it might be better to extract a special "biscuit"
|
// it might be better to extract a special "biscuit"
|
||||||
// labeled subkey and reinitialize the chain with this
|
// labeled subkey and reinitialize the chain with this
|
||||||
pub fn danger_into_secret(self) -> Secret<KEY_SIZE> {
|
pub fn danger_into_secret(self) -> Secret<KEY_LEN> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,10 +73,9 @@ use crate::{
|
|||||||
msgs::*,
|
msgs::*,
|
||||||
pqkem::*,
|
pqkem::*,
|
||||||
prftree::{SecretPrfTree, SecretPrfTreeBranch},
|
prftree::{SecretPrfTree, SecretPrfTreeBranch},
|
||||||
sodium::*,
|
|
||||||
};
|
};
|
||||||
use anyhow::{bail, ensure, Context, Result};
|
use anyhow::{bail, ensure, Context, Result};
|
||||||
use rosenpass_ciphers::{aead, xaead};
|
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||||
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
|
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
|
||||||
use std::collections::hash_map::{
|
use std::collections::hash_map::{
|
||||||
Entry::{Occupied, Vacant},
|
Entry::{Occupied, Vacant},
|
||||||
@@ -145,10 +144,10 @@ pub type SSk = Secret<{ StaticKEM::SK_LEN }>;
|
|||||||
pub type EPk = Public<{ EphemeralKEM::PK_LEN }>;
|
pub type EPk = Public<{ EphemeralKEM::PK_LEN }>;
|
||||||
pub type ESk = Secret<{ EphemeralKEM::SK_LEN }>;
|
pub type ESk = Secret<{ EphemeralKEM::SK_LEN }>;
|
||||||
|
|
||||||
pub type SymKey = Secret<KEY_SIZE>;
|
pub type SymKey = Secret<KEY_LEN>;
|
||||||
pub type SymHash = Public<KEY_SIZE>;
|
pub type SymHash = Public<KEY_LEN>;
|
||||||
|
|
||||||
pub type PeerId = Public<KEY_SIZE>;
|
pub type PeerId = Public<KEY_LEN>;
|
||||||
pub type SessionId = Public<SESSION_ID_LEN>;
|
pub type SessionId = Public<SESSION_ID_LEN>;
|
||||||
pub type BiscuitId = Public<BISCUIT_ID_LEN>;
|
pub type BiscuitId = Public<BISCUIT_ID_LEN>;
|
||||||
|
|
||||||
@@ -1240,13 +1239,13 @@ impl HandshakeState {
|
|||||||
|
|
||||||
pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> {
|
pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> {
|
||||||
let k = self.ck.mix(&lprf::hs_enc()?)?.into_secret();
|
let k = self.ck.mix(&lprf::hs_enc()?)?.into_secret();
|
||||||
aead::encrypt(ct, k.secret(), &NONCE0, &NOTHING, pt)?;
|
aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?;
|
||||||
self.mix(ct)
|
self.mix(ct)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> {
|
pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> {
|
||||||
let k = self.ck.mix(&lprf::hs_enc()?)?.into_secret();
|
let k = self.ck.mix(&lprf::hs_enc()?)?.into_secret();
|
||||||
aead::decrypt(pt, k.secret(), &NONCE0, &NOTHING, ct)?;
|
aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?;
|
||||||
self.mix(ct)
|
self.mix(ct)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1448,7 +1447,7 @@ impl CryptoServer {
|
|||||||
.mix(peer.get(self).psk.secret())?;
|
.mix(peer.get(self).psk.secret())?;
|
||||||
|
|
||||||
// IHI8
|
// IHI8
|
||||||
hs.core.encrypt_and_mix(ih.auth_mut(), &NOTHING)?;
|
hs.core.encrypt_and_mix(ih.auth_mut(), &[])?;
|
||||||
|
|
||||||
// Update the handshake hash last (not changing any state on prior error
|
// Update the handshake hash last (not changing any state on prior error
|
||||||
peer.hs().insert(self, hs)?;
|
peer.hs().insert(self, hs)?;
|
||||||
@@ -1514,7 +1513,7 @@ impl CryptoServer {
|
|||||||
core.store_biscuit(self, peer, rh.biscuit_mut())?;
|
core.store_biscuit(self, peer, rh.biscuit_mut())?;
|
||||||
|
|
||||||
// RHR7
|
// RHR7
|
||||||
core.encrypt_and_mix(rh.auth_mut(), &NOTHING)?;
|
core.encrypt_and_mix(rh.auth_mut(), &[])?;
|
||||||
|
|
||||||
Ok(peer)
|
Ok(peer)
|
||||||
}
|
}
|
||||||
@@ -1600,7 +1599,7 @@ impl CryptoServer {
|
|||||||
ic.biscuit_mut().copy_from_slice(rh.biscuit());
|
ic.biscuit_mut().copy_from_slice(rh.biscuit());
|
||||||
|
|
||||||
// ICI4
|
// ICI4
|
||||||
core.encrypt_and_mix(ic.auth_mut(), &NOTHING)?;
|
core.encrypt_and_mix(ic.auth_mut(), &[])?;
|
||||||
|
|
||||||
// Split() – We move the secrets into the session; we do not
|
// Split() – We move the secrets into the session; we do not
|
||||||
// delete the InitiatorHandshake, just clear it's secrets because
|
// delete the InitiatorHandshake, just clear it's secrets because
|
||||||
@@ -1630,7 +1629,7 @@ impl CryptoServer {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// ICR2
|
// ICR2
|
||||||
core.encrypt_and_mix(&mut [0u8; aead::TAG_LEN], &NOTHING)?;
|
core.encrypt_and_mix(&mut [0u8; aead::TAG_LEN], &[])?;
|
||||||
|
|
||||||
// ICR3
|
// ICR3
|
||||||
core.mix(ic.sidi())?.mix(ic.sidr())?;
|
core.mix(ic.sidi())?.mix(ic.sidr())?;
|
||||||
@@ -1686,7 +1685,7 @@ impl CryptoServer {
|
|||||||
|
|
||||||
let n = cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]);
|
let n = cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]);
|
||||||
let k = ses.txkm.secret();
|
let k = ses.txkm.secret();
|
||||||
aead::encrypt(rc.auth_mut(), k, &n, &NOTHING, &NOTHING)?; // ct, k, n, ad, pt
|
aead::encrypt(rc.auth_mut(), k, &n, &[], &[])?; // ct, k, n, ad, pt
|
||||||
|
|
||||||
Ok(peer)
|
Ok(peer)
|
||||||
}
|
}
|
||||||
@@ -1723,7 +1722,7 @@ impl CryptoServer {
|
|||||||
&mut [0u8; 0],
|
&mut [0u8; 0],
|
||||||
s.txkt.secret(),
|
s.txkt.secret(),
|
||||||
&cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]),
|
&cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]),
|
||||||
&NOTHING,
|
&[],
|
||||||
rc.auth(),
|
rc.auth(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
//! Bindings and helpers for accessing libsodium functions
|
|
||||||
|
|
||||||
use anyhow::{ensure, Result};
|
|
||||||
use libsodium_sys as libsodium;
|
|
||||||
use rosenpass_constant_time::xor_into;
|
|
||||||
use rosenpass_util::attempt;
|
|
||||||
use static_assertions::const_assert_eq;
|
|
||||||
use std::os::raw::c_ulonglong;
|
|
||||||
use std::ptr::null as nullptr;
|
|
||||||
|
|
||||||
pub const NONCE0: [u8; libsodium::crypto_aead_chacha20poly1305_IETF_NPUBBYTES as usize] =
|
|
||||||
[0u8; libsodium::crypto_aead_chacha20poly1305_IETF_NPUBBYTES as usize];
|
|
||||||
pub const NOTHING: [u8; 0] = [0u8; 0];
|
|
||||||
pub const KEY_SIZE: usize = 32;
|
|
||||||
pub const MAC_SIZE: usize = 16;
|
|
||||||
|
|
||||||
const_assert_eq!(
|
|
||||||
KEY_SIZE,
|
|
||||||
libsodium::crypto_aead_chacha20poly1305_IETF_KEYBYTES as usize
|
|
||||||
);
|
|
||||||
const_assert_eq!(KEY_SIZE, libsodium::crypto_generichash_BYTES as usize);
|
|
||||||
|
|
||||||
macro_rules! sodium_call {
|
|
||||||
($name:ident, $($args:expr),*) => { attempt!({
|
|
||||||
ensure!(unsafe{libsodium::$name($($args),*)} > -1,
|
|
||||||
"Error in libsodium's {}.", stringify!($name));
|
|
||||||
Ok(())
|
|
||||||
})};
|
|
||||||
($name:ident) => { sodium_call!($name, ) };
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn blake2b_flexible(out: &mut [u8], key: &[u8], data: &[u8]) -> Result<()> {
|
|
||||||
const KEY_MIN: usize = libsodium::crypto_generichash_KEYBYTES_MIN as usize;
|
|
||||||
const KEY_MAX: usize = libsodium::crypto_generichash_KEYBYTES_MAX as usize;
|
|
||||||
const OUT_MIN: usize = libsodium::crypto_generichash_BYTES_MIN as usize;
|
|
||||||
const OUT_MAX: usize = libsodium::crypto_generichash_BYTES_MAX as usize;
|
|
||||||
assert!(key.is_empty() || (KEY_MIN <= key.len() && key.len() <= KEY_MAX));
|
|
||||||
assert!(OUT_MIN <= out.len() && out.len() <= OUT_MAX);
|
|
||||||
let kptr = match key.len() {
|
|
||||||
// NULL key
|
|
||||||
0 => nullptr(),
|
|
||||||
_ => key.as_ptr(),
|
|
||||||
};
|
|
||||||
sodium_call!(
|
|
||||||
crypto_generichash_blake2b,
|
|
||||||
out.as_mut_ptr(),
|
|
||||||
out.len(),
|
|
||||||
data.as_ptr(),
|
|
||||||
data.len() as c_ulonglong,
|
|
||||||
kptr,
|
|
||||||
key.len()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use proper streaming hash; for mix_hash too.
|
|
||||||
#[inline]
|
|
||||||
pub fn hash_into(out: &mut [u8], data: &[u8]) -> Result<()> {
|
|
||||||
assert!(out.len() == KEY_SIZE);
|
|
||||||
blake2b_flexible(out, &NOTHING, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn hash(data: &[u8]) -> Result<[u8; KEY_SIZE]> {
|
|
||||||
let mut r = [0u8; KEY_SIZE];
|
|
||||||
hash_into(&mut r, data)?;
|
|
||||||
Ok(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mac_into(out: &mut [u8], key: &[u8], data: &[u8]) -> Result<()> {
|
|
||||||
assert!(out.len() == KEY_SIZE);
|
|
||||||
assert!(key.len() == KEY_SIZE);
|
|
||||||
blake2b_flexible(out, key, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mac(key: &[u8], data: &[u8]) -> Result<[u8; KEY_SIZE]> {
|
|
||||||
let mut r = [0u8; KEY_SIZE];
|
|
||||||
mac_into(&mut r, key, data)?;
|
|
||||||
Ok(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn mac16(key: &[u8], data: &[u8]) -> Result<[u8; 16]> {
|
|
||||||
assert!(key.len() == KEY_SIZE);
|
|
||||||
let mut out = [0u8; 16];
|
|
||||||
blake2b_flexible(&mut out, key, data)?;
|
|
||||||
Ok(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn hmac_into(out: &mut [u8], key: &[u8], data: &[u8]) -> Result<()> {
|
|
||||||
// Not bothering with padding; the implementation
|
|
||||||
// uses appropriately sized keys.
|
|
||||||
ensure!(key.len() == KEY_SIZE);
|
|
||||||
|
|
||||||
const IPAD: [u8; KEY_SIZE] = [0x36u8; KEY_SIZE];
|
|
||||||
let mut temp_key = [0u8; KEY_SIZE];
|
|
||||||
temp_key.copy_from_slice(key);
|
|
||||||
xor_into(&mut temp_key, &IPAD);
|
|
||||||
let outer_data = mac(&temp_key, data)?;
|
|
||||||
|
|
||||||
const OPAD: [u8; KEY_SIZE] = [0x5Cu8; KEY_SIZE];
|
|
||||||
temp_key.copy_from_slice(key);
|
|
||||||
xor_into(&mut temp_key, &OPAD);
|
|
||||||
mac_into(out, &temp_key, &outer_data)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn hmac(key: &[u8], data: &[u8]) -> Result<[u8; KEY_SIZE]> {
|
|
||||||
let mut r = [0u8; KEY_SIZE];
|
|
||||||
hmac_into(&mut r, key, data)?;
|
|
||||||
Ok(r)
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,7 @@ readme = "readme.md"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rosenpass-util = { path = "../util" }
|
rosenpass-util = { path = "../util" }
|
||||||
|
rosenpass-to = { path = "../to" }
|
||||||
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
anyhow = { version = "1.0.71", features = ["backtrace"] }
|
||||||
libsodium-sys-stable = { version = "1.19.28", features = ["use-pkg-config"] }
|
libsodium-sys-stable = { version = "1.19.28", features = ["use-pkg-config"] }
|
||||||
log = { version = "0.4.17" }
|
log = { version = "0.4.17" }
|
||||||
|
|||||||
31
sodium/src/hash/blake2b.rs
Normal file
31
sodium/src/hash/blake2b.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use libsodium_sys as libsodium;
|
||||||
|
use rosenpass_to::{with_destination, To};
|
||||||
|
use std::ffi::c_ulonglong;
|
||||||
|
use std::ptr::null;
|
||||||
|
|
||||||
|
pub const KEY_MIN: usize = libsodium::crypto_generichash_blake2b_KEYBYTES_MIN as usize;
|
||||||
|
pub const KEY_MAX: usize = libsodium::crypto_generichash_blake2b_KEYBYTES_MAX as usize;
|
||||||
|
pub const OUT_MIN: usize = libsodium::crypto_generichash_blake2b_BYTES_MIN as usize;
|
||||||
|
pub const OUT_MAX: usize = libsodium::crypto_generichash_blake2b_BYTES_MAX as usize;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||||
|
with_destination(|out: &mut [u8]| {
|
||||||
|
assert!(key.is_empty() || (KEY_MIN <= key.len() && key.len() <= KEY_MAX));
|
||||||
|
assert!(OUT_MIN <= out.len() && out.len() <= OUT_MAX);
|
||||||
|
let kptr = match key.len() {
|
||||||
|
// NULL key
|
||||||
|
0 => null(),
|
||||||
|
_ => key.as_ptr(),
|
||||||
|
};
|
||||||
|
sodium_call!(
|
||||||
|
crypto_generichash_blake2b,
|
||||||
|
out.as_mut_ptr(),
|
||||||
|
out.len(),
|
||||||
|
data.as_ptr(),
|
||||||
|
data.len() as c_ulonglong,
|
||||||
|
kptr,
|
||||||
|
key.len()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
1
sodium/src/hash/mod.rs
Normal file
1
sodium/src/hash/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod blake2b;
|
||||||
@@ -16,4 +16,5 @@ pub fn init() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod aead;
|
pub mod aead;
|
||||||
|
pub mod hash;
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
|
|||||||
Reference in New Issue
Block a user