Build fixes, ephemeral keying logic and ratchet logic, split out symmetric key since it is a non-trivial type.

This commit is contained in:
Adam Ierymenko 2021-11-12 18:04:34 -05:00
parent 184c4aede1
commit 06bd77946b
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
11 changed files with 267 additions and 41 deletions

View file

@ -25,10 +25,10 @@ impl SHA512 {
pub fn hmac(key: &[u8], msg: &[u8]) -> [u8; SHA512_HASH_SIZE] {
let mut m = gcrypt::mac::Mac::new(gcrypt::mac::Algorithm::HmacSha512).unwrap();
let _ = m.set_key(key);
let _ = m.update(msg);
m.set_key(key).expect("FATAL: invalid HMAC-SHA512 key");;
m.update(msg).expect("FATAL: HMAC-SHA512 failed");
let mut h = [0_u8; SHA512_HASH_SIZE];
let _ = m.get_mac(&mut h);
m.get_mac(&mut h).expect("FATAL: HMAC-SHA512 failed");
h
}
@ -77,10 +77,10 @@ impl SHA384 {
pub fn hmac(key: &[u8], msg: &[u8]) -> [u8; SHA384_HASH_SIZE] {
let mut m = gcrypt::mac::Mac::new(gcrypt::mac::Algorithm::HmacSha384).unwrap();
let _ = m.set_key(key);
let _ = m.update(msg);
m.set_key(key).expect("FATAL: invalid HMAC-SHA384 key");
m.update(msg).expect("FATAL: HMAC-SHA384 failed");
let mut h = [0_u8; SHA384_HASH_SIZE];
let _ = m.get_mac(&mut h);
m.get_mac(&mut h).expect("FATAL: HMAC-SHA384 failed");
h
}

View file

@ -25,11 +25,11 @@ use rand_core::{RngCore, CryptoRng};
use quickcheck::{Arbitrary, Gen, QuickCheck};
/// The secret key size, in bytes.
pub const SECRET_KEY_SIZE: usize = 48;
pub const SIDH_P751_SECRET_KEY_SIZE: usize = 48;
/// The public key size, in bytes.
pub const PUBLIC_KEY_SIZE: usize = 564;
pub const SIDH_P751_PUBLIC_KEY_SIZE: usize = 564;
/// The shared secret size, in bytes.
pub const SHARED_SECRET_SIZE: usize = 188;
pub const SIDH_P751_SHARED_SECRET_SIZE: usize = 188;
const MAX_INT_POINTS_ALICE: usize = 8;
const MAX_INT_POINTS_BOB: usize = 10;
@ -125,7 +125,7 @@ impl SIDHPublicKeyBob {
/// Alice's secret key.
#[derive(Copy, Clone)]
pub struct SIDHSecretKeyAlice {
pub scalar: [u8; SECRET_KEY_SIZE],
pub scalar: [u8; SIDH_P751_SECRET_KEY_SIZE],
}
impl Debug for SIDHSecretKeyAlice {
@ -206,7 +206,7 @@ impl SIDHSecretKeyAlice {
/// Compute (Alice's view of) a shared secret using Alice's secret key and Bob's public key.
#[allow(non_snake_case)]
pub fn shared_secret(&self, bob_public: &SIDHPublicKeyBob) -> [u8; SHARED_SECRET_SIZE] {
pub fn shared_secret(&self, bob_public: &SIDHPublicKeyBob) -> [u8; SIDH_P751_SHARED_SECRET_SIZE] {
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
let xQ = ProjectivePoint::from_affine(&bob_public.affine_xQ);
@ -250,7 +250,7 @@ impl SIDHSecretKeyAlice {
/// Bob's secret key.
#[derive(Copy, Clone)]
pub struct SIDHSecretKeyBob {
pub scalar: [u8; SECRET_KEY_SIZE],
pub scalar: [u8; SIDH_P751_SECRET_KEY_SIZE],
}
impl Debug for SIDHSecretKeyBob {
@ -325,7 +325,7 @@ impl SIDHSecretKeyBob {
/// Compute (Bob's view of) a shared secret using Bob's secret key and Alice's public key.
#[allow(non_snake_case)]
pub fn shared_secret(&self, alice_public: &SIDHPublicKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
pub fn shared_secret(&self, alice_public: &SIDHPublicKeyAlice) -> [u8; SIDH_P751_SHARED_SECRET_SIZE] {
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
let xQ = ProjectivePoint::from_affine(&alice_public.affine_xQ);
@ -367,7 +367,7 @@ impl SIDHSecretKeyBob {
/// implement SIDH validation, each keypair should be used for at most one
/// shared secret computation.
pub fn generate_alice_keypair<R: RngCore + CryptoRng>(rng: &mut R) -> (SIDHPublicKeyAlice, SIDHSecretKeyAlice) {
let mut scalar = [0u8; SECRET_KEY_SIZE];
let mut scalar = [0u8; SIDH_P751_SECRET_KEY_SIZE];
rng.fill_bytes(&mut scalar[..]);
// Bit-twiddle to ensure scalar is in 2*[0,2^371):
@ -388,7 +388,7 @@ pub fn generate_alice_keypair<R: RngCore + CryptoRng>(rng: &mut R) -> (SIDHPubli
/// implement SIDH validation, each keypair should be used for at most one
/// shared secret computation.
pub fn generate_bob_keypair<R: RngCore + CryptoRng>(rng: &mut R) -> (SIDHPublicKeyBob, SIDHSecretKeyBob) {
let mut scalar = [0u8; SECRET_KEY_SIZE];
let mut scalar = [0u8; SIDH_P751_SECRET_KEY_SIZE];
// Perform rejection sampling to obtain a random value in [0,3^238]:
let mut ok: u32 = 1;
for _ in 0..102 {
@ -501,7 +501,7 @@ mod test {
//
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
#[allow(non_snake_case)]
pub fn alice_shared_secret_slow(bob_public: &SIDHPublicKeyBob, alice_secret: &SIDHSecretKeyAlice) -> [u8; SHARED_SECRET_SIZE] {
pub fn alice_shared_secret_slow(bob_public: &SIDHPublicKeyBob, alice_secret: &SIDHSecretKeyAlice) -> [u8; SIDH_P751_SHARED_SECRET_SIZE] {
let current_curve = ProjectiveCurveParameters::recover_curve_parameters(&bob_public.affine_xP, &bob_public.affine_xQ, &bob_public.affine_xQmP);
let xP = ProjectivePoint::from_affine(&bob_public.affine_xP);
let xQ = ProjectivePoint::from_affine(&bob_public.affine_xQ);
@ -532,7 +532,7 @@ mod test {
//
// This function just exists to ensure that the fast isogeny-tree strategy works correctly.
#[allow(non_snake_case)]
pub fn bob_shared_secret_slow(alice_public: &SIDHPublicKeyAlice, bob_secret: &SIDHSecretKeyBob) -> [u8; SHARED_SECRET_SIZE] {
pub fn bob_shared_secret_slow(alice_public: &SIDHPublicKeyAlice, bob_secret: &SIDHSecretKeyBob) -> [u8; SIDH_P751_SHARED_SECRET_SIZE] {
let mut current_curve = ProjectiveCurveParameters::recover_curve_parameters(&alice_public.affine_xP, &alice_public.affine_xQ, &alice_public.affine_xQmP);
let xP = ProjectivePoint::from_affine(&alice_public.affine_xP);
let xQ = ProjectivePoint::from_affine(&alice_public.affine_xQ);

View file

@ -15,13 +15,13 @@ pub mod defaults;
mod node;
/// Standard packet buffer type including pool container.
pub type PacketBuffer = crate::util::pool::Pooled<Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::vl1::buffer::PooledBufferFactory<{ crate::vl1::protocol::PACKET_SIZE_MAX }>>;
pub type PacketBuffer = crate::util::pool::Pooled<crate::vl1::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::PacketBufferFactory>;
/// Factory type to supply to a new PacketBufferPool.
pub type PacketBufferFactory = crate::vl1::buffer::PooledBufferFactory<{ crate::vl1::protocol::PACKET_SIZE_MAX }>;
/// Source for instances of PacketBuffer
pub type PacketBufferPool = crate::util::pool::Pool<Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::vl1::buffer::PacketBufferFactory>;
pub type PacketBufferPool = crate::util::pool::Pool<crate::vl1::buffer::Buffer<{ crate::vl1::protocol::PACKET_SIZE_MAX }>, crate::PacketBufferFactory>;
pub use node::{CallerInterface, Node};

View file

@ -7,22 +7,21 @@
*/
use std::sync::atomic::AtomicU32;
use std::io::Write;
use std::convert::TryInto;
use zerotier_core_crypto::c25519::C25519KeyPair;
use zerotier_core_crypto::hash::SHA384_HASH_SIZE;
use zerotier_core_crypto::p521::P521KeyPair;
use zerotier_core_crypto::c25519::{C25519KeyPair, C25519_PUBLIC_KEY_SIZE};
use zerotier_core_crypto::hash::{SHA384_HASH_SIZE, SHA384};
use zerotier_core_crypto::p521::{P521KeyPair, P521_PUBLIC_KEY_SIZE, P521PublicKey};
use zerotier_core_crypto::random::SecureRandom;
use zerotier_core_crypto::secret::Secret;
use zerotier_core_crypto::sidhp751::{SIDHPublicKeyAlice, SIDHPublicKeyBob, SIDHSecretKeyAlice, SIDHSecretKeyBob};
use zerotier_core_crypto::sidhp751::{SIDHPublicKeyAlice, SIDHPublicKeyBob, SIDHSecretKeyAlice, SIDHSecretKeyBob, SIDH_P751_PUBLIC_KEY_SIZE};
use zerotier_core_crypto::varint;
use crate::vl1::Address;
use crate::vl1::protocol::EPHEMERAL_SECRET_SIDH_TTL;
use crate::vl1::protocol::EphemeralKeyAgreementAlgorithm;
use crate::vl1::symmetricsecret::SymmetricSecret;
const EPHEMERAL_CIPHER_C25519: u8 = 1;
const EPHEMERAL_CIPHER_P521: u8 = 2;
const EPHEMERAL_CIPHER_SIDH_P751: u8 = 3;
#[derive(Copy, Clone)]
enum SIDHSecretKey {
Alice(SIDHPublicKeyAlice, SIDHSecretKeyAlice),
@ -43,13 +42,22 @@ impl SIDHSecretKey {
pub fn generate(local_address: Address, remote_address: Address) -> SIDHSecretKey {
let mut rng = SecureRandom::get();
if local_address < remote_address {
let (p, s) = zerotier_core_crypto::sidh::sidh::generate_alice_keypair(&mut rng);
let (p, s) = zerotier_core_crypto::sidhp751::generate_alice_keypair(&mut rng);
SIDHSecretKey::Alice(p, s)
} else {
let (p, s) = zerotier_core_crypto::sidh::sidh::generate_bob_keypair(&mut rng);
let (p, s) = zerotier_core_crypto::sidhp751::generate_bob_keypair(&mut rng);
SIDHSecretKey::Bob(p, s)
}
}
/// Returns 0 if Alice, 1 if Bob.
#[inline(always)]
pub fn role(&self) -> u8 {
match self {
Self::Alice(_, _) => 0,
Self::Bob(_, _) => 1,
}
}
}
/// An ephemeral secret key negotiated to implement forward secrecy.
@ -57,7 +65,7 @@ pub struct EphemeralSecret {
timestamp_ticks: i64,
c25519: C25519KeyPair,
p521: P521KeyPair,
sidhp751: SIDHSecretKey,
sidhp751: Option<SIDHSecretKey>,
}
impl EphemeralSecret {
@ -70,19 +78,194 @@ impl EphemeralSecret {
timestamp_ticks: time_ticks,
c25519: C25519KeyPair::generate(true),
p521: P521KeyPair::generate(true).expect("NIST P-521 key pair generation failed"),
sidhp751: SIDHSecretKey::generate(local_address, remote_address),
sidhp751: Some(SIDHSecretKey::generate(local_address, remote_address)),
}
}
/// Create a public version of this ephemeral secret to share with our counterparty.
pub fn public(&self) -> Vec<u8> {
todo!()
pub fn public_bytes(&self) -> Vec<u8> {
let mut b: Vec<u8> = Vec::with_capacity(8 + C25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + SIDH_P751_PUBLIC_KEY_SIZE);
b.push(EphemeralKeyAgreementAlgorithm::C25519 as u8);
let _ = varint::write(&mut b, C25519_PUBLIC_KEY_SIZE as u64);
let _ = b.write_all(&self.c25519.public_bytes());
let _ = self.sidhp751.map(|sidhp751| {
b.push(EphemeralKeyAgreementAlgorithm::SIDHP751 as u8);
let _ = varint::write(&mut b, (SIDH_P751_PUBLIC_KEY_SIZE + 1) as u64);
b.push(sidhp751.role());
let pk = match &sidhp751 {
SIDHSecretKey::Alice(a, _) => a.to_bytes(),
SIDHSecretKey::Bob(b, _) => b.to_bytes()
};
let _ = b.write_all(&pk);
});
// FIPS note: any FIPS compliant ciphers must be last or the exchange will not be FIPS compliant. That's
// because we chain/ratchet using KHDF and non-FIPS ciphers are considered "salt" inputs for HKDF from a
// FIPS point of view. Final key must be HKDF(salt, FIPS-compliant algorithm secret). Order has no actual
// implication for security.
b.push(EphemeralKeyAgreementAlgorithm::NistP521ECDH as u8);
let _ = varint::write(&mut b, P521_PUBLIC_KEY_SIZE as u64);
let _ = b.write_all(self.p521.public_key_bytes());
b
}
/// Perform ephemeral key agreement.
///
/// None is returned if the public key data is malformed, no algorithms overlap, etc.
///
/// Input is the previous session key. The long-lived identity key exchange key starts
/// the ratchet sequence, or rather a key derived from it for this purpose.
///
/// Since ephemeral secrets should only be used once, this consumes the object.
pub fn agree(self, time_ticks: i64, static_secret: &SymmetricSecret, previous_ephemeral_secret: Option<&EphemeralSymmetricSecret>, other_public_bytes: &[u8]) -> Option<EphemeralSymmetricSecret> {
let (ratchet_count, mut key) = previous_ephemeral_secret.map_or_else(|| {
(0_u64, static_secret.next_ephemeral_ratchet_key.clone())
}, |previous_ephemeral_secret| {
(previous_ephemeral_secret.ratchet_count + 1, Secret(SHA384::hmac(&static_secret.next_ephemeral_ratchet_key.0, &previous_ephemeral_secret.secret.next_ephemeral_ratchet_key.0)))
});
let mut algs: Vec<EphemeralKeyAgreementAlgorithm> = Vec::with_capacity(3);
let mut other_public_bytes = other_public_bytes;
while !other_public_bytes.is_empty() {
let cipher = other_public_bytes[0];
other_public_bytes = &other_public_bytes[1..];
let key_len = varint::read(&mut other_public_bytes);
if key_len.is_err() {
return None;
}
let key_len = key_len.unwrap().0 as usize;
match cipher.try_into() {
Ok(EphemeralKeyAgreementAlgorithm::C25519) => {
if other_public_bytes.len() < C25519_PUBLIC_KEY_SIZE || key_len != C25519_PUBLIC_KEY_SIZE {
return None;
}
let c25519_secret = self.c25519.agree(&other_public_bytes[0..C25519_PUBLIC_KEY_SIZE]);
other_public_bytes = &other_public_bytes[C25519_PUBLIC_KEY_SIZE..];
key.0 = SHA384::hmac(&key.0, &c25519_secret.0);
algs.push(EphemeralKeyAgreementAlgorithm::C25519);
},
Ok(EphemeralKeyAgreementAlgorithm::SIDHP751) => {
if other_public_bytes.len() < (SIDH_P751_PUBLIC_KEY_SIZE + 1) || key_len != (SIDH_P751_PUBLIC_KEY_SIZE + 1) {
return None;
}
let _ = match self.sidhp751.as_ref() {
Some(SIDHSecretKey::Alice(_, seck)) => {
if other_public_bytes[0] != 0 { // Alice can't agree with Alice
None
} else {
Some(Secret(seck.shared_secret(&SIDHPublicKeyBob::from_bytes(&other_public_bytes[1..(SIDH_P751_PUBLIC_KEY_SIZE + 1)]))))
}
},
Some(SIDHSecretKey::Bob(_, seck)) => {
if other_public_bytes[0] != 1 { // Bob can't agree with Bob
None
} else {
Some(Secret(seck.shared_secret(&SIDHPublicKeyAlice::from_bytes(&other_public_bytes[1..(SIDH_P751_PUBLIC_KEY_SIZE + 1)]))))
}
},
None => None,
}.map(|sidh_secret| {
key.0 = SHA384::hmac(&key.0, &sidh_secret.0);
algs.push(EphemeralKeyAgreementAlgorithm::SIDHP751);
});
other_public_bytes = &other_public_bytes[(SIDH_P751_PUBLIC_KEY_SIZE + 1)..];
},
Ok(EphemeralKeyAgreementAlgorithm::NistP521ECDH) => {
if other_public_bytes.len() < P521_PUBLIC_KEY_SIZE || key_len != P521_PUBLIC_KEY_SIZE {
return None;
}
let p521_public = P521PublicKey::from_bytes(&other_public_bytes[0..P521_PUBLIC_KEY_SIZE]);
other_public_bytes = &other_public_bytes[P521_PUBLIC_KEY_SIZE..];
if p521_public.is_none() {
return None;
}
let p521_key = self.p521.agree(p521_public.as_ref().unwrap());
if p521_key.is_none() {
return None;
}
key.0 = SHA384::hmac(&key.0, &p521_key.unwrap().0);
algs.push(EphemeralKeyAgreementAlgorithm::NistP521ECDH);
},
Err(_) => {
if other_public_bytes.len() < key_len {
return None;
}
other_public_bytes = &other_public_bytes[key_len..];
}
}
}
return if !algs.is_empty() {
Some(EphemeralSymmetricSecret {
secret: SymmetricSecret::new(key),
agreement_algorithms: algs,
agreement_timestamp_ticks: time_ticks,
local_secret_timestamp_ticks: self.timestamp_ticks,
ratchet_count,
encrypt_uses: AtomicU32::new(0),
decrypt_uses: AtomicU32::new(0)
})
} else {
None
};
}
}
pub struct EphemeralSymmetricSecret {
secret: SymmetricSecret,
agreement_algorithms: Vec<EphemeralKeyAgreementAlgorithm>,
agreement_timestamp_ticks: i64,
local_secret_timestamp_ticks: i64,
ratchet_count: u64,
encrypt_uses: AtomicU32,
decrypt_uses: AtomicU32,
}
impl EphemeralSymmetricSecret {
#[inline(always)]
pub fn use_secret_to_encrypt(&self) -> &SymmetricSecret {
let _ = self.encrypt_uses.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
&self.secret
}
#[inline(always)]
pub fn use_secret_to_decrypt(&self) -> &SymmetricSecret {
let _ = self.decrypt_uses.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
&self.secret
}
pub fn is_fips_compliant(&self) -> bool {
self.agreement_algorithms.last().map_or(false, |alg| alg.is_fips_compliant())
}
}
#[cfg(test)]
mod tests {
use crate::vl1::ephemeral::EphemeralSecret;
use crate::vl1::Address;
use crate::vl1::symmetricsecret::SymmetricSecret;
use zerotier_core_crypto::secret::Secret;
#[test]
fn ephemeral_agreement() {
let static_secret = SymmetricSecret::new(Secret([1_u8; 48]));
let alice = EphemeralSecret::new(1, Address::from_u64(0xdeadbeef00).unwrap(), Address::from_u64(0xbeefdead00).unwrap());
let bob = EphemeralSecret::new(1, Address::from_u64(0xbeefdead00).unwrap(), Address::from_u64(0xdeadbeef00).unwrap());
let alice_public_bytes = alice.public_bytes();
let bob_public_bytes = bob.public_bytes();
let alice_key = alice.agree(2, &static_secret, None, bob_public_bytes.as_slice()).unwrap();
let bob_key = bob.agree(2, &static_secret, None, alice_public_bytes.as_slice()).unwrap();
assert_eq!(&alice_key.secret.key.0, &bob_key.secret.key.0);
//println!("ephemeral_agreement secret: {}", zerotier_core_crypto::hex::to_string(&alice_key.secret.key.0));
}
}

View file

@ -6,7 +6,7 @@
* https://www.zerotier.com/
*/
use crate::vl1::vl1node::PacketBuffer;
use crate::PacketBuffer;
use crate::vl1::protocol::*;
/// Packet fragment re-assembler and container.

View file

@ -33,4 +33,4 @@ pub use dictionary::Dictionary;
pub use inetaddress::InetAddress;
pub use peer::Peer;
pub use path::Path;
pub use vl1node::{PacketBuffer, PacketBufferPool, PacketBufferFactory, VL1CallerInterface};
pub use vl1node::{VL1Node, VL1CallerInterface};

View file

@ -14,8 +14,9 @@ use parking_lot::Mutex;
use crate::util::U64PassThroughHasher;
use crate::vl1::Endpoint;
use crate::vl1::fragmentedpacket::FragmentedPacket;
use crate::vl1::vl1node::{PacketBuffer, VL1CallerInterface};
use crate::vl1::vl1node::VL1CallerInterface;
use crate::vl1::protocol::*;
use crate::PacketBuffer;
/// Keepalive interval for paths in milliseconds.
pub(crate) const PATH_KEEPALIVE_INTERVAL: i64 = 20000;

View file

@ -10,6 +10,7 @@ use std::mem::MaybeUninit;
use crate::vl1::Address;
use crate::vl1::buffer::{RawObject, Buffer};
use std::convert::TryFrom;
pub const VERB_VL1_NOP: u8 = 0x00;
pub const VERB_VL1_HELLO: u8 = 0x01;
@ -47,7 +48,7 @@ pub const KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0: u8 = b'0';
pub const KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1: u8 = b'1';
/// KBKDF usage label for acknowledgement of a shared secret.
pub const KBKDF_KEY_USAGE_LABEL_EPHEMERAL_ACK: u8 = b'A';
pub const KBKDF_KEY_USAGE_LABEL_EPHEMERAL_RATCHET: u8 = b'E';
/// Try to re-key ephemeral keys after this time.
pub const EPHEMERAL_SECRET_REKEY_AFTER_TIME: i64 = 1000 * 60 * 60; // 1 hour
@ -176,6 +177,37 @@ pub const WHOIS_RETRY_MAX: u16 = 3;
/// Maximum number of packets to queue up behind a WHOIS.
pub const WHOIS_MAX_WAITING_PACKETS: usize = 64;
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum EphemeralKeyAgreementAlgorithm {
C25519 = 1,
SIDHP751 = 2,
NistP521ECDH = 3
}
impl EphemeralKeyAgreementAlgorithm {
pub fn is_fips_compliant(&self) -> bool {
match self {
Self::NistP521ECDH => true,
_ => false
}
}
}
impl TryFrom<u8> for EphemeralKeyAgreementAlgorithm {
type Error = ();
#[inline(always)]
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::C25519),
2 => Ok(Self::SIDHP751),
3 => Ok(Self::NistP521ECDH),
_ => Err(())
}
}
}
/// Compress a packet and return true if compressed.
/// The 'dest' buffer must be empty (will panic otherwise). A return value of false indicates an error or
/// that the data was not compressible. The state of the destination buffer is undefined on a return

View file

@ -14,7 +14,7 @@ use zerotier_core_crypto::kbkdf::zt_kbkdf_hmac_sha384;
use zerotier_core_crypto::secret::Secret;
use crate::util::pool::{Pool, PoolFactory};
use crate::vl1::protocol::{KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC};
use crate::vl1::protocol::{KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC, KBKDF_KEY_USAGE_LABEL_EPHEMERAL_RATCHET};
pub struct AesGmacSivPoolFactory(Secret<SHA384_HASH_SIZE>, Secret<SHA384_HASH_SIZE>);
@ -32,13 +32,21 @@ impl PoolFactory<AesGmacSiv> for AesGmacSivPoolFactory {
pub struct SymmetricSecret {
pub key: Secret<SHA384_HASH_SIZE>,
pub packet_hmac_key: Secret<SHA384_HASH_SIZE>,
pub next_ephemeral_ratchet_key: Secret<SHA384_HASH_SIZE>,
pub hello_dictionary_keyed_cipher: Mutex<AesCtr>,
pub aes_gmac_siv: Pool<AesGmacSiv, AesGmacSivPoolFactory>,
}
impl PartialEq for SymmetricSecret {
fn eq(&self, other: &Self) -> bool { self.key.0.eq(&other.key.0) }
}
impl Eq for SymmetricSecret {}
impl SymmetricSecret {
pub fn new(base_key: Secret<SHA384_HASH_SIZE>) -> SymmetricSecret {
let usage_packet_hmac = zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_PACKET_HMAC, 0, 0);
let usage_ephemeral_ratchet = zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_EPHEMERAL_RATCHET, 0, 0);
let usage_hello_dictionary_key = zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_HELLO_DICTIONARY_ENCRYPT, 0, 0);
let aes_factory = AesGmacSivPoolFactory(
zt_kbkdf_hmac_sha384(&base_key.0, KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0, 0, 0),
@ -46,6 +54,7 @@ impl SymmetricSecret {
SymmetricSecret {
key: base_key,
packet_hmac_key: usage_packet_hmac,
next_ephemeral_ratchet_key: usage_ephemeral_ratchet,
hello_dictionary_keyed_cipher: Mutex::new(AesCtr::new(&usage_hello_dictionary_key.0[0..32])),
aes_gmac_siv: Pool::new(2, aes_factory),
}

View file

@ -13,8 +13,9 @@ use parking_lot::Mutex;
use crate::util::gate::IntervalGate;
use crate::vl1::Address;
use crate::vl1::fragmentedpacket::FragmentedPacket;
use crate::vl1::vl1node::{VL1Node, PacketBuffer, VL1CallerInterface};
use crate::vl1::vl1node::{VL1Node, VL1CallerInterface};
use crate::vl1::protocol::{WHOIS_RETRY_INTERVAL, WHOIS_MAX_WAITING_PACKETS, WHOIS_RETRY_MAX};
use crate::PacketBuffer;
pub(crate) enum QueuedPacket {
Unfragmented(PacketBuffer),

View file

@ -32,6 +32,6 @@ impl VL1PacketHandler for Switch {
impl Switch {
pub fn new() -> Self {
Self
Self{}
}
}