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 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"), }
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}