rusty_dtls/
crypto.rs

1use core::net::{IpAddr, SocketAddr};
2use core::panic;
3
4use crate::handshake::CryptoInformation;
5use crate::parsing::HandshakeType;
6use crate::parsing_utility::{ParseBuffer, Parser};
7use crate::DtlsError;
8
9#[cfg(feature = "aes128gcm_sha256")]
10use {aes_gcm::Aes128Gcm, sha2::digest::generic_array::typenum::Unsigned};
11
12use aes_gcm::{
13    aes::{
14        cipher::{BlockEncrypt, BlockSizeUser},
15        Aes128,
16    },
17    AeadCore, AeadInPlace, KeyInit, KeySizeUser,
18};
19use hkdf::hmac::Mac;
20use hkdf::{hmac::SimpleHmac, Hkdf};
21use log::trace;
22use sha2::digest::Update;
23use sha2::{
24    digest::{generic_array::GenericArray, FixedOutput, OutputSizeUser},
25    Digest, Sha256,
26};
27
28pub struct PskTranscriptHashes {
29    #[cfg(feature = "aes128gcm_sha256")]
30    pub(crate) sha256: Sha256,
31}
32
33impl Default for PskTranscriptHashes {
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl PskTranscriptHashes {
40    pub fn new() -> Self {
41        Self {
42            #[cfg(feature = "aes128gcm_sha256")]
43            sha256: <Sha256 as Digest>::new(),
44        }
45    }
46
47    pub fn update(&mut self, data: &[u8]) {
48        print_bytes!("TranscriptHash Update", data);
49        #[cfg(feature = "aes128gcm_sha256")]
50        Digest::update(&mut self.sha256, data);
51    }
52
53    pub fn finalize(&self, partial_client_hello: &[&[u8]]) -> FinalizedPskTranscriptHashes {
54        FinalizedPskTranscriptHashes {
55            #[cfg(feature = "aes128gcm_sha256")]
56            sha256: {
57                let mut hash = self.sha256.clone();
58                partial_client_hello.iter().for_each(|part| {
59                    Digest::update(&mut hash, part);
60                });
61                hash.finalize()
62            },
63        }
64    }
65
66    pub fn client_transition_to_single_hash(self, cipher_suite: CipherSuite) -> PskTranscriptHash {
67        // When the server responds to a
68        // ClientHello with a HelloRetryRequest, the value of ClientHello1 is
69        // replaced with a special synthetic handshake message of handshake type
70        // "message_hash" containing Hash(ClientHello1).
71        match cipher_suite {
72            #[cfg(feature = "aes128gcm_sha256")]
73            CipherSuite::Aes128GcmSha256 => {
74                let client_hello_1 = self.sha256.finalize();
75                let hash = calculate_hello_retry_transcript_hash::<Sha256>(&client_hello_1);
76                PskTranscriptHash::Sha256(hash)
77            }
78            CipherSuite::NullCipherSuite => todo!(),
79        }
80    }
81}
82
83pub struct FinalizedPskTranscriptHashes {
84    #[cfg(feature = "aes128gcm_sha256")]
85    pub(crate) sha256: GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>,
86}
87
88impl FinalizedPskTranscriptHashes {
89    pub fn get(&self, hash_fn: HashFunction) -> &[u8] {
90        match hash_fn {
91            #[cfg(feature = "aes128gcm_sha256")]
92            HashFunction::Sha256 => &self.sha256,
93        }
94    }
95}
96
97pub enum PskTranscriptHash {
98    Sha256(Sha256),
99}
100
101impl PskTranscriptHash {
102    pub fn new(cipher_suite: CipherSuite) -> Self {
103        match cipher_suite {
104            #[cfg(feature = "aes128gcm_sha256")]
105            CipherSuite::Aes128GcmSha256 => Self::Sha256(<Sha256 as Digest>::new()),
106            CipherSuite::NullCipherSuite => panic!(),
107        }
108    }
109    pub fn update(&mut self, data: &[u8]) {
110        print_bytes!("TranscriptHash Update", data);
111        match self {
112            PskTranscriptHash::Sha256(h) => Digest::update(h, data),
113        }
114    }
115
116    pub fn server_digest_cookie_hash(&mut self, cookie: &[u8]) {
117        match self {
118            PskTranscriptHash::Sha256(h) => {
119                digest_client_hello_1_hash(h, &cookie[..<Sha256 as OutputSizeUser>::output_size()])
120            }
121        }
122    }
123
124    pub fn finalize(&self, partial_client_hello: &[&[u8]]) -> FinalizedPskTranscriptHash {
125        match self {
126            PskTranscriptHash::Sha256(h) => {
127                let mut h = h.clone();
128                partial_client_hello.iter().for_each(|part| {
129                    Digest::update(&mut h, part);
130                });
131                FinalizedPskTranscriptHash::Sha256(h.finalize())
132            }
133        }
134    }
135}
136pub enum FinalizedPskTranscriptHash {
137    Sha256(GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>),
138}
139
140impl AsRef<[u8]> for FinalizedPskTranscriptHash {
141    fn as_ref(&self) -> &[u8] {
142        match self {
143            FinalizedPskTranscriptHash::Sha256(h) => h,
144        }
145    }
146}
147
148pub fn encode_cookie(
149    buffer: &mut ParseBuffer<'_>,
150    key: &[u8],
151    hash: &PskTranscriptHash,
152    peer_addr: &SocketAddr,
153) -> Result<(), DtlsError> {
154    let hash = hash.finalize(&[]);
155    let start = buffer.offset();
156    buffer.write_slice_checked(hash.as_ref())?;
157    let mut hmac =
158        <SimpleHmac<Sha256> as KeyInit>::new_from_slice(key).map_err(|_| DtlsError::CryptoError)?;
159    Mac::update(&mut hmac, hash.as_ref());
160    match peer_addr.ip() {
161        IpAddr::V4(i) => Mac::update(&mut hmac, &i.to_bits().to_be_bytes()),
162        IpAddr::V6(i) => Mac::update(&mut hmac, &i.to_bits().to_be_bytes()),
163    }
164    let mac = hmac.finalize_fixed();
165    buffer.write_slice_checked(&mac)?;
166    print_bytes!("Cookie", &buffer.as_ref()[start..]);
167    Ok(())
168}
169
170pub fn verify_cookie(cookie: &[u8], key: &[u8], peer_addr: &SocketAddr) -> Result<bool, DtlsError> {
171    print_bytes!("Cookie", cookie);
172    let mut hmac =
173        <SimpleHmac<Sha256> as KeyInit>::new_from_slice(key).map_err(|_| DtlsError::CryptoError)?;
174    let tag_len = <SimpleHmac<Sha256> as OutputSizeUser>::output_size();
175    Mac::update(&mut hmac, &cookie[..cookie.len() - tag_len]);
176    match peer_addr.ip() {
177        IpAddr::V4(i) => Mac::update(&mut hmac, &i.to_bits().to_be_bytes()),
178        IpAddr::V6(i) => Mac::update(&mut hmac, &i.to_bits().to_be_bytes()),
179    }
180    Ok(hmac.verify_slice(&cookie[cookie.len() - tag_len..]).is_ok())
181}
182
183pub struct Psk<'a> {
184    pub(crate) identity: &'a [u8],
185    pub(crate) psk: &'a [u8],
186    pub(crate) hash_function: HashFunction,
187    pub(crate) key_type: PskType,
188}
189
190impl<'a> Psk<'a> {
191    pub fn new(identity: &'a [u8], psk: &'a [u8], hash_function: HashFunction) -> Self {
192        Self {
193            identity,
194            psk,
195            hash_function,
196            key_type: PskType::External,
197        }
198    }
199}
200
201#[derive(Clone, Copy, PartialEq, Eq, Debug)]
202pub enum HashFunction {
203    #[cfg(feature = "aes128gcm_sha256")]
204    Sha256,
205}
206
207impl HashFunction {
208    pub fn output_size(self) -> usize {
209        match self {
210            #[cfg(feature = "aes128gcm_sha256")]
211            HashFunction::Sha256 => <Sha256 as OutputSizeUser>::output_size(),
212        }
213    }
214}
215
216pub(crate) enum PskType {
217    #[allow(unused)]
218    Resumption {
219        ticket_creation_timestamp_ms: u64,
220    },
221    External,
222}
223
224#[repr(u16)]
225#[derive(Clone, Copy, PartialEq, Eq)]
226pub enum CipherSuite {
227    NullCipherSuite = 0x0,
228    #[cfg(feature = "aes128gcm_sha256")]
229    Aes128GcmSha256 = 0x1301,
230}
231
232impl CipherSuite {
233    pub const fn all() -> &'static [CipherSuite] {
234        &[
235            #[cfg(feature = "aes128gcm_sha256")]
236            CipherSuite::Aes128GcmSha256,
237        ]
238    }
239
240    pub fn hash_function(&self) -> HashFunction {
241        match self {
242            #[cfg(feature = "aes128gcm_sha256")]
243            CipherSuite::Aes128GcmSha256 => HashFunction::Sha256,
244            CipherSuite::NullCipherSuite => panic!(),
245        }
246    }
247}
248
249impl TryFrom<u16> for CipherSuite {
250    type Error = DtlsError;
251    fn try_from(value: u16) -> Result<Self, DtlsError> {
252        match value {
253            0x0 => Ok(Self::NullCipherSuite),
254            #[cfg(feature = "aes128gcm_sha256")]
255            0x1301 => Ok(Self::Aes128GcmSha256),
256            _ => Err(DtlsError::ParseError),
257        }
258    }
259}
260
261pub enum TrafficSecret {
262    #[cfg(feature = "aes128gcm_sha256")]
263    Aes128GcmSha256 {
264        traffic_secret: GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>,
265        key: GenericArray<u8, <Aes128Gcm as KeySizeUser>::KeySize>,
266        iv: GenericArray<u8, <Aes128Gcm as AeadCore>::NonceSize>,
267        sn: GenericArray<u8, <Aes128Gcm as KeySizeUser>::KeySize>,
268    },
269    None,
270}
271
272pub fn mac_length(secret: &TrafficSecret) -> usize {
273    match secret {
274        #[cfg(feature = "aes128gcm_sha256")]
275        TrafficSecret::Aes128GcmSha256 {
276            traffic_secret: _,
277            key: _,
278            iv: _,
279            sn: _,
280        } => <Aes128Gcm as AeadCore>::TagSize::to_usize(),
281        _ => unreachable!("Invalid cipher suite"), // Rust requires this branch for references
282    }
283}
284
285pub fn aead_encrypt_in_place(
286    secret: &TrafficSecret,
287    record_seq_num: &u64,
288    additional_data: &[u8],
289    plaintext: &mut ParseBuffer<'_>,
290) -> Result<(), DtlsError> {
291    match secret {
292        #[cfg(feature = "aes128gcm_sha256")]
293        TrafficSecret::Aes128GcmSha256 {
294            traffic_secret: _,
295            key,
296            iv,
297            sn: _,
298        } => {
299            encrypt_in_place::<Aes128Gcm>(key, iv, record_seq_num, additional_data, plaintext)?;
300        }
301        TrafficSecret::None => panic!(),
302    }
303    Ok(())
304}
305
306fn generate_nonce(record_seq_num: &u64, iv: &[u8], nonce: &mut [u8]) {
307    let nonce_len = nonce.len();
308    nonce[nonce_len - 8..].copy_from_slice(&record_seq_num.to_be_bytes());
309    nonce
310        .iter_mut()
311        .zip(iv.iter())
312        .for_each(|(nonce_byte, iv_byte)| *nonce_byte ^= iv_byte);
313}
314
315pub fn aead_decrypt_in_place(
316    secret: &TrafficSecret,
317    record_seq_num: &u64,
318    additional_data: &[u8],
319    ciphertext: &mut [u8],
320) -> Result<(), DtlsError> {
321    match secret {
322        #[cfg(feature = "aes128gcm_sha256")]
323        TrafficSecret::Aes128GcmSha256 {
324            traffic_secret: _,
325            key,
326            iv,
327            sn: _,
328        } => {
329            decrypt_in_place::<Aes128Gcm>(key, iv, record_seq_num, additional_data, ciphertext)?;
330        }
331        TrafficSecret::None => panic!(),
332    }
333    Ok(())
334}
335
336pub fn xor_sequence_number(
337    secret: &TrafficSecret,
338    record_seq_num: &mut [u8],
339    cipher_text: &[u8; 16],
340) -> Result<(), DtlsError> {
341    debug_assert!(record_seq_num.len() == 1 || record_seq_num.len() == 2);
342    trace!("xor_seq_num: seq_num: {record_seq_num:x?}");
343    print_bytes!("cipher_text", cipher_text);
344    match secret {
345        #[cfg(feature = "aes128gcm_sha256")]
346        TrafficSecret::Aes128GcmSha256 {
347            traffic_secret: _,
348            key: _,
349            iv: _,
350            sn,
351        } => {
352            print_bytes!("sn", sn);
353            xor_seq_num_aes128(sn, record_seq_num, cipher_text);
354        }
355        TrafficSecret::None => panic!(),
356    };
357    Ok(())
358}
359
360fn xor_seq_num_aes128(sn: &[u8], record_seq_num: &mut [u8], cipher_text: &[u8; 16]) {
361    let mut mask = GenericArray::clone_from_slice(cipher_text);
362    Aes128::new_from_slice(sn).unwrap().encrypt_block(&mut mask);
363    let seq_num_len = record_seq_num.len();
364    record_seq_num
365        .iter_mut()
366        .zip(&mask[0..seq_num_len])
367        .for_each(|(record_bytem, mask_byte)| *record_bytem ^= mask_byte);
368}
369
370pub enum CipherDependentCryptoState {
371    #[cfg(feature = "aes128gcm_sha256")]
372    Aes128GcmSha256 {
373        transcript_hash: Sha256,
374        hkdf_state: Hkdf<Sha256, SimpleHmac<Sha256>>,
375    },
376    None,
377}
378
379impl CipherDependentCryptoState {
380    pub fn new(
381        cipher_suite: CipherSuite,
382        psk: Option<&[u8]>,
383        hashes: CryptoInformation,
384    ) -> Result<CipherDependentCryptoState, DtlsError> {
385        let empty_psk = GenericArray::<u8, <Sha256 as OutputSizeUser>::OutputSize>::default();
386        let psk = if let Some(psk) = psk {
387            psk
388        } else {
389            empty_psk.as_slice()
390        };
391        match cipher_suite {
392            #[cfg(feature = "aes128gcm_sha256")]
393            CipherSuite::Aes128GcmSha256 => {
394                let hkdf = Hkdf::<Sha256, SimpleHmac<Sha256>>::new(None, psk);
395                let hash = match hashes {
396                    CryptoInformation::PreServerHello(hashes) => hashes.sha256,
397                    CryptoInformation::PostHelloRetry(PskTranscriptHash::Sha256(h)) => h,
398                    _ => Err(DtlsError::IllegalInnerState)?,
399                };
400                Ok(CipherDependentCryptoState::Aes128GcmSha256 {
401                    transcript_hash: hash,
402                    hkdf_state: hkdf,
403                })
404            }
405            CipherSuite::NullCipherSuite => panic!(),
406        }
407    }
408
409    pub fn update_transcript_hash(&mut self, data: &[u8]) {
410        print_bytes!("TranscriptHash Update", data);
411        match self {
412            #[cfg(feature = "aes128gcm_sha256")]
413            CipherDependentCryptoState::Aes128GcmSha256 {
414                transcript_hash,
415                hkdf_state: _,
416            } => {
417                Digest::update(transcript_hash, data);
418            }
419            CipherDependentCryptoState::None => panic!(),
420        }
421    }
422
423    pub fn extract_new_hkdf_state(&mut self, ikm: Option<&[u8]>) -> Result<(), DtlsError> {
424        match self {
425            #[cfg(feature = "aes128gcm_sha256")]
426            CipherDependentCryptoState::Aes128GcmSha256 {
427                transcript_hash: _,
428                hkdf_state,
429            } => {
430                extract_new_hkdf_state::<Sha256>(hkdf_state, ikm)?;
431            }
432            CipherDependentCryptoState::None => panic!(),
433        }
434        Ok(())
435    }
436
437    pub fn derive_traffic_secret(&self, label: &str) -> Result<TrafficSecret, DtlsError> {
438        match &self {
439            #[cfg(feature = "aes128gcm_sha256")]
440            CipherDependentCryptoState::Aes128GcmSha256 {
441                transcript_hash,
442                hkdf_state,
443            } => {
444                let (traffic_secret, key, iv, sn) =
445                    derive_traffic_secret::<Aes128Gcm, Sha256>(hkdf_state, transcript_hash, label)?;
446                Ok(TrafficSecret::Aes128GcmSha256 {
447                    traffic_secret,
448                    key,
449                    iv,
450                    sn,
451                })
452            }
453            CipherDependentCryptoState::None => panic!(),
454        }
455    }
456
457    pub fn encode_verify_data(
458        &mut self,
459        buffer: &mut ParseBuffer<'_>,
460        secret: &TrafficSecret,
461    ) -> Result<(), DtlsError> {
462        match (self, secret) {
463            #[cfg(feature = "aes128gcm_sha256")]
464            (
465                CipherDependentCryptoState::Aes128GcmSha256 {
466                    transcript_hash,
467                    hkdf_state: _,
468                },
469                TrafficSecret::Aes128GcmSha256 {
470                    traffic_secret,
471                    key: _,
472                    iv: _,
473                    sn: _,
474                },
475            ) => encode_verify_data::<Sha256>(
476                buffer,
477                traffic_secret,
478                &transcript_hash.clone().finalize(),
479            ),
480            (CipherDependentCryptoState::None, _) => panic!(),
481            (_, TrafficSecret::None) => panic!(),
482        }
483    }
484
485    pub fn check_verify_data(
486        &mut self,
487        buffer: &mut ParseBuffer<'_>,
488        secret: &TrafficSecret,
489    ) -> Result<bool, DtlsError> {
490        match (self, secret) {
491            #[cfg(feature = "aes128gcm_sha256")]
492            (
493                CipherDependentCryptoState::Aes128GcmSha256 {
494                    transcript_hash,
495                    hkdf_state: _,
496                },
497                TrafficSecret::Aes128GcmSha256 {
498                    traffic_secret,
499                    key: _,
500                    iv: _,
501                    sn: _,
502                },
503            ) => check_verify_data::<Sha256>(
504                buffer,
505                traffic_secret,
506                &transcript_hash.clone().finalize(),
507            ),
508            (CipherDependentCryptoState::None, _) => panic!(),
509            (_, TrafficSecret::None) => panic!(),
510        }
511    }
512}
513
514trait HkdfExt {
515    fn hkdf_expand(&self, info_components: &[&[u8]], okm: &mut [u8]) -> Result<(), DtlsError>;
516}
517
518impl<H> HkdfExt for Hkdf<H, SimpleHmac<H>>
519where
520    H: Digest + Clone + OutputSizeUser + BlockSizeUser,
521{
522    fn hkdf_expand(&self, info_components: &[&[u8]], okm: &mut [u8]) -> Result<(), DtlsError> {
523        self.expand_multi_info(info_components, okm)
524            .map_err(|_| DtlsError::CryptoError)
525    }
526}
527
528fn hkdf_expand_label(
529    hkdf: &dyn HkdfExt,
530    label: &str,
531    context: &[u8],
532    okm: &mut [u8],
533) -> Result<(), DtlsError> {
534    let okm_len = okm.len() as u16;
535    trace!("Hkdf_expand_label: {:?}", label);
536    let label_len = 6 + label.len() as u8;
537    hkdf.hkdf_expand(
538        &[
539            &okm_len.to_be_bytes(),
540            &label_len.to_be_bytes(),
541            b"dtls13",
542            label.as_bytes(),
543            &(context.len() as u8).to_be_bytes(),
544            context,
545        ],
546        okm,
547    )
548    .map_err(|_| DtlsError::CryptoError)?;
549    print_bytes!("Context", context);
550    print_bytes!("OKM", okm);
551    Ok(())
552}
553
554fn calculate_hello_retry_transcript_hash<H: Digest + Update>(client_hello_1_hash: &[u8]) -> H {
555    let mut hash = <H as Digest>::new();
556    digest_client_hello_1_hash(&mut hash, client_hello_1_hash);
557    hash
558}
559
560fn digest_client_hello_1_hash(hash: &mut dyn Update, client_hello_1_hash: &[u8]) {
561    print_bytes!("Client Hello 1 Hash", client_hello_1_hash);
562    hash.update(&[
563        HandshakeType::MessageHash as u8,
564        0,
565        0,
566        client_hello_1_hash.len() as u8,
567    ]);
568    hash.update(client_hello_1_hash);
569}
570
571fn encode_verify_data<H: Digest + BlockSizeUser + OutputSizeUser + Clone>(
572    buffer: &mut ParseBuffer<'_>,
573    traffic_secret: &[u8],
574    transcript_hash: &[u8],
575) -> Result<(), DtlsError> {
576    let verify_data = calculate_verify_data::<H>(traffic_secret, transcript_hash)?;
577    buffer.write_slice_checked(&verify_data)
578}
579
580fn check_verify_data<H: Digest + BlockSizeUser + OutputSizeUser + Clone>(
581    buffer: &mut ParseBuffer<'_>,
582    traffic_secret: &[u8],
583    transcript_hash: &[u8],
584) -> Result<bool, DtlsError> {
585    let verify_data = calculate_verify_data::<H>(traffic_secret, transcript_hash)?;
586    let hash_len = transcript_hash.len();
587    Ok(buffer.read_slice_checked(hash_len)? == verify_data.as_slice())
588}
589
590fn extract_new_hkdf_state<H: Digest + BlockSizeUser + OutputSizeUser + Clone>(
591    hkdf_state: &mut Hkdf<H, SimpleHmac<H>>,
592    ikm: Option<&[u8]>,
593) -> Result<(), DtlsError> {
594    let mut derived = GenericArray::<u8, <H as OutputSizeUser>::OutputSize>::default();
595    hkdf_expand_label(hkdf_state, "derived", &empty_hash::<H>(), &mut derived)?;
596    let hkdf = if let Some(ikm) = ikm {
597        Hkdf::<H, SimpleHmac<H>>::new(Some(derived.as_slice()), ikm)
598    } else {
599        let ikm = GenericArray::<u8, <H as OutputSizeUser>::OutputSize>::default();
600        Hkdf::<H, SimpleHmac<H>>::new(Some(derived.as_slice()), &ikm)
601    };
602    *hkdf_state = hkdf;
603    Ok(())
604}
605
606pub fn validate_binder(
607    received_binder: &[u8],
608    psk: &Psk,
609    transcript_hash: &[u8],
610) -> Result<bool, DtlsError> {
611    trace!("Validating binder entry");
612    print_bytes!("received_binder", received_binder);
613    print_bytes!("transcript_hash", transcript_hash);
614    let valid = match psk.hash_function {
615        #[cfg(feature = "aes128gcm_sha256")]
616        HashFunction::Sha256 => {
617            received_binder == calculate_binder_value::<Sha256>(psk, transcript_hash)?.as_slice()
618        }
619    };
620    Ok(valid)
621}
622
623pub fn encode_binder_entry(
624    buffer: &mut ParseBuffer<'_>,
625    psk: &Psk,
626    transcript_hash: &[u8],
627) -> Result<(), DtlsError> {
628    trace!("Encode binder entry");
629    print_bytes!("transcript_hash", transcript_hash);
630    let binder: &[u8] = match psk.hash_function {
631        #[cfg(feature = "aes128gcm_sha256")]
632        HashFunction::Sha256 => &calculate_binder_value::<Sha256>(psk, transcript_hash)?,
633    };
634    Parser::new_mut_slice(buffer, binder)?
635        .write_len_u8()
636        .write_slice()
637        .end();
638    Ok(())
639}
640
641fn calculate_binder_value<H: Clone + OutputSizeUser + FixedOutput + Digest + BlockSizeUser>(
642    psk: &Psk,
643    transcript_hash: &[u8],
644) -> Result<GenericArray<u8, <H as OutputSizeUser>::OutputSize>, DtlsError> {
645    let hkdf = Hkdf::<H, SimpleHmac<H>>::new(None, psk.psk);
646    let label = match psk.key_type {
647        PskType::Resumption {
648            ticket_creation_timestamp_ms: _,
649        } => "res binder",
650        PskType::External => "ext binder",
651    };
652    let mut binder_key = GenericArray::<u8, <H as OutputSizeUser>::OutputSize>::default();
653    hkdf_expand_label(&hkdf, label, &empty_hash::<H>(), &mut binder_key)?;
654    calculate_verify_data::<H>(&binder_key, transcript_hash)
655}
656
657fn empty_hash<D: Digest + OutputSizeUser>() -> GenericArray<u8, <D as OutputSizeUser>::OutputSize> {
658    let mut h = <D as Digest>::new();
659    Digest::update(&mut h, []);
660    h.finalize()
661}
662
663pub fn calculate_verify_data<H: Digest + BlockSizeUser + OutputSizeUser + Clone>(
664    base_key: &[u8],
665    data: &[u8],
666) -> Result<GenericArray<u8, H::OutputSize>, DtlsError> {
667    let hkdf = Hkdf::<H, SimpleHmac<H>>::from_prk(base_key).map_err(|_| DtlsError::CryptoError)?;
668    print_bytes!("PRK", base_key);
669    let mut finished_key = GenericArray::<u8, <H as OutputSizeUser>::OutputSize>::default();
670    hkdf_expand_label(&hkdf, "finished", &[], &mut finished_key)?;
671    let mut hmac = <SimpleHmac<H> as KeyInit>::new_from_slice(&finished_key)
672        .map_err(|_| DtlsError::CryptoError)?;
673    Mac::update(&mut hmac, data);
674    Ok(hmac.finalize_fixed())
675}
676
677fn encrypt_in_place<A: KeyInit + AeadInPlace>(
678    key: &[u8],
679    iv: &[u8],
680    record_seq_num: &u64,
681    additional_data: &[u8],
682    plaintext: &mut ParseBuffer<'_>,
683) -> Result<(), DtlsError> {
684    let mut nonce = GenericArray::default();
685    generate_nonce(record_seq_num, iv, nonce.as_mut_slice());
686    A::new_from_slice(key)
687        .unwrap()
688        .encrypt_in_place(&nonce, additional_data, plaintext)
689        .map_err(|_| DtlsError::CryptoError)?;
690    Ok(())
691}
692
693fn decrypt_in_place<A: KeyInit + AeadInPlace>(
694    key: &[u8],
695    iv: &[u8],
696    record_seq_num: &u64,
697    additional_data: &[u8],
698    ciphertext: &mut [u8],
699) -> Result<(), DtlsError> {
700    let mut nonce = GenericArray::default();
701    generate_nonce(record_seq_num, iv, nonce.as_mut_slice());
702    let len = ciphertext.len();
703    let mut ciphertext = ParseBuffer::init_with_offset(ciphertext, len);
704    A::new_from_slice(key)
705        .unwrap()
706        .decrypt_in_place(&nonce, additional_data, &mut ciphertext)
707        .map_err(|_| DtlsError::CryptoError)?;
708    Ok(())
709}
710
711fn derive_traffic_secret<
712    A: KeySizeUser + AeadCore,
713    H: Digest + Clone + OutputSizeUser + BlockSizeUser,
714>(
715    hkdf: &Hkdf<H, SimpleHmac<H>>,
716    hash: &H,
717    label: &str,
718) -> Result<
719    (
720        GenericArray<u8, <H as OutputSizeUser>::OutputSize>,
721        GenericArray<u8, <A as KeySizeUser>::KeySize>,
722        GenericArray<u8, <A as AeadCore>::NonceSize>,
723        GenericArray<u8, <A as KeySizeUser>::KeySize>,
724    ),
725    DtlsError,
726> {
727    let hash = <H as Digest>::finalize(hash.clone());
728    let mut traffic_secret = GenericArray::<u8, <H as OutputSizeUser>::OutputSize>::default();
729    hkdf_expand_label(hkdf, label, &hash, &mut traffic_secret)?;
730
731    let hkdf =
732        Hkdf::<H, SimpleHmac<H>>::from_prk(&traffic_secret).map_err(|_| DtlsError::CryptoError)?;
733    let mut key = GenericArray::default();
734    hkdf_expand_label(&hkdf, "key", &[], &mut key)?;
735    let mut iv = GenericArray::default();
736    hkdf_expand_label(&hkdf, "iv", &[], &mut iv)?;
737    let mut sn = GenericArray::default();
738    hkdf_expand_label(&hkdf, "sn", &[], &mut sn)?;
739    Ok((traffic_secret, key, iv, sn))
740}