mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-22 14:23:59 -07:00
Some more ZSSP work and a VDF we may use.
This commit is contained in:
parent
df39130082
commit
0b74ef6f3c
4 changed files with 189 additions and 77 deletions
|
@ -3,6 +3,7 @@
|
|||
pub mod aes;
|
||||
pub mod aes_gmac_siv;
|
||||
pub mod hash;
|
||||
pub mod mimcvdf;
|
||||
pub mod p384;
|
||||
pub mod poly1305;
|
||||
pub mod random;
|
||||
|
|
148
crypto/src/mimcvdf.rs
Normal file
148
crypto/src/mimcvdf.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* (c) ZeroTier, Inc.
|
||||
* https://www.zerotier.com/
|
||||
*/
|
||||
|
||||
/*
|
||||
* https://eprint.iacr.org/2016/492.pdf
|
||||
* https://vitalik.ca/general/2018/07/21/starks_part_3.html
|
||||
*/
|
||||
|
||||
// 2^127 - 39
|
||||
const PRIME: u128 = 170141183460469231731687303715884105689;
|
||||
// 2p-1/3
|
||||
const PRIME_2P_MINUS_1_DIV_3: u128 = 113427455640312821154458202477256070459;
|
||||
|
||||
const K_COUNT_MASK: usize = 63;
|
||||
const K: [u64; 64] = [
|
||||
0x921cdfd99022340f,
|
||||
0xe7c65f78c70afaa8,
|
||||
0x72793744494c4fda,
|
||||
0x67759e2688bc9c0a,
|
||||
0x7681a224661f0ac0,
|
||||
0xa7b81b099925a2bf,
|
||||
0x16d43792e66b030a,
|
||||
0x841bd90742d26ee9,
|
||||
0xb1346ec08db97053,
|
||||
0xd044229c1173d972,
|
||||
0xf4813498dfdead0e,
|
||||
0xe46dca4c237d2c28,
|
||||
0xac64872778089599,
|
||||
0x67be75af74416e74,
|
||||
0xb9dec3aefd3ae012,
|
||||
0xf0497147953c4276,
|
||||
0xf6ac07fd3944177d,
|
||||
0xccf1c28813eb589b,
|
||||
0x49abb5e2b0bff5bd,
|
||||
0xd5c15eeb39587d69,
|
||||
0x9c6ff50ee6898649,
|
||||
0x763f3b25524a0fbf,
|
||||
0xa6029c37f715c02c,
|
||||
0xe458a5902b2b5629,
|
||||
0x8e4d6be6a1ba32c5,
|
||||
0x052aba0b61738f20,
|
||||
0xc18a6901fa026b12,
|
||||
0x137df11cf1dbe811,
|
||||
0x5da0310e419be602,
|
||||
0xc66ddec578f52891,
|
||||
0xe4eae4efc0f0d54f,
|
||||
0xf9d488269f118012,
|
||||
0xcf9b5108f66e77d1,
|
||||
0x443ba29939f5a657,
|
||||
0xa4e4b7d28c51e5c2,
|
||||
0xe030d1772f112c01,
|
||||
0xe136f0cf8da5e172,
|
||||
0x3e9ee638f9663dc2,
|
||||
0xbc5c1db73e639dfd,
|
||||
0xa9fbbaa873fedf73,
|
||||
0xffb2a5247d10ab8f,
|
||||
0x06e6f3b5ae4b67ac,
|
||||
0x475e7d427d331282,
|
||||
0xcac6237c40a9d653,
|
||||
0xe9a15c1d177beefa,
|
||||
0xa14ef2111c2175a3,
|
||||
0x8427d4b68982fc21,
|
||||
0x12171e2a55d43343,
|
||||
0x37715fdea87a0a60,
|
||||
0x24bc5d28cff8ecad,
|
||||
0x92276e4118304e62,
|
||||
0x824b66792f58dd45,
|
||||
0xe43973cf253b6947,
|
||||
0xd0db2c5a2a4f064d,
|
||||
0x734cdb241520ad04,
|
||||
0xcec4f2ce5013069e,
|
||||
0x2741c83c07bbf9e0,
|
||||
0x284be707dcbda1a4,
|
||||
0xd602f3d8545799b2,
|
||||
0xea3977f56573b4d2,
|
||||
0x0723fda64d57d0c6,
|
||||
0x04dc344d0dde863a,
|
||||
0x7584143462914be4,
|
||||
0x111307f7823dfcc6,
|
||||
];
|
||||
|
||||
fn mulmod<const M: u128>(mut a: u128, mut b: u128) -> u128 {
|
||||
let mut res: u128 = 0;
|
||||
a %= M;
|
||||
loop {
|
||||
if (b & 1) != 0 {
|
||||
res = res.wrapping_add(a) % M;
|
||||
}
|
||||
b = b.wrapping_shr(1);
|
||||
if b != 0 {
|
||||
a = a.wrapping_shl(1) % M;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn powmod<const M: u128>(mut base: u128, mut exp: u128) -> u128 {
|
||||
let mut res: u128 = 1;
|
||||
loop {
|
||||
if (exp & 1) != 0 {
|
||||
res = mulmod::<M>(base, res);
|
||||
}
|
||||
exp = exp.wrapping_shr(1);
|
||||
if exp != 0 {
|
||||
base = mulmod::<M>(base, base);
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delay(mut input: u128, rounds: usize) -> u128 {
|
||||
debug_assert!(rounds > 0);
|
||||
input %= PRIME;
|
||||
for r in 1..(rounds + 1) {
|
||||
input = powmod::<PRIME>(input ^ (K[(rounds - r) & K_COUNT_MASK] as u128), PRIME_2P_MINUS_1_DIV_3);
|
||||
}
|
||||
input
|
||||
}
|
||||
|
||||
pub fn verify(mut proof: u128, expected: u128, rounds: usize) -> bool {
|
||||
debug_assert!(rounds > 0);
|
||||
for r in 0..rounds {
|
||||
proof = mulmod::<PRIME>(proof, mulmod::<PRIME>(proof, proof)) ^ (K[r & K_COUNT_MASK] as u128);
|
||||
}
|
||||
proof == (expected % PRIME)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn delay_and_verify() {
|
||||
for i in 1..5 {
|
||||
let input = (crate::random::xorshift64_random() as u128).wrapping_mul(crate::random::xorshift64_random() as u128);
|
||||
let proof = delay(input, i * 3);
|
||||
assert!(verify(proof, input, i * 3));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,8 +22,6 @@ pub(crate) const SESSION_PROTOCOL_VERSION: u8 = 0x00;
|
|||
pub(crate) const COUNTER_WINDOW_MAX_OOO: usize = 16;
|
||||
pub(crate) const COUNTER_WINDOW_MAX_SKIP_AHEAD: u64 = 16777216;
|
||||
|
||||
pub(crate) const NOISE_MAX_HANDSHAKE_PACKET_SIZE: usize = 2048;
|
||||
|
||||
pub(crate) const PACKET_TYPE_DATA: u8 = 0;
|
||||
pub(crate) const PACKET_TYPE_ALICE_NOISE_XK_INIT: u8 = 1;
|
||||
pub(crate) const PACKET_TYPE_BOB_NOISE_XK_ACK: u8 = 2;
|
||||
|
@ -41,7 +39,8 @@ pub(crate) const KBKDF_KEY_USAGE_LABEL_AES_GCM_ALICE_TO_BOB: u8 = b'A'; // AES-G
|
|||
pub(crate) const KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE: u8 = b'B'; // AES-GCM in B->A direction
|
||||
|
||||
pub(crate) const MAX_FRAGMENTS: usize = 48; // hard protocol max: 63
|
||||
pub(crate) const KEY_EXCHANGE_MAX_FRAGMENTS: usize = 8; // enough room for p384 + ZT identity + kyber1024 + tag/hmac/etc.
|
||||
pub(crate) const MAX_NOISE_HANDSHAKE_FRAGMENTS: usize = 16; // enough room for p384 + ZT identity + kyber1024 + tag/hmac/etc.
|
||||
pub(crate) const MAX_NOISE_HANDSHAKE_SIZE: usize = MAX_NOISE_HANDSHAKE_FRAGMENTS * MIN_TRANSPORT_MTU;
|
||||
|
||||
pub(crate) const AES_KEY_SIZE: usize = 32;
|
||||
pub(crate) const AES_HEADER_CHECK_KEY_SIZE: usize = 16;
|
||||
|
@ -80,13 +79,12 @@ pub(crate) struct BobNoiseXKAck {
|
|||
pub bob_hk_ciphertext: [u8; KYBER_CIPHERTEXTBYTES],
|
||||
// -- end encrypted sectiion
|
||||
pub hmac_es_ee: [u8; HMAC_SHA384_SIZE],
|
||||
pub hmac_es_ee_se_hk_psk: [u8; HMAC_SHA384_SIZE],
|
||||
}
|
||||
|
||||
impl BobNoiseXKAck {
|
||||
pub const ENC_START: usize = HEADER_SIZE + 1 + P384_PUBLIC_KEY_SIZE;
|
||||
pub const AUTH_START: usize = Self::ENC_START + SessionId::SIZE + KYBER_CIPHERTEXTBYTES;
|
||||
pub const SIZE: usize = Self::AUTH_START + HMAC_SHA384_SIZE + HMAC_SHA384_SIZE;
|
||||
pub const SIZE: usize = Self::AUTH_START + HMAC_SHA384_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
109
zssp/src/zssp.rs
109
zssp/src/zssp.rs
|
@ -23,7 +23,6 @@ use zerotier_crypto::{random, secure_eq};
|
|||
use zerotier_utils::gatherarray::GatherArray;
|
||||
use zerotier_utils::memory;
|
||||
use zerotier_utils::ringbuffermap::RingBufferMap;
|
||||
use zerotier_utils::unlikely_branch;
|
||||
|
||||
use pqc_kyber::{KYBER_SECRETKEYBYTES, KYBER_SSBYTES};
|
||||
|
||||
|
@ -38,7 +37,8 @@ use crate::sessionid::SessionId;
|
|||
/// Each application using ZSSP must create an instance of this to own sessions and
|
||||
/// defragment incoming packets that are not yet associated with a session.
|
||||
pub struct Context<Application: ApplicationLayer> {
|
||||
initial_offer_defrag: Mutex<RingBufferMap<u64, GatherArray<Application::IncomingPacketBuffer, KEY_EXCHANGE_MAX_FRAGMENTS>, 1024, 1024>>,
|
||||
initial_offer_defrag:
|
||||
Mutex<RingBufferMap<u64, GatherArray<Application::IncomingPacketBuffer, MAX_NOISE_HANDSHAKE_FRAGMENTS>, 1024, 1024>>,
|
||||
sessions: RwLock<SessionMaps<Application>>,
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ struct SessionMaps<Application: ApplicationLayer> {
|
|||
incomplete: HashMap<SessionId, Arc<NoiseXKIncoming>>,
|
||||
}
|
||||
|
||||
/// State for an incoming incomplete Noise_XK session that isn't fully negotiated yet.
|
||||
struct NoiseXKIncoming {
|
||||
timestamp: i64,
|
||||
alice_session_id: SessionId,
|
||||
|
@ -308,7 +309,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
) -> Result<ReceiveResult<'b, Application>, Error> {
|
||||
let incoming_packet: &mut [u8] = incoming_packet_buf.as_mut();
|
||||
if incoming_packet.len() < MIN_PACKET_SIZE {
|
||||
unlikely_branch();
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
|
||||
|
@ -345,7 +345,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
return Ok(ReceiveResult::Ok);
|
||||
}
|
||||
} else {
|
||||
unlikely_branch();
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
} else {
|
||||
|
@ -365,11 +364,9 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
unlikely_branch();
|
||||
return Ok(ReceiveResult::Ignored);
|
||||
}
|
||||
} else {
|
||||
unlikely_branch();
|
||||
if let Some(p) = self.sessions.read().unwrap().incomplete.get(&local_session_id).cloned() {
|
||||
Aes::new(p.header_check_cipher_key.as_bytes())
|
||||
.decrypt_block_in_place(&mut incoming_packet[HEADER_CHECK_ENCRYPT_START..HEADER_CHECK_ENCRYPT_END]);
|
||||
|
@ -378,12 +375,12 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
return Err(Error::UnknownLocalSessionId(local_session_id));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unlikely_branch();
|
||||
}
|
||||
|
||||
let (key_index, packet_type, fragment_count, fragment_no, counter) = parse_packet_header(&incoming_packet);
|
||||
// If we make it here the packet is not associated with a session or is associated with an
|
||||
// incomplete session (Noise_XK mid-negotiation).
|
||||
|
||||
let (key_index, packet_type, fragment_count, fragment_no, counter) = parse_packet_header(&incoming_packet);
|
||||
if fragment_count > 1 {
|
||||
let mut defrag = self.initial_offer_defrag.lock().unwrap();
|
||||
let fragment_gather_array = defrag.get_or_create_mut(&counter, || GatherArray::new(fragment_count));
|
||||
|
@ -424,10 +421,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
return Ok(ReceiveResult::Ok);
|
||||
}
|
||||
|
||||
/// Called internally when all fragments of a packet are received.
|
||||
///
|
||||
/// NOTE: header check codes will already have been validated on receipt of each fragment. AEAD authentication
|
||||
/// and decryption has NOT yet been performed, and is done here.
|
||||
fn receive_complete<
|
||||
'b,
|
||||
SendFunction: FnMut(Option<&Arc<Session<Application>>>, &mut [u8]),
|
||||
|
@ -466,7 +459,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
let current_frag_data_start = data_len;
|
||||
data_len += f.len() - HEADER_SIZE;
|
||||
if data_len > data_buf.len() {
|
||||
unlikely_branch();
|
||||
session_key.return_receive_cipher(c);
|
||||
return Err(Error::DataBufferTooSmall);
|
||||
}
|
||||
|
@ -477,12 +469,10 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
let current_frag_data_start = data_len;
|
||||
let last_fragment = fragments.last().unwrap().as_ref();
|
||||
if last_fragment.len() < (HEADER_SIZE + AES_GCM_TAG_SIZE) {
|
||||
unlikely_branch();
|
||||
return Err(Error::InvalidPacket);
|
||||
}
|
||||
data_len += last_fragment.len() - (HEADER_SIZE + AES_GCM_TAG_SIZE);
|
||||
if data_len > data_buf.len() {
|
||||
unlikely_branch();
|
||||
session_key.return_receive_cipher(c);
|
||||
return Err(Error::DataBufferTooSmall);
|
||||
}
|
||||
|
@ -492,8 +482,7 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
&mut data_buf[current_frag_data_start..data_len],
|
||||
);
|
||||
|
||||
let gcm_tag = &last_fragment[payload_end..];
|
||||
let aead_authentication_ok = c.finish_decrypt(gcm_tag);
|
||||
let aead_authentication_ok = c.finish_decrypt(&last_fragment[payload_end..]);
|
||||
session_key.return_receive_cipher(c);
|
||||
|
||||
if aead_authentication_ok {
|
||||
|
@ -504,7 +493,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
if session_key.confirmed {
|
||||
drop(state);
|
||||
} else {
|
||||
unlikely_branch();
|
||||
let key_created_at_counter = session_key.created_at_counter;
|
||||
drop(state);
|
||||
|
||||
|
@ -523,21 +511,18 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
|
||||
return Ok(ReceiveResult::OkData(session, &mut data_buf[..data_len]));
|
||||
} else {
|
||||
unlikely_branch();
|
||||
return Ok(ReceiveResult::Ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Err(Error::FailedAuthentication);
|
||||
} else {
|
||||
unlikely_branch();
|
||||
return Err(Error::SessionNotEstablished);
|
||||
}
|
||||
} else {
|
||||
unlikely_branch();
|
||||
|
||||
// For KEX packets go ahead and pre-assemble all fragments to simplify the code below.
|
||||
let mut pkt_assembly_buffer = [0u8; NOISE_MAX_HANDSHAKE_PACKET_SIZE];
|
||||
// For Noise setup/KEX packets go ahead and pre-assemble all fragments to simplify the code below.
|
||||
let mut pkt_assembly_buffer = [0u8; MAX_NOISE_HANDSHAKE_SIZE];
|
||||
let pkt_assembled_size = assemble_fragments_into::<Application>(fragments, &mut pkt_assembly_buffer)?;
|
||||
if pkt_assembled_size < MIN_PACKET_SIZE {
|
||||
return Err(Error::InvalidPacket);
|
||||
|
@ -572,7 +557,6 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
}
|
||||
|
||||
let pkt: &AliceNoiseXKInit = byte_array_as_proto_buffer(pkt_assembled)?;
|
||||
|
||||
let alice_noise_e = P384PublicKey::from_bytes(&pkt.alice_noise_e).ok_or(Error::FailedAuthentication)?;
|
||||
let noise_es = app.get_local_s_keypair().agree(&alice_noise_e).ok_or(Error::FailedAuthentication)?;
|
||||
|
||||
|
@ -596,8 +580,8 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
let mut ctr = AesCtr::new(kbkdf::<AES_KEY_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_ENCRYPTION>(noise_es.as_bytes()).as_bytes());
|
||||
ctr.reset_set_iv(&SHA384::hash(&pkt.alice_noise_e)[..AES_CTR_NONCE_SIZE]);
|
||||
ctr.crypt_in_place(&mut pkt_assembled[AliceNoiseXKInit::ENC_START..AliceNoiseXKInit::AUTH_START]);
|
||||
let pkt: &AliceNoiseXKInit = byte_array_as_proto_buffer(pkt_assembled)?;
|
||||
|
||||
let pkt: &AliceNoiseXKInit = byte_array_as_proto_buffer(pkt_assembled)?;
|
||||
let alice_session_id = SessionId::new_from_bytes(&pkt.alice_session_id).ok_or(Error::InvalidPacket)?;
|
||||
|
||||
// Create Bob's ephemeral keys and derive noise_es_ee by agreeing with Alice's. Also create
|
||||
|
@ -639,7 +623,7 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
newest_id = Some(*id);
|
||||
}
|
||||
}
|
||||
sessions.incomplete.remove(newest_id.as_ref().unwrap());
|
||||
let _ = sessions.incomplete.remove(newest_id.as_ref().unwrap());
|
||||
}
|
||||
|
||||
sessions.incomplete.insert(
|
||||
|
@ -672,7 +656,7 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
ctr.reset_set_iv(&bob_noise_e[P384_PUBLIC_KEY_SIZE - AES_CTR_NONCE_SIZE..]);
|
||||
ctr.crypt_in_place(&mut reply_buffer[BobNoiseXKAck::ENC_START..BobNoiseXKAck::AUTH_START]);
|
||||
|
||||
// Add HMAC-SHA384 to reply packet, allowing Alice to derive noise_es_ee and authenticate.
|
||||
// Add HMAC-SHA384 to reply packet.
|
||||
let reply_hmac = hmac_sha384_2(
|
||||
kbkdf::<HMAC_SHA384_SIZE, KBKDF_KEY_USAGE_LABEL_KEX_AUTHENTICATION>(noise_es_ee.as_bytes()).as_bytes(),
|
||||
&create_message_nonce(PACKET_TYPE_BOB_NOISE_XK_ACK, 1),
|
||||
|
@ -763,28 +747,17 @@ impl<Application: ApplicationLayer> Context<Application> {
|
|||
noise_es_ee_se_hk_psk.as_bytes(),
|
||||
);
|
||||
|
||||
// Authenticate entire key exchange.
|
||||
if !secure_eq(
|
||||
&pkt.hmac_es_ee_se_hk_psk,
|
||||
&hmac_sha384_2(
|
||||
noise_es_ee_se_hk_psk_hmac_key.as_bytes(),
|
||||
&message_nonce,
|
||||
&pkt_assembled[HEADER_SIZE..BobNoiseXKAck::AUTH_START + HMAC_SHA384_SIZE],
|
||||
),
|
||||
) {
|
||||
return Err(Error::FailedAuthentication);
|
||||
}
|
||||
|
||||
let reply_counter = session.get_next_outgoing_counter().ok_or(Error::MaxKeyLifetimeExceeded)?;
|
||||
let reply_message_nonce = create_message_nonce(PACKET_TYPE_ALICE_NOISE_XK_ACK, reply_counter.get());
|
||||
|
||||
// Create reply informing Bob of our static identity now that we've verified Bob and set
|
||||
// up forward secrecy. Also return Bob's opaque note.
|
||||
let mut reply_buffer = [0u8; NOISE_MAX_HANDSHAKE_PACKET_SIZE];
|
||||
let mut reply_buffer = [0u8; MAX_NOISE_HANDSHAKE_SIZE];
|
||||
reply_buffer[HEADER_SIZE] = SESSION_PROTOCOL_VERSION;
|
||||
let mut reply_len = HEADER_SIZE + 1;
|
||||
let mut reply_buffer_append = |b: &[u8]| {
|
||||
let reply_len_new = reply_len + b.len();
|
||||
debug_assert!(reply_len_new <= MAX_NOISE_HANDSHAKE_SIZE);
|
||||
reply_buffer[reply_len..reply_len_new].copy_from_slice(b);
|
||||
reply_len = reply_len_new;
|
||||
};
|
||||
|
@ -1040,7 +1013,7 @@ impl<Application: ApplicationLayer> Session<Application> {
|
|||
u64::from(remote_session_id),
|
||||
state.current_key,
|
||||
counter,
|
||||
)?;
|
||||
);
|
||||
c.crypt(&data[..chunk_size], &mut mtu_sized_buffer[HEADER_SIZE..fragment_size]);
|
||||
data = &data[chunk_size..];
|
||||
if fragment_no == last_fragment_no {
|
||||
|
@ -1058,8 +1031,6 @@ impl<Application: ApplicationLayer> Session<Application> {
|
|||
session_key.return_send_cipher(c);
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
unlikely_branch();
|
||||
}
|
||||
}
|
||||
return Err(Error::SessionNotEstablished);
|
||||
|
@ -1101,34 +1072,30 @@ fn set_packet_header(
|
|||
recipient_session_id: u64,
|
||||
key_index: usize,
|
||||
counter: u64,
|
||||
) -> Result<(), Error> {
|
||||
) {
|
||||
debug_assert!(packet.len() >= MIN_PACKET_SIZE);
|
||||
debug_assert!(fragment_count > 0);
|
||||
debug_assert!(fragment_count <= MAX_FRAGMENTS);
|
||||
debug_assert!(fragment_no < MAX_FRAGMENTS);
|
||||
debug_assert!(packet_type <= 0x0f); // packet type is 4 bits
|
||||
if fragment_count <= MAX_FRAGMENTS {
|
||||
// [0-47] recipient session ID
|
||||
// -- start of header check cipher single block encrypt --
|
||||
// [48-48] key index (least significant bit)
|
||||
// [49-51] packet type (0-15)
|
||||
// [52-57] fragment count (1..64 - 1, so 0 means 1 fragment)
|
||||
// [58-63] fragment number (0..63)
|
||||
// [64-127] 64-bit counter
|
||||
memory::store_raw(
|
||||
(u64::from(recipient_session_id)
|
||||
| ((key_index & 1) as u64).wrapping_shl(48)
|
||||
| (packet_type as u64).wrapping_shl(49)
|
||||
| ((fragment_count - 1) as u64).wrapping_shl(52)
|
||||
| (fragment_no as u64).wrapping_shl(58))
|
||||
.to_le(),
|
||||
packet,
|
||||
);
|
||||
memory::store_raw(counter.to_le(), &mut packet[8..]);
|
||||
Ok(())
|
||||
} else {
|
||||
unlikely_branch();
|
||||
Err(Error::DataTooLarge)
|
||||
}
|
||||
|
||||
// [0-47] recipient session ID
|
||||
// -- start of header check cipher single block encrypt --
|
||||
// [48-48] key index (least significant bit)
|
||||
// [49-51] packet type (0-15)
|
||||
// [52-57] fragment count (1..64 - 1, so 0 means 1 fragment)
|
||||
// [58-63] fragment number (0..63)
|
||||
// [64-127] 64-bit counter
|
||||
memory::store_raw(
|
||||
(u64::from(recipient_session_id)
|
||||
| ((key_index & 1) as u64).wrapping_shl(48)
|
||||
| (packet_type as u64).wrapping_shl(49)
|
||||
| ((fragment_count - 1) as u64).wrapping_shl(52)
|
||||
| (fragment_no as u64).wrapping_shl(58))
|
||||
.to_le(),
|
||||
packet,
|
||||
);
|
||||
memory::store_raw(counter.to_le(), &mut packet[8..]);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -1187,7 +1154,7 @@ fn send_with_fragmentation<SendFunction: FnMut(&mut [u8])>(
|
|||
recipient_session_id,
|
||||
key_index,
|
||||
counter,
|
||||
)?;
|
||||
);
|
||||
if let Some(hcc) = header_check_cipher {
|
||||
hcc.encrypt_block_in_place(&mut fragment[6..22]);
|
||||
}
|
||||
|
@ -1232,8 +1199,6 @@ impl SessionKey {
|
|||
.pop()
|
||||
.unwrap_or_else(|| Box::new(AesGcm::new(self.send_key.as_bytes(), true))))
|
||||
} else {
|
||||
unlikely_branch();
|
||||
|
||||
// Not only do we return an error, but we also destroy the key.
|
||||
let mut scp = self.send_cipher_pool.lock().unwrap();
|
||||
scp.clear();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue