1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt::{self, Debug, Formatter};
4
5use aws_lc_rs::aead::{
6 self, Aad, BoundKey, NONCE_LEN, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey,
7};
8use aws_lc_rs::agreement;
9use aws_lc_rs::cipher::{AES_128_KEY_LEN, AES_256_KEY_LEN};
10use aws_lc_rs::digest::{SHA256_OUTPUT_LEN, SHA384_OUTPUT_LEN, SHA512_OUTPUT_LEN};
11use aws_lc_rs::encoding::{AsBigEndian, Curve25519SeedBin, EcPrivateKeyBin};
12use zeroize::Zeroize;
13
14use crate::crypto::aws_lc_rs::hmac::{HMAC_SHA256, HMAC_SHA384, HMAC_SHA512};
15use crate::crypto::aws_lc_rs::unspecified_err;
16use crate::crypto::hpke::{
17 EncapsulatedSecret, Hpke, HpkeOpener, HpkePrivateKey, HpkePublicKey, HpkeSealer, HpkeSuite,
18};
19use crate::crypto::tls13::{HkdfExpander, HkdfPrkExtract, HkdfUsingHmac, expand};
20use crate::msgs::enums::{HpkeAead, HpkeKdf, HpkeKem};
21use crate::msgs::handshake::HpkeSymmetricCipherSuite;
22#[cfg(feature = "std")]
23use crate::sync::Arc;
24use crate::{Error, OtherError};
25
26pub static ALL_SUPPORTED_SUITES: &[&dyn Hpke] = &[
28 DH_KEM_P256_HKDF_SHA256_AES_128,
29 DH_KEM_P256_HKDF_SHA256_AES_256,
30 #[cfg(not(feature = "fips"))]
31 DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305,
32 DH_KEM_P384_HKDF_SHA384_AES_128,
33 DH_KEM_P384_HKDF_SHA384_AES_256,
34 #[cfg(not(feature = "fips"))]
35 DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305,
36 DH_KEM_P521_HKDF_SHA512_AES_128,
37 DH_KEM_P521_HKDF_SHA512_AES_256,
38 #[cfg(not(feature = "fips"))]
39 DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305,
40 #[cfg(not(feature = "fips"))]
41 DH_KEM_X25519_HKDF_SHA256_AES_128,
42 #[cfg(not(feature = "fips"))]
43 DH_KEM_X25519_HKDF_SHA256_AES_256,
44 #[cfg(not(feature = "fips"))]
45 DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305,
46];
47
48pub static DH_KEM_P256_HKDF_SHA256_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA256_OUTPUT_LEN> =
51 &HpkeAwsLcRs {
52 suite: HpkeSuite {
53 kem: HpkeKem::DHKEM_P256_HKDF_SHA256,
54 sym: HpkeSymmetricCipherSuite {
55 kdf_id: HpkeKdf::HKDF_SHA256,
56 aead_id: HpkeAead::AES_128_GCM,
57 },
58 },
59 dh_kem: DH_KEM_P256_HKDF_SHA256,
60 hkdf: RING_HKDF_HMAC_SHA256,
61 aead: &aead::AES_128_GCM,
62 };
63
64pub static DH_KEM_P256_HKDF_SHA256_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA256_OUTPUT_LEN> =
67 &HpkeAwsLcRs {
68 suite: HpkeSuite {
69 kem: HpkeKem::DHKEM_P256_HKDF_SHA256,
70 sym: HpkeSymmetricCipherSuite {
71 kdf_id: HpkeKdf::HKDF_SHA256,
72 aead_id: HpkeAead::AES_256_GCM,
73 },
74 },
75 dh_kem: DH_KEM_P256_HKDF_SHA256,
76 hkdf: RING_HKDF_HMAC_SHA256,
77 aead: &aead::AES_256_GCM,
78 };
79
80pub static DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305: &HpkeAwsLcRs<
83 CHACHA_KEY_LEN,
84 SHA256_OUTPUT_LEN,
85> = &HpkeAwsLcRs {
86 suite: HpkeSuite {
87 kem: HpkeKem::DHKEM_P256_HKDF_SHA256,
88 sym: HpkeSymmetricCipherSuite {
89 kdf_id: HpkeKdf::HKDF_SHA256,
90 aead_id: HpkeAead::CHACHA20_POLY_1305,
91 },
92 },
93 dh_kem: DH_KEM_P256_HKDF_SHA256,
94 hkdf: RING_HKDF_HMAC_SHA256,
95 aead: &aead::CHACHA20_POLY1305,
96};
97
98pub static DH_KEM_P384_HKDF_SHA384_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA384_OUTPUT_LEN> =
101 &HpkeAwsLcRs {
102 suite: HpkeSuite {
103 kem: HpkeKem::DHKEM_P384_HKDF_SHA384,
104 sym: HpkeSymmetricCipherSuite {
105 kdf_id: HpkeKdf::HKDF_SHA384,
106 aead_id: HpkeAead::AES_128_GCM,
107 },
108 },
109 dh_kem: DH_KEM_P384_HKDF_SHA384,
110 hkdf: RING_HKDF_HMAC_SHA384,
111 aead: &aead::AES_128_GCM,
112 };
113
114pub static DH_KEM_P384_HKDF_SHA384_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA384_OUTPUT_LEN> =
117 &HpkeAwsLcRs {
118 suite: HpkeSuite {
119 kem: HpkeKem::DHKEM_P384_HKDF_SHA384,
120 sym: HpkeSymmetricCipherSuite {
121 kdf_id: HpkeKdf::HKDF_SHA384,
122 aead_id: HpkeAead::AES_256_GCM,
123 },
124 },
125 dh_kem: DH_KEM_P384_HKDF_SHA384,
126 hkdf: RING_HKDF_HMAC_SHA384,
127 aead: &aead::AES_256_GCM,
128 };
129
130pub static DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305: &HpkeAwsLcRs<
133 CHACHA_KEY_LEN,
134 SHA384_OUTPUT_LEN,
135> = &HpkeAwsLcRs {
136 suite: HpkeSuite {
137 kem: HpkeKem::DHKEM_P384_HKDF_SHA384,
138 sym: HpkeSymmetricCipherSuite {
139 kdf_id: HpkeKdf::HKDF_SHA384,
140 aead_id: HpkeAead::CHACHA20_POLY_1305,
141 },
142 },
143 dh_kem: DH_KEM_P384_HKDF_SHA384,
144 hkdf: RING_HKDF_HMAC_SHA384,
145 aead: &aead::CHACHA20_POLY1305,
146};
147
148pub static DH_KEM_P521_HKDF_SHA512_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA512_OUTPUT_LEN> =
151 &HpkeAwsLcRs {
152 suite: HpkeSuite {
153 kem: HpkeKem::DHKEM_P521_HKDF_SHA512,
154 sym: HpkeSymmetricCipherSuite {
155 kdf_id: HpkeKdf::HKDF_SHA512,
156 aead_id: HpkeAead::AES_128_GCM,
157 },
158 },
159 dh_kem: DH_KEM_P521_HKDF_SHA512,
160 hkdf: RING_HKDF_HMAC_SHA512,
161 aead: &aead::AES_128_GCM,
162 };
163
164pub static DH_KEM_P521_HKDF_SHA512_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA512_OUTPUT_LEN> =
167 &HpkeAwsLcRs {
168 suite: HpkeSuite {
169 kem: HpkeKem::DHKEM_P521_HKDF_SHA512,
170 sym: HpkeSymmetricCipherSuite {
171 kdf_id: HpkeKdf::HKDF_SHA512,
172 aead_id: HpkeAead::AES_256_GCM,
173 },
174 },
175 dh_kem: DH_KEM_P521_HKDF_SHA512,
176 hkdf: RING_HKDF_HMAC_SHA512,
177 aead: &aead::AES_256_GCM,
178 };
179
180pub static DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305: &HpkeAwsLcRs<
183 CHACHA_KEY_LEN,
184 SHA512_OUTPUT_LEN,
185> = &HpkeAwsLcRs {
186 suite: HpkeSuite {
187 kem: HpkeKem::DHKEM_P521_HKDF_SHA512,
188 sym: HpkeSymmetricCipherSuite {
189 kdf_id: HpkeKdf::HKDF_SHA512,
190 aead_id: HpkeAead::CHACHA20_POLY_1305,
191 },
192 },
193 dh_kem: DH_KEM_P521_HKDF_SHA512,
194 hkdf: RING_HKDF_HMAC_SHA512,
195 aead: &aead::CHACHA20_POLY1305,
196};
197
198pub static DH_KEM_X25519_HKDF_SHA256_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA256_OUTPUT_LEN> =
201 &HpkeAwsLcRs {
202 suite: HpkeSuite {
203 kem: HpkeKem::DHKEM_X25519_HKDF_SHA256,
204 sym: HpkeSymmetricCipherSuite {
205 kdf_id: HpkeKdf::HKDF_SHA256,
206 aead_id: HpkeAead::AES_128_GCM,
207 },
208 },
209 dh_kem: DH_KEM_X25519_HKDF_SHA256,
210 hkdf: RING_HKDF_HMAC_SHA256,
211 aead: &aead::AES_128_GCM,
212 };
213
214pub static DH_KEM_X25519_HKDF_SHA256_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA256_OUTPUT_LEN> =
217 &HpkeAwsLcRs {
218 suite: HpkeSuite {
219 kem: HpkeKem::DHKEM_X25519_HKDF_SHA256,
220 sym: HpkeSymmetricCipherSuite {
221 kdf_id: HpkeKdf::HKDF_SHA256,
222 aead_id: HpkeAead::AES_256_GCM,
223 },
224 },
225 dh_kem: DH_KEM_X25519_HKDF_SHA256,
226 hkdf: RING_HKDF_HMAC_SHA256,
227 aead: &aead::AES_256_GCM,
228 };
229
230pub static DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305: &HpkeAwsLcRs<
233 CHACHA_KEY_LEN,
234 SHA256_OUTPUT_LEN,
235> = &HpkeAwsLcRs {
236 suite: HpkeSuite {
237 kem: HpkeKem::DHKEM_X25519_HKDF_SHA256,
238 sym: HpkeSymmetricCipherSuite {
239 kdf_id: HpkeKdf::HKDF_SHA256,
240 aead_id: HpkeAead::CHACHA20_POLY_1305,
241 },
242 },
243 dh_kem: DH_KEM_X25519_HKDF_SHA256,
244 hkdf: RING_HKDF_HMAC_SHA256,
245 aead: &aead::CHACHA20_POLY1305,
246};
247
248pub struct HpkeAwsLcRs<const KEY_SIZE: usize, const KDF_SIZE: usize> {
250 suite: HpkeSuite,
251 dh_kem: &'static DhKem<KDF_SIZE>,
252 hkdf: &'static dyn HkdfPrkExtract,
253 aead: &'static aead::Algorithm,
254}
255
256impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> {
257 fn key_schedule(
261 &self,
262 shared_secret: KemSharedSecret<KDF_SIZE>,
263 info: &[u8],
264 ) -> Result<KeySchedule<KEY_SIZE>, Error> {
265 let suite_id = LabeledSuiteId::Hpke(self.suite);
269 let psk_id_hash = labeled_extract_for_prk(self.hkdf, suite_id, None, Label::PskIdHash, &[]);
270 let info_hash = labeled_extract_for_prk(self.hkdf, suite_id, None, Label::InfoHash, info);
271 let key_schedule_context = [
272 &[0][..], &psk_id_hash,
274 &info_hash,
275 ]
276 .concat();
277
278 let key = AeadKey(self.key_schedule_labeled_expand::<KEY_SIZE>(
279 &shared_secret,
280 &key_schedule_context,
281 Label::Key,
282 ));
283
284 let base_nonce = self.key_schedule_labeled_expand::<NONCE_LEN>(
285 &shared_secret,
286 &key_schedule_context,
287 Label::BaseNonce,
288 );
289
290 Ok(KeySchedule {
291 aead: self.aead,
292 key,
293 base_nonce,
294 seq_num: 0,
295 })
296 }
297
298 fn key_schedule_labeled_expand<const L: usize>(
299 &self,
300 shared_secret: &KemSharedSecret<KDF_SIZE>,
301 key_schedule_context: &[u8],
302 label: Label,
303 ) -> [u8; L] {
304 let suite_id = LabeledSuiteId::Hpke(self.suite);
305 labeled_expand::<L>(
306 suite_id,
307 labeled_extract_for_expand(
308 self.hkdf,
309 suite_id,
310 Some(&shared_secret.0),
311 Label::Secret,
312 &[],
313 ),
314 label,
315 key_schedule_context,
316 )
317 }
318}
319
320impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Hpke for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> {
321 fn seal(
322 &self,
323 info: &[u8],
324 aad: &[u8],
325 plaintext: &[u8],
326 pub_key: &HpkePublicKey,
327 ) -> Result<(EncapsulatedSecret, Vec<u8>), Error> {
328 let (encap, mut sealer) = self.setup_sealer(info, pub_key)?;
329 Ok((encap, sealer.seal(aad, plaintext)?))
330 }
331
332 fn setup_sealer(
333 &self,
334 info: &[u8],
335 pub_key: &HpkePublicKey,
336 ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error> {
337 let (encap, sealer) = Sealer::new(self, info, pub_key)?;
338 Ok((encap, Box::new(sealer)))
339 }
340
341 fn open(
342 &self,
343 enc: &EncapsulatedSecret,
344 info: &[u8],
345 aad: &[u8],
346 ciphertext: &[u8],
347 secret_key: &HpkePrivateKey,
348 ) -> Result<Vec<u8>, Error> {
349 self.setup_opener(enc, info, secret_key)?
350 .open(aad, ciphertext)
351 }
352
353 fn setup_opener(
354 &self,
355 enc: &EncapsulatedSecret,
356 info: &[u8],
357 secret_key: &HpkePrivateKey,
358 ) -> Result<Box<dyn HpkeOpener + 'static>, Error> {
359 Ok(Box::new(Opener::new(self, enc, info, secret_key)?))
360 }
361
362 fn fips(&self) -> bool {
363 matches!(
364 (self.suite.kem, self.suite.sym.aead_id),
368 (
369 HpkeKem::DHKEM_P256_HKDF_SHA256
371 | HpkeKem::DHKEM_P384_HKDF_SHA384
372 | HpkeKem::DHKEM_P521_HKDF_SHA512,
373 HpkeAead::AES_128_GCM | HpkeAead::AES_256_GCM,
375 )
376 )
377 }
378
379 fn generate_key_pair(&self) -> Result<(HpkePublicKey, HpkePrivateKey), Error> {
380 (self.dh_kem.key_generator)()
381 }
382
383 fn suite(&self) -> HpkeSuite {
384 self.suite
385 }
386}
387
388impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> {
389 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
390 self.suite.fmt(f)
391 }
392}
393
394struct Sealer<const KEY_SIZE: usize, const KDF_SIZE: usize> {
396 key_schedule: KeySchedule<KEY_SIZE>,
397}
398
399impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Sealer<KEY_SIZE, KDF_SIZE> {
400 fn new(
404 suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>,
405 info: &[u8],
406 pub_key: &HpkePublicKey,
407 ) -> Result<(EncapsulatedSecret, Self), Error> {
408 let (shared_secret, enc) = suite.dh_kem.encap(pub_key)?;
414 let key_schedule = suite.key_schedule(shared_secret, info)?;
415 Ok((enc, Self { key_schedule }))
416 }
417
418 #[cfg(test)]
421 fn test_only_new(
422 suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>,
423 info: &[u8],
424 pub_key: &HpkePublicKey,
425 sk_e: &[u8],
426 ) -> Result<(EncapsulatedSecret, Self), Error> {
427 let (shared_secret, enc) = suite
428 .dh_kem
429 .test_only_encap(pub_key, sk_e)?;
430 let key_schedule = suite.key_schedule(shared_secret, info)?;
431 Ok((enc, Self { key_schedule }))
432 }
433}
434
435impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeSealer for Sealer<KEY_SIZE, KDF_SIZE> {
436 fn seal(&mut self, aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, Error> {
437 let key = UnboundKey::new(self.key_schedule.aead, &self.key_schedule.key.0)
443 .map_err(unspecified_err)?;
444 let mut sealing_key = SealingKey::new(key, &mut self.key_schedule);
445
446 let mut in_out_buffer = Vec::from(plaintext);
447 sealing_key
448 .seal_in_place_append_tag(Aad::from(aad), &mut in_out_buffer)
449 .map_err(unspecified_err)?;
450
451 Ok(in_out_buffer)
452 }
453}
454
455impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for Sealer<KEY_SIZE, KDF_SIZE> {
456 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
457 f.debug_struct("Sealer").finish()
458 }
459}
460
461struct Opener<const KEY_SIZE: usize, const KDF_SIZE: usize> {
463 key_schedule: KeySchedule<KEY_SIZE>,
464}
465
466impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Opener<KEY_SIZE, KDF_SIZE> {
467 fn new(
471 suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>,
472 enc: &EncapsulatedSecret,
473 info: &[u8],
474 secret_key: &HpkePrivateKey,
475 ) -> Result<Self, Error> {
476 Ok(Self {
481 key_schedule: suite.key_schedule(suite.dh_kem.decap(enc, secret_key)?, info)?,
482 })
483 }
484}
485
486impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeOpener for Opener<KEY_SIZE, KDF_SIZE> {
487 fn open(&mut self, aad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
488 let key = UnboundKey::new(self.key_schedule.aead, &self.key_schedule.key.0)
496 .map_err(unspecified_err)?;
497 let mut opening_key = OpeningKey::new(key, &mut self.key_schedule);
498
499 let mut in_out_buffer = Vec::from(ciphertext);
500 let plaintext = opening_key
501 .open_in_place(Aad::from(aad), &mut in_out_buffer)
502 .map_err(unspecified_err)?;
503
504 Ok(plaintext.to_vec())
505 }
506}
507
508impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for Opener<KEY_SIZE, KDF_SIZE> {
509 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
510 f.debug_struct("Opener").finish()
511 }
512}
513
514struct DhKem<const KDF_SIZE: usize> {
520 id: HpkeKem,
521 agreement_algorithm: &'static agreement::Algorithm,
522 key_generator:
523 &'static (dyn Fn() -> Result<(HpkePublicKey, HpkePrivateKey), Error> + Send + Sync),
524 hkdf: &'static dyn HkdfPrkExtract,
525}
526
527impl<const KDF_SIZE: usize> DhKem<KDF_SIZE> {
528 fn encap(
532 &self,
533 recipient: &HpkePublicKey,
534 ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> {
535 let sk_e =
539 agreement::PrivateKey::generate(self.agreement_algorithm).map_err(unspecified_err)?;
540 self.encap_impl(recipient, sk_e)
541 }
542
543 #[cfg(test)]
546 fn test_only_encap(
547 &self,
548 recipient: &HpkePublicKey,
549 test_only_ske: &[u8],
550 ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> {
551 let sk_e = agreement::PrivateKey::from_private_key(self.agreement_algorithm, test_only_ske)
553 .map_err(key_rejected_err)?;
554 self.encap_impl(recipient, sk_e)
555 }
556
557 fn encap_impl(
558 &self,
559 recipient: &HpkePublicKey,
560 sk_e: agreement::PrivateKey,
561 ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> {
562 let enc = sk_e
574 .compute_public_key()
575 .map_err(unspecified_err)?;
576 let pk_r = agreement::UnparsedPublicKey::new(self.agreement_algorithm, &recipient.0);
577 let kem_context = [enc.as_ref(), pk_r.bytes()].concat();
578
579 let shared_secret = agreement::agree(&sk_e, &pk_r, aws_lc_rs::error::Unspecified, |dh| {
580 Ok(self.extract_and_expand(dh, &kem_context))
581 })
582 .map_err(unspecified_err)?;
583
584 Ok((
585 KemSharedSecret(shared_secret),
586 EncapsulatedSecret(enc.as_ref().into()),
587 ))
588 }
589
590 fn decap(
594 &self,
595 enc: &EncapsulatedSecret,
596 recipient: &HpkePrivateKey,
597 ) -> Result<KemSharedSecret<KDF_SIZE>, Error> {
598 let pk_e = agreement::UnparsedPublicKey::new(self.agreement_algorithm, &enc.0);
609 let sk_r = agreement::PrivateKey::from_private_key(
610 self.agreement_algorithm,
611 recipient.secret_bytes(),
612 )
613 .map_err(key_rejected_err)?;
614 let pk_rm = sk_r
615 .compute_public_key()
616 .map_err(unspecified_err)?;
617 let kem_context = [&enc.0, pk_rm.as_ref()].concat();
618
619 let shared_secret = agreement::agree(&sk_r, &pk_e, aws_lc_rs::error::Unspecified, |dh| {
620 Ok(self.extract_and_expand(dh, &kem_context))
621 })
622 .map_err(unspecified_err)?;
623
624 Ok(KemSharedSecret(shared_secret))
625 }
626
627 fn extract_and_expand(&self, dh: &[u8], kem_context: &[u8]) -> [u8; KDF_SIZE] {
631 let suite_id = LabeledSuiteId::Kem(self.id);
638 labeled_expand(
639 suite_id,
640 labeled_extract_for_expand(self.hkdf, suite_id, None, Label::EaePrk, dh),
641 Label::SharedSecret,
642 kem_context,
643 )
644 }
645}
646
647static DH_KEM_P256_HKDF_SHA256: &DhKem<SHA256_OUTPUT_LEN> = &DhKem {
648 id: HpkeKem::DHKEM_P256_HKDF_SHA256,
649 agreement_algorithm: &agreement::ECDH_P256,
650 key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P256),
651 hkdf: RING_HKDF_HMAC_SHA256,
652};
653
654static DH_KEM_P384_HKDF_SHA384: &DhKem<SHA384_OUTPUT_LEN> = &DhKem {
655 id: HpkeKem::DHKEM_P384_HKDF_SHA384,
656 agreement_algorithm: &agreement::ECDH_P384,
657 key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P384),
658 hkdf: RING_HKDF_HMAC_SHA384,
659};
660
661static DH_KEM_P521_HKDF_SHA512: &DhKem<SHA512_OUTPUT_LEN> = &DhKem {
662 id: HpkeKem::DHKEM_P521_HKDF_SHA512,
663 agreement_algorithm: &agreement::ECDH_P521,
664 key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P521),
665 hkdf: RING_HKDF_HMAC_SHA512,
666};
667
668static DH_KEM_X25519_HKDF_SHA256: &DhKem<SHA256_OUTPUT_LEN> = &DhKem {
669 id: HpkeKem::DHKEM_X25519_HKDF_SHA256,
670 agreement_algorithm: &agreement::X25519,
671 key_generator: &generate_x25519_key_pair,
672 hkdf: RING_HKDF_HMAC_SHA256,
673};
674
675fn generate_p_curve_key_pair(
682 alg: &'static agreement::Algorithm,
683) -> Result<(HpkePublicKey, HpkePrivateKey), Error> {
684 debug_assert_ne!(alg, &agreement::X25519);
688 let (public_key, private_key) = generate_key_pair(alg)?;
689 let raw_private_key: EcPrivateKeyBin<'_> = private_key
690 .as_be_bytes()
691 .map_err(unspecified_err)?;
692 Ok((
693 public_key,
694 HpkePrivateKey::from(raw_private_key.as_ref().to_vec()),
695 ))
696}
697
698fn generate_x25519_key_pair() -> Result<(HpkePublicKey, HpkePrivateKey), Error> {
705 let (public_key, private_key) = generate_key_pair(&agreement::X25519)?;
706 let raw_private_key: Curve25519SeedBin<'_> = private_key
707 .as_be_bytes()
708 .map_err(unspecified_err)?;
709 Ok((
710 public_key,
711 HpkePrivateKey::from(raw_private_key.as_ref().to_vec()),
712 ))
713}
714
715fn generate_key_pair(
716 alg: &'static agreement::Algorithm,
717) -> Result<(HpkePublicKey, agreement::PrivateKey), Error> {
718 let private_key = agreement::PrivateKey::generate(alg).map_err(unspecified_err)?;
719 let public_key = HpkePublicKey(
720 private_key
721 .compute_public_key()
722 .map_err(unspecified_err)?
723 .as_ref()
724 .to_vec(),
725 );
726 Ok((public_key, private_key))
727}
728
729struct KeySchedule<const KEY_SIZE: usize> {
732 aead: &'static aead::Algorithm,
733 key: AeadKey<KEY_SIZE>,
734 base_nonce: [u8; NONCE_LEN],
735 seq_num: u32,
736}
737
738impl<const KEY_SIZE: usize> KeySchedule<KEY_SIZE> {
739 fn compute_nonce(&self) -> [u8; NONCE_LEN] {
743 let mut nonce = [0; NONCE_LEN];
751 let seq_bytes = self.seq_num.to_be_bytes();
752 nonce[NONCE_LEN - seq_bytes.len()..].copy_from_slice(&seq_bytes);
753
754 for (n, &b) in nonce.iter_mut().zip(&self.base_nonce) {
755 *n ^= b;
756 }
757
758 nonce
759 }
760
761 fn increment_seq_num(&mut self) -> Result<(), aws_lc_rs::error::Unspecified> {
765 let max_seq_num = (1u128 << (NONCE_LEN * 8)) - 1;
773
774 if u128::from(self.seq_num) >= max_seq_num {
777 return Err(aws_lc_rs::error::Unspecified);
778 }
779
780 self.seq_num += 1;
781 Ok(())
782 }
783}
784
785impl<const KEY_SIZE: usize> NonceSequence for &mut KeySchedule<KEY_SIZE> {
786 fn advance(&mut self) -> Result<Nonce, aws_lc_rs::error::Unspecified> {
787 let nonce = self.compute_nonce();
788 self.increment_seq_num()?;
789 Nonce::try_assume_unique_for_key(&nonce)
790 }
791}
792
793fn labeled_extract_for_expand(
797 hkdf: &'static dyn HkdfPrkExtract,
798 suite_id: LabeledSuiteId,
799 salt: Option<&[u8]>,
800 label: Label,
801 ikm: &[u8],
802) -> Box<dyn HkdfExpander> {
803 let labeled_ikm = [&b"HPKE-v1"[..], &suite_id.encoded(), label.as_ref(), ikm].concat();
808 hkdf.extract_from_secret(salt, &labeled_ikm)
809}
810
811fn labeled_extract_for_prk(
815 hkdf: &'static dyn HkdfPrkExtract,
816 suite_id: LabeledSuiteId,
817 salt: Option<&[u8]>,
818 label: Label,
819 ikm: &[u8],
820) -> Vec<u8> {
821 let labeled_ikm = [&b"HPKE-v1"[..], &suite_id.encoded(), label.as_ref(), ikm].concat();
826 hkdf.extract_prk_from_secret(salt, &labeled_ikm)
827}
828
829fn labeled_expand<const L: usize>(
833 suite_id: LabeledSuiteId,
834 expander: Box<dyn HkdfExpander>,
835 label: Label,
836 kem_context: &[u8],
837) -> [u8; L] {
838 let output_len = u16::to_be_bytes(L as u16);
844 let info = &[
845 &output_len[..],
846 b"HPKE-v1",
847 &suite_id.encoded(),
848 label.as_ref(),
849 kem_context,
850 ];
851
852 expand(&*expander, info)
853}
854
855#[derive(Debug)]
857enum Label {
858 PskIdHash,
859 InfoHash,
860 Secret,
861 Key,
862 BaseNonce,
863 EaePrk,
864 SharedSecret,
865}
866
867impl AsRef<[u8]> for Label {
868 fn as_ref(&self) -> &[u8] {
869 match self {
870 Self::PskIdHash => b"psk_id_hash",
871 Self::InfoHash => b"info_hash",
872 Self::Secret => b"secret",
873 Self::Key => b"key",
874 Self::BaseNonce => b"base_nonce",
875 Self::EaePrk => b"eae_prk",
876 Self::SharedSecret => b"shared_secret",
877 }
878 }
879}
880
881#[derive(Debug, Copy, Clone)]
884enum LabeledSuiteId {
885 Hpke(HpkeSuite),
886 Kem(HpkeKem),
887}
888
889impl LabeledSuiteId {
890 fn encoded(&self) -> Vec<u8> {
897 match self {
898 Self::Hpke(suite) => [
899 &b"HPKE"[..],
900 &u16::from(suite.kem).to_be_bytes(),
901 &u16::from(suite.sym.kdf_id).to_be_bytes(),
902 &u16::from(suite.sym.aead_id).to_be_bytes(),
903 ]
904 .concat(),
905 Self::Kem(kem) => [&b"KEM"[..], &u16::from(*kem).to_be_bytes()].concat(),
906 }
907 }
908}
909
910struct AeadKey<const KEY_LEN: usize>([u8; KEY_LEN]);
912
913impl<const KEY_LEN: usize> Drop for AeadKey<KEY_LEN> {
914 fn drop(&mut self) {
915 self.0.zeroize()
916 }
917}
918
919struct KemSharedSecret<const KDF_LEN: usize>([u8; KDF_LEN]);
921
922impl<const KDF_LEN: usize> Drop for KemSharedSecret<KDF_LEN> {
923 fn drop(&mut self) {
924 self.0.zeroize();
925 }
926}
927
928fn key_rejected_err(_e: aws_lc_rs::error::KeyRejected) -> Error {
929 #[cfg(feature = "std")]
930 {
931 Error::Other(OtherError(Arc::new(_e)))
932 }
933 #[cfg(not(feature = "std"))]
934 {
935 Error::Other(OtherError())
936 }
937}
938
939const CHACHA_KEY_LEN: usize = 32;
942
943static RING_HKDF_HMAC_SHA256: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA256);
944static RING_HKDF_HMAC_SHA384: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA384);
945static RING_HKDF_HMAC_SHA512: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA512);
946
947#[cfg(test)]
948mod tests {
949 use alloc::{format, vec};
950
951 use super::*;
952
953 #[test]
954 fn smoke_test() {
955 for suite in ALL_SUPPORTED_SUITES {
956 _ = format!("{suite:?}"); let (pk, sk) = suite.generate_key_pair().unwrap();
960
961 let info = &[
963 0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x47, 0x72, 0x65, 0x63, 0x69,
964 0x61, 0x6e, 0x20, 0x55, 0x72, 0x6e,
965 ][..];
966
967 let (enc, mut sealer) = suite.setup_sealer(info, &pk).unwrap();
969
970 _ = format!("{sealer:?}"); let bad_setup_res = suite.setup_sealer(info, &HpkePublicKey(vec![]));
974 assert!(matches!(bad_setup_res.unwrap_err(), Error::Other(_)));
975
976 let aad = &[0xC0, 0xFF, 0xEE];
978 let pt = &[0xF0, 0x0D];
979 let ct = sealer.seal(aad, pt).unwrap();
980
981 let mut opener = suite
983 .setup_opener(&enc, info, &sk)
984 .unwrap();
985 _ = format!("{opener:?}"); let bad_key_res = suite.setup_opener(&enc, info, &HpkePrivateKey::from(vec![]));
989 assert!(matches!(bad_key_res.unwrap_err(), Error::Other(_)));
990
991 let pt_prime = opener.open(aad, &ct).unwrap();
993 assert_eq!(pt_prime, pt);
994
995 let open_res = opener.open(&[0x0], &ct);
997 assert!(matches!(open_res.unwrap_err(), Error::Other(_)));
998
999 let mut sk_rm_prime = sk.secret_bytes().to_vec();
1001 sk_rm_prime[10] ^= 0xFF; let mut opener_two = suite
1003 .setup_opener(&enc, info, &HpkePrivateKey::from(sk_rm_prime))
1004 .unwrap();
1005 let open_res = opener_two.open(aad, &ct);
1006 assert!(matches!(open_res.unwrap_err(), Error::Other(_)));
1007 }
1008 }
1009
1010 #[cfg(not(feature = "fips"))] #[test]
1012 fn test_fips() {
1013 let testcases: &[(&dyn Hpke, bool)] = &[
1014 (DH_KEM_P256_HKDF_SHA256_AES_128, true),
1016 (DH_KEM_P256_HKDF_SHA256_AES_256, true),
1017 (DH_KEM_P384_HKDF_SHA384_AES_128, true),
1018 (DH_KEM_P384_HKDF_SHA384_AES_256, true),
1019 (DH_KEM_P521_HKDF_SHA512_AES_128, true),
1020 (DH_KEM_P521_HKDF_SHA512_AES_256, true),
1021 (DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305, false),
1023 (DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305, false),
1024 (DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305, false),
1025 (DH_KEM_X25519_HKDF_SHA256_AES_128, false),
1027 (DH_KEM_X25519_HKDF_SHA256_AES_256, false),
1028 (DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305, false),
1029 ];
1030 for (suite, expected) in testcases {
1031 assert_eq!(suite.fips(), *expected);
1032 }
1033 }
1034}
1035
1036#[cfg(test)]
1037mod rfc_tests {
1038 use alloc::string::String;
1039 use std::fs::File;
1040 use std::println;
1041
1042 use serde::Deserialize;
1043
1044 use super::*;
1045
1046 #[test]
1050 fn check_test_vectors() {
1051 for (idx, vec) in test_vectors().into_iter().enumerate() {
1052 let Some(hpke) = vec.applicable() else {
1053 println!("skipping inapplicable vector {idx}");
1054 continue;
1055 };
1056
1057 println!("testing vector {idx}");
1058 let pk_r = HpkePublicKey(hex::decode(vec.pk_rm).unwrap());
1059 let sk_r = HpkePrivateKey::from(hex::decode(vec.sk_rm).unwrap());
1060 let sk_em = hex::decode(vec.sk_em).unwrap();
1061 let info = hex::decode(vec.info).unwrap();
1062 let expected_enc = hex::decode(vec.enc).unwrap();
1063
1064 let (enc, mut sealer) = hpke
1065 .setup_test_sealer(&info, &pk_r, &sk_em)
1066 .unwrap();
1067 assert_eq!(enc.0, expected_enc);
1068
1069 let mut opener = hpke
1070 .setup_opener(&enc, &info, &sk_r)
1071 .unwrap();
1072
1073 for test_encryption in vec.encryptions {
1074 let aad = hex::decode(test_encryption.aad).unwrap();
1075 let pt = hex::decode(test_encryption.pt).unwrap();
1076 let expected_ct = hex::decode(test_encryption.ct).unwrap();
1077
1078 let ciphertext = sealer.seal(&aad, &pt).unwrap();
1079 assert_eq!(ciphertext, expected_ct);
1080
1081 let plaintext = opener.open(&aad, &ciphertext).unwrap();
1082 assert_eq!(plaintext, pt);
1083 }
1084 }
1085 }
1086
1087 trait TestHpke: Hpke {
1088 fn setup_test_sealer(
1089 &self,
1090 info: &[u8],
1091 pub_key: &HpkePublicKey,
1092 sk_em: &[u8],
1093 ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error>;
1094 }
1095
1096 impl<const KEY_SIZE: usize, const KDF_SIZE: usize> TestHpke for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> {
1097 fn setup_test_sealer(
1098 &self,
1099 info: &[u8],
1100 pub_key: &HpkePublicKey,
1101 sk_em: &[u8],
1102 ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error> {
1103 let (encap, sealer) = Sealer::test_only_new(self, info, pub_key, sk_em)?;
1104 Ok((encap, Box::new(sealer)))
1105 }
1106 }
1107
1108 static TEST_SUITES: &[&dyn TestHpke] = &[
1109 DH_KEM_P256_HKDF_SHA256_AES_128,
1110 DH_KEM_P256_HKDF_SHA256_AES_256,
1111 #[cfg(not(feature = "fips"))]
1112 DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305,
1113 DH_KEM_P384_HKDF_SHA384_AES_128,
1114 DH_KEM_P384_HKDF_SHA384_AES_256,
1115 #[cfg(not(feature = "fips"))]
1116 DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305,
1117 DH_KEM_P521_HKDF_SHA512_AES_128,
1118 DH_KEM_P521_HKDF_SHA512_AES_256,
1119 #[cfg(not(feature = "fips"))]
1120 DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305,
1121 #[cfg(not(feature = "fips"))]
1122 DH_KEM_X25519_HKDF_SHA256_AES_128,
1123 #[cfg(not(feature = "fips"))]
1124 DH_KEM_X25519_HKDF_SHA256_AES_256,
1125 #[cfg(not(feature = "fips"))]
1126 DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305,
1127 ];
1128
1129 #[derive(Deserialize, Debug)]
1130 struct TestVector {
1131 mode: u8,
1132 kem_id: u16,
1133 kdf_id: u16,
1134 aead_id: u16,
1135 info: String,
1136 #[serde(rename(deserialize = "pkRm"))]
1137 pk_rm: String,
1138 #[serde(rename(deserialize = "skRm"))]
1139 sk_rm: String,
1140 #[serde(rename(deserialize = "skEm"))]
1141 sk_em: String,
1142 enc: String,
1143 encryptions: Vec<TestEncryption>,
1144 }
1145
1146 #[derive(Deserialize, Debug)]
1147 struct TestEncryption {
1148 aad: String,
1149 pt: String,
1150 ct: String,
1151 }
1152
1153 impl TestVector {
1154 fn suite(&self) -> HpkeSuite {
1155 HpkeSuite {
1156 kem: HpkeKem::from(self.kem_id),
1157 sym: HpkeSymmetricCipherSuite {
1158 kdf_id: HpkeKdf::from(self.kdf_id),
1159 aead_id: HpkeAead::from(self.aead_id),
1160 },
1161 }
1162 }
1163
1164 fn applicable(&self) -> Option<&'static dyn TestHpke> {
1165 if self.mode != 0 {
1167 return None;
1168 }
1169
1170 Self::lookup_suite(self.suite(), TEST_SUITES)
1171 }
1172
1173 fn lookup_suite(
1174 suite: HpkeSuite,
1175 supported: &[&'static dyn TestHpke],
1176 ) -> Option<&'static dyn TestHpke> {
1177 supported
1178 .iter()
1179 .find(|s| s.suite() == suite)
1180 .copied()
1181 }
1182 }
1183
1184 fn test_vectors() -> Vec<TestVector> {
1185 serde_json::from_reader(
1186 &mut File::open("../rustls-provider-test/tests/rfc-9180-test-vectors.json")
1187 .expect("failed to open test vectors data file"),
1188 )
1189 .expect("failed to deserialize test vectors")
1190 }
1191}