replace encryption layer and add masked byte
This commit is contained in:
@@ -7,13 +7,12 @@ license.workspace = true
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
blake3 = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
num_enum = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-crypto = { path = "../crypto", features = ["asymmetric", "hashing", "serde"] }
|
||||
nym-crypto = { path = "../crypto", features = ["hashing"] }
|
||||
nym-kkt-ciphersuite = { workspace = true, features = ["digests"] }
|
||||
|
||||
libcrux-kem = { workspace = true }
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_kkt::{
|
||||
ciphersuite::{Ciphersuite, EncapsulationKey, HashFunction, KEM, SignatureScheme},
|
||||
context::KKTMode,
|
||||
@@ -17,22 +16,11 @@ use nym_kkt::{
|
||||
hash_encapsulation_key,
|
||||
},
|
||||
session::{
|
||||
anonymous_initiator_process, initiator_ingest_response, initiator_process,
|
||||
responder_ingest_message, responder_process,
|
||||
initiator_ingest_response, initiator_process, responder_ingest_message, responder_process,
|
||||
},
|
||||
};
|
||||
use rand09::prelude::*;
|
||||
|
||||
pub fn gen_ed25519_keypair(c: &mut Criterion) {
|
||||
c.bench_function("Generate Ed25519 Keypair", |b| {
|
||||
b.iter(|| {
|
||||
let mut s: [u8; 32] = [0u8; 32];
|
||||
rand09::rng().fill_bytes(&mut s);
|
||||
ed25519::KeyPair::from_secret(s, 0)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn gen_mlkem768_keypair(c: &mut Criterion) {
|
||||
c.bench_function("Generate MlKem768 Keypair", |b| {
|
||||
b.iter(|| {
|
||||
@@ -107,12 +95,14 @@ pub fn kkt_benchmark(c: &mut Criterion) {
|
||||
c.bench_function(
|
||||
&format!("{kem}, {hash_function} | Anonymous Initiator: Generate Request",),
|
||||
|b| {
|
||||
b.iter(|| anonymous_initiator_process(&mut rng, ciphersuite).unwrap());
|
||||
b.iter(|| {
|
||||
initiator_process(&mut rng, KKTMode::OneWay, ciphersuite, None).unwrap()
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let (mut i_context, i_frame) =
|
||||
anonymous_initiator_process(&mut rng, ciphersuite).unwrap();
|
||||
initiator_process(&mut rng, KKTMode::OneWay, ciphersuite, None).unwrap();
|
||||
|
||||
c.bench_function(
|
||||
&format!(
|
||||
@@ -419,10 +409,5 @@ pub fn kkt_benchmark(c: &mut Criterion) {
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
gen_ed25519_keypair,
|
||||
gen_mlkem768_keypair,
|
||||
kkt_benchmark
|
||||
);
|
||||
criterion_group!(benches, gen_mlkem768_keypair, kkt_benchmark);
|
||||
criterion_main!(benches);
|
||||
|
||||
+246
-92
@@ -1,15 +1,76 @@
|
||||
use libcrux_chacha20poly1305::TAG_LEN;
|
||||
use libcrux_psq::handshake::types::DHPublicKey;
|
||||
use libcrux_psq::handshake::types::{DHKeyPair, DHPrivateKey, DHPublicKey};
|
||||
use nym_crypto::hkdf::blake3::{derive_key_blake3, derive_key_blake3_multi_input};
|
||||
use zeroize::Zeroize;
|
||||
use nym_kkt_ciphersuite::x25519::PUBLIC_KEY_LENGTH;
|
||||
use rand09::{CryptoRng, RngCore};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
use crate::{
|
||||
ciphersuite::EncapsulationKey, context::KKTRole, encryption::KKTSessionSecret, error::KKTError,
|
||||
frame::KKT_SESSION_ID_LEN,
|
||||
ciphersuite::EncapsulationKey,
|
||||
context::{KKTContext, KKTRole},
|
||||
error::KKTError,
|
||||
frame::{KKT_SESSION_ID_LEN, KKTFrame},
|
||||
masked_byte::{MASKED_BYTE_LEN, MaskedByte},
|
||||
};
|
||||
|
||||
const MAX_PAYLOAD_LEN: usize = 65535;
|
||||
#[derive(Zeroize, ZeroizeOnDrop)]
|
||||
pub struct KKTCarrier(Carrier);
|
||||
impl KKTCarrier {
|
||||
fn read_message(&mut self) {
|
||||
// if we are reading a message and we have not read or written a message before
|
||||
// this means that we are a responder who is
|
||||
// reading the initiator's first handshake message
|
||||
if self.0.rx_counter() == 1 && self.0.tx_counter() == 1 {
|
||||
// in this case, we parse out the eph public key, the nonce, and the version hash
|
||||
// we decode to see if the hash is
|
||||
}
|
||||
// if we are reading a message and we have written a message before
|
||||
// this means that we are an initiator
|
||||
// who is reading the responder's handshake message
|
||||
if self.0.rx_counter() == 1 && self.0.tx_counter() > 1 {}
|
||||
}
|
||||
fn write_message(&mut self) {}
|
||||
|
||||
// Generate carrier and encrypt first message
|
||||
|
||||
// the first message would look like this
|
||||
// (outer_header || eph_pk ||
|
||||
|
||||
// fn init<R>(
|
||||
// rng: &mut R,
|
||||
// responder_public_key: &DHPublicKey,
|
||||
// payload: &[u8],
|
||||
// header: Option<&[u8]>,
|
||||
// ) -> Result<(Self, Vec<u8>), KKTError>
|
||||
// where
|
||||
// R: RngCore + CryptoRng,
|
||||
// {
|
||||
// let ephemeral_keypair = DHKeyPair::new(rng);
|
||||
// let shared_secret = ephemeral_keypair
|
||||
// .sk()
|
||||
// .diffie_hellman(responder_public_key)
|
||||
// .map_err(|_| KKTError::X25519Error {
|
||||
// info: "Key Derivation Error",
|
||||
// })?;
|
||||
|
||||
// let carrier = Carrier::from_secret(&shared_secret.as_ref(), context);
|
||||
|
||||
// match header {
|
||||
// Some(header) => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
fn respond(responder_private_key: &DHPrivateKey, expects_header: bool) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
// This is arbitrary
|
||||
pub const MAX_PAYLOAD_LEN: usize = 1_000_000;
|
||||
const CARRIER_KDF_INFO_TX: &str = "CARRIER_V1_KDF_RX";
|
||||
const CARRIER_KDF_INFO_RX: &str = "CARRIER_V1_KDF_TX";
|
||||
const KKT_CARRIER_CONTEXT: &[u8] = b"CARRIER_V1_KKT_V1_KDF";
|
||||
|
||||
#[derive(Zeroize, ZeroizeOnDrop)]
|
||||
pub struct Carrier {
|
||||
tx_key: [u8; 32],
|
||||
rx_key: [u8; 32],
|
||||
@@ -17,6 +78,11 @@ pub struct Carrier {
|
||||
rx_counter: u64,
|
||||
}
|
||||
|
||||
pub enum CarrierRole {
|
||||
Initiator,
|
||||
Responder,
|
||||
}
|
||||
|
||||
fn increment_nonce(nonce: &mut u64) -> Result<(), KKTError> {
|
||||
match nonce.checked_add(1) {
|
||||
Some(incremented_nonce) => {
|
||||
@@ -37,51 +103,154 @@ fn as_nonce_bytes(nonce: u64) -> [u8; 12] {
|
||||
}
|
||||
|
||||
impl Carrier {
|
||||
pub fn from_session_secret(
|
||||
mut session_secret: KKTSessionSecret,
|
||||
role: KKTRole,
|
||||
kkt_session_id: &[u8; KKT_SESSION_ID_LEN],
|
||||
responder_public_key: &DHPublicKey,
|
||||
responder_encapsulation_key: &EncapsulationKey,
|
||||
) -> Result<Self, KKTError> {
|
||||
let mut salt = derive_key_blake3_multi_input(
|
||||
"nym-kkt-carrier-kdf-main",
|
||||
&[
|
||||
responder_encapsulation_key.encode().as_ref(),
|
||||
responder_public_key.as_ref(),
|
||||
],
|
||||
kkt_session_id,
|
||||
);
|
||||
|
||||
let k1 = derive_key_blake3(
|
||||
"nym-kkt-carrier-kdf-initiator",
|
||||
session_secret.as_bytes().as_ref(),
|
||||
&salt,
|
||||
);
|
||||
let k2 = derive_key_blake3(
|
||||
"nym-kkt-carrier-kdf-responder",
|
||||
session_secret.as_bytes().as_ref(),
|
||||
&salt,
|
||||
);
|
||||
|
||||
salt.zeroize();
|
||||
session_secret.zeroize();
|
||||
|
||||
Ok(match role {
|
||||
KKTRole::Initiator => Self {
|
||||
tx_key: k1,
|
||||
rx_key: k2,
|
||||
tx_counter: 1,
|
||||
rx_counter: 1,
|
||||
},
|
||||
KKTRole::Responder => Self {
|
||||
tx_key: k2,
|
||||
rx_key: k1,
|
||||
tx_counter: 1,
|
||||
rx_counter: 1,
|
||||
},
|
||||
})
|
||||
fn init(tx_key: [u8; 32], rx_key: [u8; 32]) -> Self {
|
||||
Self {
|
||||
tx_key: tx_key,
|
||||
rx_key: rx_key,
|
||||
tx_counter: 1,
|
||||
rx_counter: 1,
|
||||
}
|
||||
}
|
||||
pub fn new<R>(
|
||||
rng: &mut R,
|
||||
remote_public_key: &DHPublicKey,
|
||||
context: &[u8],
|
||||
) -> Result<(Self, DHPublicKey), KKTError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let ephemeral_keypair = DHKeyPair::new(rng);
|
||||
let shared_secret = ephemeral_keypair
|
||||
.sk()
|
||||
.diffie_hellman(remote_public_key)
|
||||
.map_err(|_| KKTError::X25519Error {
|
||||
info: "Key Derivation Error",
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
Self::from_secret_slice(shared_secret.as_ref(), context),
|
||||
ephemeral_keypair.pk,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn tx_counter(&self) -> u64 {
|
||||
self.tx_counter
|
||||
}
|
||||
|
||||
pub(crate) fn rx_counter(&self) -> u64 {
|
||||
self.rx_counter
|
||||
}
|
||||
|
||||
pub fn new_kkt_responder(
|
||||
responder_keypair: &DHKeyPair,
|
||||
message: &[u8],
|
||||
supported_versions: &[u8],
|
||||
) -> Result<(Carrier, KKTFrame, KKTContext), KKTError> {
|
||||
let mut initiator_public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [0; PUBLIC_KEY_LENGTH];
|
||||
initiator_public_key_bytes.clone_from_slice(&message[0..PUBLIC_KEY_LENGTH]);
|
||||
|
||||
// check mask
|
||||
|
||||
// todo: deal with this
|
||||
let masked_byte =
|
||||
MaskedByte::try_from(&message[PUBLIC_KEY_LENGTH..PUBLIC_KEY_LENGTH + MASKED_BYTE_LEN])
|
||||
.unwrap();
|
||||
|
||||
let mut mask = Vec::from(&initiator_public_key_bytes);
|
||||
mask.extend_from_slice(responder_keypair.pk.as_ref());
|
||||
|
||||
// todo: deal with this
|
||||
let byte = masked_byte.unmask(&mask).unwrap();
|
||||
|
||||
// todo: derive version from byte
|
||||
|
||||
if supported_versions.iter().find(|x| *x == &byte).is_some() {
|
||||
// now that the version is ok, we can try dh
|
||||
|
||||
let initiator_public_key = DHPublicKey::from_bytes(&initiator_public_key_bytes);
|
||||
|
||||
let shared_secret = responder_keypair
|
||||
.sk()
|
||||
.diffie_hellman(&initiator_public_key)
|
||||
.map_err(|_| KKTError::X25519Error {
|
||||
info: "Key Derivation Error",
|
||||
})?;
|
||||
|
||||
let mut context = Vec::from(masked_byte.as_slice());
|
||||
context.extend_from_slice(&KKT_CARRIER_CONTEXT);
|
||||
context.extend_from_slice(&initiator_public_key.as_ref());
|
||||
context.extend_from_slice(&responder_keypair.pk.as_ref());
|
||||
|
||||
let mut carrier = Self::from_secret_slice(shared_secret.as_ref(), &context).flip_keys();
|
||||
|
||||
let decrypted_message =
|
||||
carrier.decrypt(&message[PUBLIC_KEY_LENGTH + MASKED_BYTE_LEN..])?;
|
||||
let (frame, context) = KKTFrame::from_bytes(&decrypted_message)?;
|
||||
|
||||
Ok((carrier, frame, context))
|
||||
} else {
|
||||
panic!("unsupported protocol version");
|
||||
}
|
||||
}
|
||||
pub fn new_kkt_initiator<R>(
|
||||
rng: &mut R,
|
||||
responder_public_key: &DHPublicKey,
|
||||
version_byte: u8,
|
||||
kkt_frame: &KKTFrame,
|
||||
) -> Result<(Self, Vec<u8>), KKTError>
|
||||
where
|
||||
R: CryptoRng + RngCore,
|
||||
{
|
||||
let ephemeral_keypair = DHKeyPair::new(rng);
|
||||
let shared_secret = ephemeral_keypair
|
||||
.sk()
|
||||
.diffie_hellman(responder_public_key)
|
||||
.map_err(|_| KKTError::X25519Error {
|
||||
info: "Key Derivation Error",
|
||||
})?;
|
||||
|
||||
let mut mask = Vec::from(ephemeral_keypair.pk.as_ref());
|
||||
mask.extend_from_slice(responder_public_key.as_ref());
|
||||
|
||||
let masked_byte = MaskedByte::new(version_byte, &mask);
|
||||
|
||||
let mut context = Vec::from(masked_byte.as_slice());
|
||||
context.extend_from_slice(&KKT_CARRIER_CONTEXT);
|
||||
context.extend_from_slice(&ephemeral_keypair.pk.as_ref());
|
||||
context.extend_from_slice(&responder_public_key.as_ref());
|
||||
|
||||
let mut carrier = Self::from_secret_slice(shared_secret.as_ref(), &context);
|
||||
|
||||
let mut full_kkt_message = Vec::from(ephemeral_keypair.pk.as_ref());
|
||||
full_kkt_message.extend_from_slice(masked_byte.as_slice());
|
||||
let encrypted_kkt_frame = carrier.encrypt(&kkt_frame.to_bytes())?;
|
||||
full_kkt_message.extend_from_slice(&encrypted_kkt_frame);
|
||||
|
||||
Ok((carrier, full_kkt_message))
|
||||
}
|
||||
|
||||
pub fn from_secret_slice(secret: &[u8], context: &[u8]) -> Self {
|
||||
let tx_key = derive_key_blake3(CARRIER_KDF_INFO_TX, secret, &context);
|
||||
let rx_key = derive_key_blake3(CARRIER_KDF_INFO_RX, secret, &context);
|
||||
Self::init(tx_key, rx_key)
|
||||
}
|
||||
|
||||
pub fn from_secret(mut secret: [u8; 32], context: &[u8]) -> Self {
|
||||
let tx_key = derive_key_blake3(CARRIER_KDF_INFO_TX, secret.as_ref(), &context);
|
||||
let rx_key = derive_key_blake3(CARRIER_KDF_INFO_RX, secret.as_ref(), &context);
|
||||
secret.zeroize();
|
||||
Self::init(tx_key, rx_key)
|
||||
}
|
||||
|
||||
fn flip_keys(self) -> Self {
|
||||
Self {
|
||||
tx_key: self.rx_key,
|
||||
rx_key: self.tx_key,
|
||||
tx_counter: self.rx_counter,
|
||||
rx_counter: self.tx_counter,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encrypt(&mut self, plaintext: &[u8]) -> Result<Vec<u8>, KKTError> {
|
||||
if plaintext.len() > MAX_PAYLOAD_LEN {
|
||||
return Err(KKTError::AEADError {
|
||||
@@ -128,13 +297,14 @@ mod tests {
|
||||
KKT_RESPONSE_AAD,
|
||||
carrier::Carrier,
|
||||
ciphersuite::EncapsulationKey,
|
||||
encryption::*,
|
||||
context::{KKTMode, KKTRole},
|
||||
frame::KKTFrame,
|
||||
key_utils::{
|
||||
generate_keypair_libcrux, generate_keypair_mceliece, generate_keypair_mlkem,
|
||||
generate_keypair_x25519, hash_encapsulation_key,
|
||||
},
|
||||
session::{
|
||||
anonymous_initiator_process, initiator_ingest_response, responder_ingest_message,
|
||||
initiator_ingest_response, initiator_process, responder_ingest_message,
|
||||
responder_process,
|
||||
},
|
||||
};
|
||||
@@ -143,7 +313,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_e2e() {
|
||||
let mut rng = rand09::rng();
|
||||
// generate ed25519 keys
|
||||
|
||||
// generate responder x25519 keys
|
||||
let responder_x25519_keypair = generate_keypair_x25519(&mut rng);
|
||||
@@ -192,7 +361,7 @@ mod tests {
|
||||
|
||||
let r_kem_key_bytes = responder_kem_public_key.encode();
|
||||
|
||||
let _i_dir_hash = hash_encapsulation_key(
|
||||
let i_dir_hash = hash_encapsulation_key(
|
||||
&ciphersuite.hash_function(),
|
||||
ciphersuite.hash_len(),
|
||||
&i_kem_key_bytes,
|
||||
@@ -204,19 +373,24 @@ mod tests {
|
||||
&r_kem_key_bytes,
|
||||
);
|
||||
|
||||
// OneWay
|
||||
|
||||
let (mut i_context, i_frame) =
|
||||
anonymous_initiator_process(&mut rng, ciphersuite).unwrap();
|
||||
initiator_process(&mut rng, KKTMode::OneWay, ciphersuite, None).unwrap();
|
||||
|
||||
// encryption - initiator frame
|
||||
|
||||
let (i_session_secret, i_bytes) =
|
||||
encrypt_initial_kkt_frame(&mut rng, &responder_x25519_keypair.pk, &i_frame)
|
||||
.unwrap();
|
||||
let (mut i_carrier, i_bytes) = Carrier::new_kkt_initiator(
|
||||
&mut rng,
|
||||
&responder_x25519_keypair.pk,
|
||||
1u8,
|
||||
&i_frame,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// decryption - initiator frame
|
||||
|
||||
let (r_session_secret, i_frame_r, i_context_r) =
|
||||
decrypt_initial_kkt_frame(responder_x25519_keypair.sk(), &i_bytes).unwrap();
|
||||
let (mut r_carrier, i_frame_r, i_context_r) =
|
||||
Carrier::new_kkt_responder(&responder_x25519_keypair, &i_bytes, &[1]).unwrap();
|
||||
|
||||
let (mut r_context, _) =
|
||||
responder_ingest_message(&i_context_r, None, &i_frame_r).unwrap();
|
||||
@@ -229,14 +403,12 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// encryption - responder frame
|
||||
let r_bytes =
|
||||
encrypt_kkt_frame(&mut rng, &r_session_secret, &r_frame, KKT_RESPONSE_AAD)
|
||||
.unwrap();
|
||||
let r_bytes = r_carrier.encrypt(&r_frame.to_bytes()).unwrap();
|
||||
|
||||
// decryption - responder frame
|
||||
|
||||
let (i_frame_r, i_context_r) =
|
||||
decrypt_kkt_frame(&i_session_secret, &r_bytes, KKT_RESPONSE_AAD).unwrap();
|
||||
KKTFrame::from_bytes(&i_carrier.decrypt(&r_bytes).unwrap()).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
@@ -248,47 +420,29 @@ mod tests {
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes);
|
||||
|
||||
let mut initiator_carrier = Carrier::from_session_secret(
|
||||
i_session_secret,
|
||||
i_context.role(),
|
||||
&i_frame.session_id(),
|
||||
&responder_x25519_keypair.pk,
|
||||
&i_obtained_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut responder_carrier = Carrier::from_session_secret(
|
||||
r_session_secret,
|
||||
r_context.role(),
|
||||
&r_frame.session_id(),
|
||||
&responder_x25519_keypair.pk,
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let test1 = b"test1: i>r #1";
|
||||
let ct1 = initiator_carrier.encrypt(test1).unwrap();
|
||||
let pt1 = responder_carrier.decrypt(&ct1).unwrap();
|
||||
let ct1 = i_carrier.encrypt(test1).unwrap();
|
||||
let pt1 = r_carrier.decrypt(&ct1).unwrap();
|
||||
assert_eq!(pt1, test1);
|
||||
|
||||
let test2 = b"test2: r>i #1";
|
||||
let ct2 = initiator_carrier.encrypt(test2).unwrap();
|
||||
let pt2 = responder_carrier.decrypt(&ct2).unwrap();
|
||||
let ct2 = i_carrier.encrypt(test2).unwrap();
|
||||
let pt2 = r_carrier.decrypt(&ct2).unwrap();
|
||||
assert_eq!(pt2, test2);
|
||||
let test3 = b"test3: i>r #2";
|
||||
|
||||
let ct3 = initiator_carrier.encrypt(test3).unwrap();
|
||||
let pt3 = responder_carrier.decrypt(&ct3).unwrap();
|
||||
let ct3 = i_carrier.encrypt(test3).unwrap();
|
||||
let pt3 = r_carrier.decrypt(&ct3).unwrap();
|
||||
assert_eq!(pt3, test3);
|
||||
|
||||
let test4 = b"test4: i>r #3";
|
||||
let ct4 = initiator_carrier.encrypt(test4).unwrap();
|
||||
let pt4 = responder_carrier.decrypt(&ct4).unwrap();
|
||||
let ct4 = i_carrier.encrypt(test4).unwrap();
|
||||
let pt4 = r_carrier.decrypt(&ct4).unwrap();
|
||||
assert_eq!(pt4, test4);
|
||||
|
||||
let test5 = b"test5: r>i #2";
|
||||
let ct5 = initiator_carrier.encrypt(test5).unwrap();
|
||||
let pt5 = responder_carrier.decrypt(&ct5).unwrap();
|
||||
let ct5 = i_carrier.encrypt(test5).unwrap();
|
||||
let pt5 = r_carrier.decrypt(&ct5).unwrap();
|
||||
assert_eq!(pt5, test5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,18 @@ pub enum KKTError {
|
||||
LibcruxError,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MaskedByteError {
|
||||
#[error(
|
||||
"Invalid Masked Byte Length: Expected({}), Actual({}).",
|
||||
expected,
|
||||
actual
|
||||
)]
|
||||
InvalidLength { expected: usize, actual: usize },
|
||||
#[error("Failed to Unmask Byte.")]
|
||||
Failure,
|
||||
}
|
||||
|
||||
impl From<libcrux_kem::Error> for KKTError {
|
||||
fn from(err: libcrux_kem::Error) -> Self {
|
||||
match err {
|
||||
|
||||
+159
-239
@@ -3,12 +3,13 @@
|
||||
|
||||
pub mod ciphersuite;
|
||||
pub mod context;
|
||||
pub mod encryption;
|
||||
// pub mod encryption;
|
||||
pub mod error;
|
||||
pub mod frame;
|
||||
pub mod key_utils;
|
||||
// pub mod kkt;
|
||||
pub mod carrier;
|
||||
pub mod masked_byte;
|
||||
pub mod rekey;
|
||||
pub mod session;
|
||||
|
||||
@@ -22,202 +23,170 @@ pub(crate) const KKT_INITIAL_FRAME_AAD: &[u8] = b"KKT_INITIAL_FRAME";
|
||||
mod test {
|
||||
use crate::{
|
||||
KKT_RESPONSE_AAD,
|
||||
carrier::Carrier,
|
||||
ciphersuite::{Ciphersuite, EncapsulationKey, HashFunction, KEM},
|
||||
encryption::{
|
||||
decrypt_initial_kkt_frame, decrypt_kkt_frame, encrypt_initial_kkt_frame,
|
||||
encrypt_kkt_frame,
|
||||
},
|
||||
context::KKTMode,
|
||||
frame::KKTFrame,
|
||||
key_utils::{
|
||||
generate_keypair_libcrux, generate_keypair_mceliece, generate_keypair_mlkem,
|
||||
generate_keypair_x25519, hash_encapsulation_key,
|
||||
},
|
||||
session::{
|
||||
anonymous_initiator_process, initiator_ingest_response, initiator_process,
|
||||
responder_ingest_message, responder_process,
|
||||
initiator_ingest_response, initiator_process, responder_ingest_message,
|
||||
responder_process,
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_kkt_psq_e2e_clear() {
|
||||
fn test_kkt_psq_e2e() {
|
||||
let mut rng = rand09::rng();
|
||||
|
||||
for kem in [KEM::MlKem768, KEM::XWing, KEM::X25519, KEM::McEliece] {
|
||||
for hash_function in [
|
||||
HashFunction::Blake3,
|
||||
HashFunction::SHA256,
|
||||
HashFunction::Shake128,
|
||||
HashFunction::Shake256,
|
||||
] {
|
||||
let ciphersuite = Ciphersuite::resolve_ciphersuite(
|
||||
kem,
|
||||
hash_function,
|
||||
crate::ciphersuite::SignatureScheme::Ed25519,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// generate kem public keys
|
||||
|
||||
let (responder_kem_public_key, initiator_kem_public_key) = match kem {
|
||||
KEM::MlKem768 => (
|
||||
EncapsulationKey::MlKem768(generate_keypair_mlkem(&mut rng).1),
|
||||
EncapsulationKey::MlKem768(generate_keypair_mlkem(&mut rng).1),
|
||||
),
|
||||
KEM::XWing => (
|
||||
EncapsulationKey::XWing(generate_keypair_libcrux(&mut rng, kem).unwrap().1),
|
||||
EncapsulationKey::XWing(generate_keypair_libcrux(&mut rng, kem).unwrap().1),
|
||||
),
|
||||
KEM::X25519 => (
|
||||
EncapsulationKey::X25519(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
EncapsulationKey::X25519(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
),
|
||||
KEM::McEliece => (
|
||||
EncapsulationKey::McEliece(generate_keypair_mceliece(&mut rng).1),
|
||||
EncapsulationKey::McEliece(generate_keypair_mceliece(&mut rng).1),
|
||||
),
|
||||
};
|
||||
|
||||
let i_kem_key_bytes = initiator_kem_public_key.encode();
|
||||
|
||||
let r_kem_key_bytes = responder_kem_public_key.encode();
|
||||
|
||||
let i_dir_hash = hash_encapsulation_key(
|
||||
&ciphersuite.hash_function(),
|
||||
ciphersuite.hash_len(),
|
||||
&i_kem_key_bytes,
|
||||
);
|
||||
|
||||
let r_dir_hash = hash_encapsulation_key(
|
||||
&ciphersuite.hash_function(),
|
||||
ciphersuite.hash_len(),
|
||||
&r_kem_key_bytes,
|
||||
);
|
||||
|
||||
// Anonymous Initiator, OneWay
|
||||
{
|
||||
let (mut i_context, i_frame) =
|
||||
anonymous_initiator_process(&mut rng, ciphersuite).unwrap();
|
||||
|
||||
let i_frame_bytes = i_frame.to_bytes();
|
||||
|
||||
let (i_frame_r, r_context) = KKTFrame::from_bytes(&i_frame_bytes).unwrap();
|
||||
|
||||
let (mut r_context, _) =
|
||||
responder_ingest_message(&r_context, None, &i_frame_r).unwrap();
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let r_bytes = r_frame.to_bytes();
|
||||
|
||||
let (i_frame_r, i_context_r) = KKTFrame::from_bytes(&r_bytes).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
// Initiator, OneWay
|
||||
{
|
||||
let (mut i_context, i_frame) = initiator_process(
|
||||
&mut rng,
|
||||
crate::context::KKTMode::OneWay,
|
||||
ciphersuite,
|
||||
for encryption in [false, true] {
|
||||
for kem in [KEM::MlKem768, KEM::XWing, KEM::X25519, KEM::McEliece] {
|
||||
for hash_function in [
|
||||
HashFunction::Blake3,
|
||||
HashFunction::SHA256,
|
||||
HashFunction::Shake128,
|
||||
HashFunction::Shake256,
|
||||
] {
|
||||
let ciphersuite = Ciphersuite::resolve_ciphersuite(
|
||||
kem,
|
||||
hash_function,
|
||||
crate::ciphersuite::SignatureScheme::Ed25519,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let i_frame_bytes = i_frame.to_bytes();
|
||||
// generate kem public keys
|
||||
|
||||
let (i_frame_r, r_context) = KKTFrame::from_bytes(&i_frame_bytes).unwrap();
|
||||
let (responder_kem_public_key, initiator_kem_public_key) = match kem {
|
||||
KEM::MlKem768 => (
|
||||
EncapsulationKey::MlKem768(generate_keypair_mlkem(&mut rng).1),
|
||||
EncapsulationKey::MlKem768(generate_keypair_mlkem(&mut rng).1),
|
||||
),
|
||||
KEM::XWing => (
|
||||
EncapsulationKey::XWing(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
EncapsulationKey::XWing(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
),
|
||||
KEM::X25519 => (
|
||||
EncapsulationKey::X25519(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
EncapsulationKey::X25519(
|
||||
generate_keypair_libcrux(&mut rng, kem).unwrap().1,
|
||||
),
|
||||
),
|
||||
KEM::McEliece => (
|
||||
EncapsulationKey::McEliece(generate_keypair_mceliece(&mut rng).1),
|
||||
EncapsulationKey::McEliece(generate_keypair_mceliece(&mut rng).1),
|
||||
),
|
||||
};
|
||||
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&r_context, None, &i_frame_r).unwrap();
|
||||
let i_kem_key_bytes = initiator_kem_public_key.encode();
|
||||
|
||||
assert!(r_obtained_key.is_none());
|
||||
let r_kem_key_bytes = responder_kem_public_key.encode();
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
let i_dir_hash = hash_encapsulation_key(
|
||||
&ciphersuite.hash_function(),
|
||||
ciphersuite.hash_len(),
|
||||
&i_kem_key_bytes,
|
||||
);
|
||||
|
||||
let r_bytes = r_frame.to_bytes();
|
||||
let r_dir_hash = hash_encapsulation_key(
|
||||
&ciphersuite.hash_function(),
|
||||
ciphersuite.hash_len(),
|
||||
&r_kem_key_bytes,
|
||||
);
|
||||
|
||||
let (i_frame_r, i_context_r) = KKTFrame::from_bytes(&r_bytes).unwrap();
|
||||
// OneWay
|
||||
{
|
||||
let (mut i_context, i_frame) =
|
||||
initiator_process(&mut rng, KKTMode::OneWay, ciphersuite, None)
|
||||
.unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
let i_frame_bytes = i_frame.to_bytes();
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
let (i_frame_r, r_context) = KKTFrame::from_bytes(&i_frame_bytes).unwrap();
|
||||
|
||||
// Initiator, Mutual
|
||||
{
|
||||
let (mut i_context, i_frame) = initiator_process(
|
||||
&mut rng,
|
||||
crate::context::KKTMode::Mutual,
|
||||
ciphersuite,
|
||||
Some(&initiator_kem_public_key),
|
||||
)
|
||||
.unwrap();
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&r_context, None, &i_frame_r).unwrap();
|
||||
|
||||
let i_frame_bytes = i_frame.to_bytes();
|
||||
assert!(r_obtained_key.is_none());
|
||||
|
||||
let (i_frame_r, r_context) = KKTFrame::from_bytes(&i_frame_bytes).unwrap();
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&r_context, Some(&i_dir_hash), &i_frame_r)
|
||||
.unwrap();
|
||||
let r_bytes = r_frame.to_bytes();
|
||||
|
||||
assert_eq!(r_obtained_key.unwrap().encode(), i_kem_key_bytes);
|
||||
let (i_frame_r, i_context_r) = KKTFrame::from_bytes(&r_bytes).unwrap();
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let r_bytes = r_frame.to_bytes();
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
|
||||
let (i_frame_r, i_context_r) = KKTFrame::from_bytes(&r_bytes).unwrap();
|
||||
// Mutual
|
||||
{
|
||||
let (mut i_context, i_frame) = initiator_process(
|
||||
&mut rng,
|
||||
KKTMode::Mutual,
|
||||
ciphersuite,
|
||||
Some(&initiator_kem_public_key),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
let i_frame_bytes = i_frame.to_bytes();
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
let (i_frame_r, r_context) = KKTFrame::from_bytes(&i_frame_bytes).unwrap();
|
||||
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&r_context, Some(&i_dir_hash), &i_frame_r)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(r_obtained_key.unwrap().encode(), i_kem_key_bytes);
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let r_bytes = r_frame.to_bytes();
|
||||
|
||||
let (i_frame_r, i_context_r) = KKTFrame::from_bytes(&r_bytes).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_kkt_psq_e2e_encrypted() {
|
||||
fn test_kkt_psq_e2e_encrypted_carrier() {
|
||||
let mut rng = rand09::rng();
|
||||
|
||||
// generate responder x25519 keys
|
||||
@@ -279,21 +248,25 @@ mod test {
|
||||
&r_kem_key_bytes,
|
||||
);
|
||||
|
||||
// Anonymous Initiator, OneWay
|
||||
// OneWay
|
||||
{
|
||||
let (mut i_context, i_frame) =
|
||||
anonymous_initiator_process(&mut rng, ciphersuite).unwrap();
|
||||
initiator_process(&mut rng, KKTMode::OneWay, ciphersuite, None).unwrap();
|
||||
|
||||
// encryption - initiator frame
|
||||
|
||||
let (i_session_secret, i_bytes) =
|
||||
encrypt_initial_kkt_frame(&mut rng, &responder_x25519_keypair.pk, &i_frame)
|
||||
.unwrap();
|
||||
let (mut i_carrier, i_bytes) = Carrier::new_kkt_initiator(
|
||||
&mut rng,
|
||||
&responder_x25519_keypair.pk,
|
||||
1u8,
|
||||
&i_frame,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// decryption - initiator frame
|
||||
|
||||
let (r_session_secret, i_frame_r, i_context_r) =
|
||||
decrypt_initial_kkt_frame(responder_x25519_keypair.sk(), &i_bytes).unwrap();
|
||||
let (mut r_carrier, i_frame_r, i_context_r) =
|
||||
Carrier::new_kkt_responder(&responder_x25519_keypair, &i_bytes, &[1])
|
||||
.unwrap();
|
||||
|
||||
let (mut r_context, _) =
|
||||
responder_ingest_message(&i_context_r, None, &i_frame_r).unwrap();
|
||||
@@ -306,14 +279,12 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
// encryption - responder frame
|
||||
let r_bytes =
|
||||
encrypt_kkt_frame(&mut rng, &r_session_secret, &r_frame, KKT_RESPONSE_AAD)
|
||||
.unwrap();
|
||||
let r_bytes = r_carrier.encrypt(&r_frame.to_bytes()).unwrap();
|
||||
|
||||
// decryption - responder frame
|
||||
|
||||
let (i_frame_r, i_context_r) =
|
||||
decrypt_kkt_frame(&i_session_secret, &r_bytes, KKT_RESPONSE_AAD).unwrap();
|
||||
KKTFrame::from_bytes(&i_carrier.decrypt(&r_bytes).unwrap()).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
@@ -325,86 +296,37 @@ mod test {
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
// Initiator, OneWay
|
||||
// Mutual
|
||||
{
|
||||
let (mut i_context, i_frame) = initiator_process(
|
||||
&mut rng,
|
||||
crate::context::KKTMode::OneWay,
|
||||
ciphersuite,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// encryption - initiator frame
|
||||
|
||||
let (i_session_secret, i_bytes) =
|
||||
encrypt_initial_kkt_frame(&mut rng, &responder_x25519_keypair.pk, &i_frame)
|
||||
.unwrap();
|
||||
|
||||
// decryption - initiator frame
|
||||
|
||||
let (r_session_secret, i_frame_r, r_context) =
|
||||
decrypt_initial_kkt_frame(responder_x25519_keypair.sk(), &i_bytes).unwrap();
|
||||
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&r_context, None, &i_frame_r).unwrap();
|
||||
|
||||
assert!(r_obtained_key.is_none());
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
i_frame_r.session_id(),
|
||||
&responder_kem_public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// encryption - responder frame
|
||||
let r_bytes =
|
||||
encrypt_kkt_frame(&mut rng, &r_session_secret, &r_frame, KKT_RESPONSE_AAD)
|
||||
.unwrap();
|
||||
|
||||
// decryption - responder frame
|
||||
|
||||
let (i_frame_r, i_context_r) =
|
||||
decrypt_kkt_frame(&i_session_secret, &r_bytes, KKT_RESPONSE_AAD).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
&i_frame_r,
|
||||
&i_context_r,
|
||||
&r_dir_hash,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(i_obtained_key.encode(), r_kem_key_bytes)
|
||||
}
|
||||
|
||||
// Initiator, Mutual
|
||||
{
|
||||
let (mut i_context, i_frame) = initiator_process(
|
||||
&mut rng,
|
||||
crate::context::KKTMode::Mutual,
|
||||
KKTMode::Mutual,
|
||||
ciphersuite,
|
||||
Some(&initiator_kem_public_key),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// encryption - initiator frame
|
||||
|
||||
let (i_session_secret, i_bytes) =
|
||||
encrypt_initial_kkt_frame(&mut rng, &responder_x25519_keypair.pk, &i_frame)
|
||||
.unwrap();
|
||||
let (mut i_carrier, i_bytes) = Carrier::new_kkt_initiator(
|
||||
&mut rng,
|
||||
&responder_x25519_keypair.pk,
|
||||
1u8,
|
||||
&i_frame,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// decryption - initiator frame
|
||||
|
||||
let (r_session_secret, i_frame_r, i_context_r) =
|
||||
decrypt_initial_kkt_frame(responder_x25519_keypair.sk(), &i_bytes).unwrap();
|
||||
|
||||
let (mut r_context, r_obtained_key) =
|
||||
responder_ingest_message(&i_context_r, Some(&i_dir_hash), &i_frame_r)
|
||||
let (mut r_carrier, i_frame_r, i_context_r) =
|
||||
Carrier::new_kkt_responder(&responder_x25519_keypair, &i_bytes, &[1])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(r_obtained_key.unwrap().encode(), i_kem_key_bytes);
|
||||
let (mut r_context, _) = responder_ingest_message(
|
||||
&i_context_r,
|
||||
Some(i_dir_hash.as_slice()),
|
||||
&i_frame_r,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let r_frame = responder_process(
|
||||
&mut r_context,
|
||||
@@ -414,14 +336,12 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
// encryption - responder frame
|
||||
let r_bytes =
|
||||
encrypt_kkt_frame(&mut rng, &r_session_secret, &r_frame, KKT_RESPONSE_AAD)
|
||||
.unwrap();
|
||||
let r_bytes = r_carrier.encrypt(&r_frame.to_bytes()).unwrap();
|
||||
|
||||
// decryption - responder frame
|
||||
|
||||
let (i_frame_r, i_context_r) =
|
||||
decrypt_kkt_frame(&i_session_secret, &r_bytes, KKT_RESPONSE_AAD).unwrap();
|
||||
KKTFrame::from_bytes(&i_carrier.decrypt(&r_bytes).unwrap()).unwrap();
|
||||
|
||||
let i_obtained_key = initiator_ingest_response(
|
||||
&mut i_context,
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
use nym_crypto::{blake3, hmac::hmac::digest::ExtendableOutput};
|
||||
|
||||
use crate::error::{
|
||||
MaskedByteError,
|
||||
MaskedByteError::{Failure, InvalidLength},
|
||||
};
|
||||
|
||||
pub const MASKED_BYTE_LEN: usize = 16;
|
||||
pub const MASKED_BYTE_CONTEXT_STR: &[u8] = b"NYM_MASKED_BYTE_V1";
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MaskedByte([u8; MASKED_BYTE_LEN]);
|
||||
|
||||
impl MaskedByte {
|
||||
/// Mask a byte by hashing it with some mask.
|
||||
/// Outputs Blake3_Hash(MASKED_BYTE_CONTEXT_STR || mask || 0xFF || byte)
|
||||
pub fn new(byte: u8, mask: &[u8]) -> Self {
|
||||
let mut output: [u8; MASKED_BYTE_LEN] = [0u8; MASKED_BYTE_LEN];
|
||||
let mut hasher = blake3::Hasher::new();
|
||||
hasher.update(MASKED_BYTE_CONTEXT_STR);
|
||||
hasher.update(mask);
|
||||
// avoid zero update
|
||||
hasher.update(&[0xFF, byte]);
|
||||
hasher.finalize_xof_into(&mut output);
|
||||
|
||||
Self(output)
|
||||
}
|
||||
/// Unmasks a byte by trial hashing.
|
||||
/// This function runs Blake3_Hash(MASKED_BYTE_CONTEXT_STR || mask || 0xFF).
|
||||
/// This Hasher state is then cloned updated with `i: u8` in (0..=u8::max).
|
||||
/// If we find an `i` which yields back the hash input, then we found the masked byte.
|
||||
/// Otherwise, the function returns an error.
|
||||
pub fn unmask(&self, mask: &[u8]) -> Result<u8, MaskedByteError> {
|
||||
let mut buf: [u8; MASKED_BYTE_LEN] = [0u8; MASKED_BYTE_LEN];
|
||||
let mut hasher = blake3::Hasher::new();
|
||||
hasher.update(MASKED_BYTE_CONTEXT_STR);
|
||||
hasher.update(mask);
|
||||
// avoid zero update
|
||||
hasher.update(&[0xFF]);
|
||||
for i in 0..=u8::MAX {
|
||||
let mut t_hasher = hasher.clone();
|
||||
t_hasher.update(&[i]);
|
||||
t_hasher.finalize_xof_into(&mut buf);
|
||||
if buf == self.0 {
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
return Err(Failure);
|
||||
}
|
||||
|
||||
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> [u8; 16] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; MASKED_BYTE_LEN]> for MaskedByte {
|
||||
fn from(value: [u8; MASKED_BYTE_LEN]) -> Self {
|
||||
MaskedByte(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8; MASKED_BYTE_LEN]> for MaskedByte {
|
||||
fn from(value: &[u8; MASKED_BYTE_LEN]) -> Self {
|
||||
MaskedByte(value.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for MaskedByte {
|
||||
type Error = MaskedByteError;
|
||||
|
||||
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||
if value.len() != MASKED_BYTE_LEN {
|
||||
Err(InvalidLength {
|
||||
expected: MASKED_BYTE_LEN,
|
||||
actual: value.len(),
|
||||
})
|
||||
} else {
|
||||
Ok(Self::from(value.as_chunks::<MASKED_BYTE_LEN>().0[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::masked_byte::MASKED_BYTE_LEN;
|
||||
|
||||
use super::MaskedByte;
|
||||
use rand09::{Rng, RngCore, rng};
|
||||
|
||||
#[test]
|
||||
fn test_masking() {
|
||||
let mut mask: [u8; 256] = [0u8; 256];
|
||||
let mut wire_bytes: [u8; MASKED_BYTE_LEN];
|
||||
|
||||
// why not
|
||||
for i in 0..=u8::MAX {
|
||||
// gen mask
|
||||
rng().fill_bytes(&mut mask);
|
||||
let masked_byte = MaskedByte::new(i, &mask);
|
||||
wire_bytes = masked_byte.to_bytes();
|
||||
|
||||
let decoded_masked_byte = MaskedByte::from(wire_bytes);
|
||||
let output = decoded_masked_byte.unmask(&mask).unwrap();
|
||||
|
||||
assert_eq!(i, output);
|
||||
|
||||
// flip bit
|
||||
let mut with_flipped_bit = decoded_masked_byte.to_bytes();
|
||||
|
||||
let byte_idx: usize = rng().random_range(0..MASKED_BYTE_LEN);
|
||||
let bit_idx = rng().random_range(0..8);
|
||||
with_flipped_bit[byte_idx] ^= 1 << bit_idx;
|
||||
|
||||
let decoded_masked_byte = MaskedByte::from(with_flipped_bit);
|
||||
assert!(decoded_masked_byte.unmask(&mask).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decoding() {
|
||||
let mut mask: [u8; 256] = [0u8; 256];
|
||||
|
||||
// gen mask
|
||||
rng().fill_bytes(&mut mask);
|
||||
let byte = rng().random();
|
||||
let masked_byte = MaskedByte::new(byte, &mask);
|
||||
let wire_bytes: [u8; MASKED_BYTE_LEN] = masked_byte.to_bytes();
|
||||
|
||||
// should succeed
|
||||
let decoded_masked_byte = MaskedByte::try_from(wire_bytes.as_slice()).unwrap();
|
||||
let output = decoded_masked_byte.unmask(&mask).unwrap();
|
||||
|
||||
assert_eq!(byte, output);
|
||||
|
||||
let empty_slice: &[u8] = &[];
|
||||
// should fail
|
||||
assert!(MaskedByte::try_from(empty_slice).is_err());
|
||||
|
||||
let mut wire_bytes_messy = Vec::from(wire_bytes);
|
||||
|
||||
// add more one more byte
|
||||
wire_bytes_messy.push(0x42);
|
||||
assert!(wire_bytes_messy.len() == MASKED_BYTE_LEN + 1);
|
||||
// should fail
|
||||
assert!(MaskedByte::try_from(wire_bytes_messy.as_slice()).is_err());
|
||||
|
||||
// pop the added byte
|
||||
_ = wire_bytes_messy.pop();
|
||||
assert!(wire_bytes_messy.len() == MASKED_BYTE_LEN);
|
||||
// should succeed
|
||||
assert!(MaskedByte::try_from(wire_bytes_messy.as_slice()).is_ok());
|
||||
|
||||
// pop one more byte
|
||||
_ = wire_bytes_messy.pop();
|
||||
assert!(wire_bytes_messy.len() == MASKED_BYTE_LEN - 1);
|
||||
// should fail
|
||||
assert!(MaskedByte::try_from(wire_bytes_messy.as_slice()).is_err());
|
||||
}
|
||||
}
|
||||
@@ -43,22 +43,6 @@ where
|
||||
Ok((context, KKTFrame::new(context_bytes, body, session_id)))
|
||||
}
|
||||
|
||||
pub fn anonymous_initiator_process<R>(
|
||||
rng: &mut R,
|
||||
ciphersuite: Ciphersuite,
|
||||
) -> Result<(KKTContext, KKTFrame), KKTError>
|
||||
where
|
||||
R: CryptoRng + RngCore,
|
||||
{
|
||||
let context = KKTContext::new(KKTRole::Initiator, KKTMode::OneWay, ciphersuite);
|
||||
let context_bytes = context.encode()?;
|
||||
|
||||
let mut session_id = [0u8; KKT_SESSION_ID_LEN];
|
||||
rng.fill_bytes(&mut session_id);
|
||||
|
||||
Ok((context, KKTFrame::new(context_bytes, &[], session_id)))
|
||||
}
|
||||
|
||||
pub fn initiator_ingest_response(
|
||||
own_context: &mut KKTContext,
|
||||
remote_frame: &KKTFrame,
|
||||
|
||||
Reference in New Issue
Block a user