tls/src/crypto/mod.rs
2024-08-03 14:59:12 +02:00

92 lines
2.6 KiB
Rust

//! Cryptographic operations.
pub mod aead;
pub mod keys;
pub use seq::{SeqId, SeqIdGen};
use sha2::digest::{typenum::Unsigned, OutputSizeUser};
trait TlsHasher: OutputSizeUser {
const ZEROED: &'static [u8];
fn expand(ikm: &[u8], label: &[u8], okm: &mut [u8]) -> Result<(), hkdf::InvalidLength>;
fn extract(salt: &[u8], ikm: &[u8]) -> Vec<u8>;
}
macro_rules! impl_hkdf_hasher {
() => {
const ZEROED: &'static [u8] =
&[0; <<Self as OutputSizeUser>::OutputSize as Unsigned>::USIZE];
fn expand(ikm: &[u8], label: &[u8], okm: &mut [u8]) -> Result<(), hkdf::InvalidLength> {
hkdf::Hkdf::<Self>::new(None, ikm).expand(&label, okm)
}
fn extract(salt: &[u8], ikm: &[u8]) -> Vec<u8> {
hkdf::Hkdf::<Self>::extract(Some(salt), ikm)
.0
.as_slice()
.to_vec()
}
};
}
impl TlsHasher for sha2::Sha256 {
impl_hkdf_hasher!();
}
impl TlsHasher for sha2::Sha384 {
impl_hkdf_hasher!();
}
pub struct CryptoProvider {
zeroed_of_hash_size: &'static [u8],
hkdf_extract: fn(salt: &[u8], ikm: &[u8]) -> Vec<u8>,
}
impl CryptoProvider {
fn new<H: TlsHasher>() -> Self {
CryptoProvider {
zeroed_of_hash_size: H::ZEROED,
hkdf_extract: H::extract,
}
}
}
mod seq {
use std::cell::Cell;
use super::aead::{Nonce, TlsNonce};
/// The sequence ID generator.
/// There is a separate one maintained for reading and writing.
pub struct SeqIdGen {
next: Cell<u64>,
}
impl SeqIdGen {
pub fn new() -> SeqIdGen {
SeqIdGen { next: Cell::new(0) }
}
pub fn next(&self) -> SeqId {
let next = self.next.get();
self.next.set(next.checked_add(1).unwrap());
SeqId(next)
}
}
// Don't implement `Clone` to ensure every seq id is only used once.
pub struct SeqId(u64);
impl SeqId {
pub fn to_nonce(self) -> TlsNonce {
// <https://datatracker.ietf.org/doc/html/rfc8446#section-5.3>
// 1. The 64-bit record sequence number is encoded in network byte
// order and padded to the left with zeros to iv_length.
let mut nonce = [0; 12];
nonce[4..12].copy_from_slice(&self.0.to_be_bytes());
let nonce = Nonce::from(nonce);
TlsNonce::new(nonce)
}
}
}
#[allow(dead_code)]
pub struct TlsInnerPlaintext {
/// The `TLSPlaintext.fragment`` value
pub content: Vec<u8>,
/// The `TLSPlaintext.type` value
pub content_type: u8,
pub padding_len: u16,
}