1use core::{borrow::Borrow, fmt, result::Result};
6
7use aes_gcm::{
8 aead::{AeadInPlace, KeyInit, KeySizeUser},
9 A_MAX, C_MAX, P_MAX,
10};
11use crypto_common::BlockSizeUser;
12use ecdsa::{
13 der,
14 signature::{Signer as Signer_, Verifier},
15};
16use elliptic_curve::{
17 ecdh,
18 scalar::NonZeroScalar,
19 sec1::{EncodedPoint, FromEncodedPoint, ToEncodedPoint},
20 CurveArithmetic, FieldBytesSize,
21};
22use rand_core::{impls, CryptoRng, RngCore};
23use sha2::digest::OutputSizeUser;
24use subtle::{Choice, ConstantTimeEq};
25use typenum::{Unsigned, U12, U16};
26
27use crate::{
28 aead::{
29 check_open_in_place_params, check_seal_in_place_params, Aead, AeadId, AeadKey, IndCca2,
30 Lifetime, OpenError, SealError,
31 },
32 csprng::Csprng,
33 ec::{Curve, Secp256r1, Secp384r1},
34 hash::{Block, Digest, Hash, HashId},
35 hex,
36 hkdf::hkdf_impl,
37 hmac::hmac_impl,
38 import::{try_from_slice, ExportError, Import, ImportError},
39 kem::{dhkem_impl, DecapKey, Ecdh, EcdhError, EncapKey},
40 keys::{PublicKey, SecretKey, SecretKeyBytes},
41 signer::{Signature, Signer, SignerError, SignerId, SigningKey, VerifyingKey},
42 zeroize::ZeroizeOnDrop,
43};
44
45#[cfg_attr(feature = "clone-aead", derive(Clone))]
47pub struct Aes256Gcm(aes_gcm::Aes256Gcm);
48
49impl Aead for Aes256Gcm {
50 const ID: AeadId = AeadId::Aes256Gcm;
51
52 const LIFETIME: Lifetime = Lifetime::Messages(u32::MAX as u64);
54
55 type KeySize = <aes_gcm::Aes256Gcm as KeySizeUser>::KeySize;
56 type NonceSize = U12;
57 type Overhead = U16; const MAX_PLAINTEXT_SIZE: u64 = P_MAX;
60 const MAX_ADDITIONAL_DATA_SIZE: u64 = A_MAX;
61 const MAX_CIPHERTEXT_SIZE: u64 = C_MAX;
62
63 type Key = AeadKey<Self::KeySize>;
64
65 #[inline]
66 fn new(key: &Self::Key) -> Self {
67 let key: &[u8; 32] = key.as_array();
68 Self(aes_gcm::Aes256Gcm::new(key.into()))
69 }
70
71 fn seal_in_place(
72 &self,
73 nonce: &[u8],
74 data: &mut [u8],
75 tag: &mut [u8],
76 additional_data: &[u8],
77 ) -> Result<(), SealError> {
78 check_seal_in_place_params::<Self>(nonce, data, tag, additional_data)?;
79
80 let got_tag = self
81 .0
82 .encrypt_in_place_detached(
83 #[allow(clippy::unnecessary_fallible_conversions)]
85 nonce
86 .try_into()
87 .map_err(|_| SealError::InvalidNonceSize(InvalidNonceSize))?,
88 additional_data,
89 data,
90 )
91 .map_err(|_| SealError::Encryption)?;
92 tag.copy_from_slice(&got_tag[..]);
93
94 Ok(())
95 }
96
97 fn open_in_place(
98 &self,
99 nonce: &[u8],
100 data: &mut [u8],
101 tag: &[u8],
102 additional_data: &[u8],
103 ) -> Result<(), OpenError> {
104 check_open_in_place_params::<Self>(nonce, data, tag, additional_data)?;
105
106 self.0
107 .decrypt_in_place_detached(
108 #[allow(clippy::unnecessary_fallible_conversions)]
110 nonce
111 .try_into()
112 .map_err(|_| OpenError::InvalidNonceSize(InvalidNonceSize))?,
113 additional_data,
114 data,
115 #[allow(clippy::unnecessary_fallible_conversions)]
117 tag.try_into().map_err(|_| OpenError::InvalidOverheadSize)?,
118 )
119 .map_err(|_| OpenError::Authentication)
120 }
121}
122
123impl IndCca2 for Aes256Gcm {}
124
125#[cfg(feature = "committing-aead")]
126mod committing {
127 use aes::cipher::{BlockEncrypt, BlockSizeUser, KeyInit};
128 use generic_array::GenericArray;
129 use typenum::{Unsigned, U32};
130
131 use super::{Aes256Gcm, Sha256};
132 use crate::aead::{AeadKey, BlockCipher};
133
134 #[doc(hidden)]
136 pub struct Aes256(aes::Aes256);
137
138 impl BlockCipher for Aes256 {
139 type BlockSize = <aes::Aes256 as BlockSizeUser>::BlockSize;
140 const BLOCK_SIZE: usize = Self::BlockSize::USIZE;
141 type Key = AeadKey<U32>;
142
143 fn new(key: &Self::Key) -> Self {
144 let key: &[u8; 32] = key.as_array();
145 let cipher = <aes::Aes256 as KeyInit>::new(key.into());
146 Self(cipher)
147 }
148
149 fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>) {
150 let block: &mut [u8; 16] = block.as_mut();
152 self.0.encrypt_block(block.into())
153 }
154 }
155
156 crate::aead::utc_aead!(Cmt1Aes256Gcm, Aes256Gcm, Aes256, "CMT-1 AES-256-GCM.");
157 crate::aead::hte_aead!(Cmt4Aes256Gcm, Cmt1Aes256Gcm, Sha256, "CMT-4 AES-256-GCM.");
158}
159#[cfg(feature = "committing-aead")]
160#[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
161pub use committing::*;
162
163use crate::aead::InvalidNonceSize;
164
165macro_rules! curve_impl {
166 ($name:ident, $doc:expr, $inner:ty, $point:ident, $curve:ident) => {
167 #[doc = concat!($doc, ".")]
168 pub use $inner as $name;
169
170 impl Curve for $inner {
171 type ScalarSize = <$curve as Curve>::ScalarSize;
172 type CompressedSize = <$curve as Curve>::CompressedSize;
173 type UncompressedSize = <$curve as Curve>::UncompressedSize;
174 }
175
176 #[doc = concat!("An encoded ", $doc, "point.")]
177 #[derive(Copy, Clone)]
178 pub struct $point(EncodedPoint<$inner>);
179
180 impl Borrow<[u8]> for $point {
181 fn borrow(&self) -> &[u8] {
182 self.0.as_bytes()
183 }
184 }
185
186 impl<'a> Import<&'a [u8]> for $point {
187 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
188 let point = EncodedPoint::<$inner>::from_bytes(data)
189 .map_err(|_| ImportError::InvalidSyntax)?;
190 Ok(Self(point))
191 }
192 }
193 };
194}
195curve_impl!(P256, "NIST-P256", p256::NistP256, P256Point, Secp256r1);
196curve_impl!(P384, "NIST-P256", p384::NistP384, P384Point, Secp384r1);
197
198#[derive(ZeroizeOnDrop)]
200pub struct SharedSecret<C>(ecdh::SharedSecret<C>)
201where
202 C: CurveArithmetic;
203
204impl<C> Borrow<[u8]> for SharedSecret<C>
205where
206 C: CurveArithmetic,
207{
208 fn borrow(&self) -> &[u8] {
209 self.0.raw_secret_bytes().as_slice()
210 }
211}
212
213macro_rules! ecdh_impl {
214 (
215 $curve:ident,
216 $doc:expr,
217 $sk:ident,
218 $pk:ident,
219 $point:ident $(,)?
220 ) => {
221 #[doc = concat!($doc, " ECDH private key.")]
222 #[derive(Clone, ZeroizeOnDrop)]
223 pub struct $sk(NonZeroScalar<$curve>);
224
225 impl DecapKey for $sk {
226 type EncapKey = $pk;
227
228 #[inline]
229 fn public(&self) -> Result<$pk, $crate::signer::PkError> {
230 Ok($pk(elliptic_curve::PublicKey::from_secret_scalar(&self.0)))
231 }
232 }
233
234 impl SecretKey for $sk {
235 type Size = FieldBytesSize<$curve>;
236
237 #[inline]
238 fn new<R: Csprng>(rng: &mut R) -> Self {
239 let sk = NonZeroScalar::random(&mut RngWrapper(rng));
240 Self(sk)
241 }
242
243 #[inline]
244 fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError> {
245 let secret: [u8; FieldBytesSize::<$curve>::USIZE] = self.0.to_bytes().into();
247 Ok(SecretKeyBytes::new(secret.into()))
248 }
249 }
250
251 #[cfg(test)]
252 impl fmt::Debug for $sk {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 hex::ct_write(f, self.0.to_bytes().as_slice())
255 }
256 }
257
258 impl ConstantTimeEq for $sk {
259 fn ct_eq(&self, other: &Self) -> Choice {
260 self.0.ct_eq(&other.0)
261 }
262 }
263
264 impl<'a> Import<&'a [u8]> for $sk {
265 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
266 let bytes = *try_from_slice(data)?;
267 let sk = Option::from(NonZeroScalar::from_repr(bytes.into()))
268 .ok_or(ImportError::InvalidSyntax)?;
269 Ok(Self(sk))
270 }
271 }
272
273 #[doc = concat!($doc, " ECDH public key.")]
274 #[derive(Clone, Eq, PartialEq)]
275 pub struct $pk(elliptic_curve::PublicKey<$curve>);
276
277 impl EncapKey for $pk {}
278
279 impl PublicKey for $pk {
280 type Data = $point;
281
282 fn export(&self) -> Self::Data {
283 $point(self.0.to_encoded_point(false))
284 }
285 }
286
287 impl fmt::Debug for $pk {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 hex::ct_write(f, self.export().borrow())
290 }
291 }
292
293 impl<'a> Import<&'a [u8]> for $pk {
294 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
295 let point = EncodedPoint::<$curve>::from_bytes(data)
296 .map_err(|_| ImportError::InvalidSyntax)?;
297 let pk = Option::from(elliptic_curve::PublicKey::from_encoded_point(&point))
298 .ok_or(ImportError::InvalidSyntax)?;
299 Ok(Self(pk))
300 }
301 }
302
303 impl Ecdh for $curve {
304 const SCALAR_SIZE: usize = <$curve as Curve>::ScalarSize::USIZE;
305
306 type PrivateKey = $sk;
307 type PublicKey = $pk;
308 type SharedSecret = SharedSecret<$curve>;
309
310 fn ecdh(
311 local: &Self::PrivateKey,
312 remote: &Self::PublicKey,
313 ) -> Result<Self::SharedSecret, EcdhError> {
314 let secret = ecdh::diffie_hellman(&local.0, remote.0.as_affine());
315 Ok(SharedSecret(secret))
316 }
317 }
318 };
319}
320ecdh_impl!(P256, "P-256", P256PrivateKey, P256PublicKey, P256Point);
321ecdh_impl!(P384, "P-384", P384PrivateKey, P384PublicKey, P384Point);
322dhkem_impl!(
325 DhKemP256HkdfSha256,
326 "DHKEM(P256, HKDF-SHA256)",
327 P256,
328 HkdfSha256,
329 P256PrivateKey,
330 P256PublicKey,
331);
332
333#[derive(Clone)]
335pub struct SigBytes<T>(T);
336
337impl<T> Borrow<[u8]> for SigBytes<T>
338where
339 T: AsRef<[u8]>,
340{
341 fn borrow(&self) -> &[u8] {
342 self.0.as_ref()
343 }
344}
345
346macro_rules! ecdsa_impl {
347 (
348 $curve:ident,
349 $doc:expr,
350 $sk:ident,
351 $pk:ident,
352 $sig:ident,
353 $point:ident $(,)?
354 ) => {
355 #[doc = concat!($doc, " ECDSA private key.")]
356 #[derive(Clone, ZeroizeOnDrop)]
357 pub struct $sk(ecdsa::SigningKey<$curve>);
358
359 impl SigningKey<$curve> for $sk {
360 fn sign(&self, msg: &[u8]) -> Result<$sig, SignerError> {
361 let sig = self.0.sign(msg);
362 Ok($sig(sig))
363 }
364
365 #[inline]
366 fn public(&self) -> Result<$pk, $crate::signer::PkError> {
367 Ok($pk(ecdsa::VerifyingKey::from(&self.0)))
368 }
369 }
370
371 impl SecretKey for $sk {
372 type Size = FieldBytesSize<$curve>;
373
374 #[inline]
375 fn new<R: Csprng>(rng: &mut R) -> Self {
376 let sk = ecdsa::SigningKey::random(&mut RngWrapper(rng));
377 Self(sk)
378 }
379
380 #[inline]
381 fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError> {
382 let secret: [u8; FieldBytesSize::<$curve>::USIZE] = self.0.to_bytes().into();
384 Ok(SecretKeyBytes::new(secret.into()))
385 }
386 }
387
388 #[cfg(test)]
389 impl fmt::Debug for $sk {
390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391 hex::ct_write(f, self.0.to_bytes().as_slice())
392 }
393 }
394
395 impl ConstantTimeEq for $sk {
396 fn ct_eq(&self, other: &Self) -> Choice {
397 self.0.ct_eq(&other.0)
398 }
399 }
400
401 impl<'a> Import<&'a [u8]> for $sk {
402 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
403 let sk =
404 ecdsa::SigningKey::from_slice(data).map_err(|_| ImportError::InvalidSyntax)?;
405 Ok(Self(sk))
406 }
407 }
408
409 #[doc = concat!($doc, " ECDSA public key.")]
410 #[derive(Clone, Eq, PartialEq)]
411 pub struct $pk(ecdsa::VerifyingKey<$curve>);
412
413 impl VerifyingKey<$curve> for $pk {
414 fn verify(&self, msg: &[u8], sig: &$sig) -> Result<(), SignerError> {
415 self.0
416 .verify(msg, &sig.0)
417 .map_err(|_| SignerError::Verification)
418 }
419 }
420
421 impl PublicKey for $pk {
422 type Data = $point;
423
424 fn export(&self) -> Self::Data {
425 $point(self.0.to_encoded_point(false))
426 }
427 }
428
429 impl fmt::Debug for $pk {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 hex::ct_write(f, self.export().borrow())
432 }
433 }
434
435 impl<'a> Import<&'a [u8]> for $pk {
436 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
437 let point = EncodedPoint::<$curve>::from_bytes(data)
438 .map_err(|_| ImportError::InvalidSyntax)?;
439 let pk = ecdsa::VerifyingKey::from_encoded_point(&point)
440 .map_err(|_| ImportError::InvalidSyntax)?;
441 Ok(Self(pk))
442 }
443 }
444
445 #[doc = concat!($doc, " ECDSA signature.")]
446 #[derive(Clone, Debug)]
447 pub struct $sig(ecdsa::Signature<$curve>);
448
449 impl Signature<$curve> for $sig {
450 type Data = SigBytes<der::Signature<$curve>>;
451
452 fn export(&self) -> Self::Data {
453 SigBytes(self.0.to_der())
454 }
455 }
456
457 impl<'a> Import<&'a [u8]> for $sig {
458 fn import(data: &'a [u8]) -> Result<Self, ImportError> {
459 let sig =
460 ecdsa::Signature::from_der(data).map_err(|_| ImportError::InvalidSyntax)?;
461 Ok(Self(sig))
462 }
463 }
464
465 impl Signer for $curve {
466 const ID: SignerId = SignerId::$curve;
467
468 type SigningKey = $sk;
469 type VerifyingKey = $pk;
470 type Signature = $sig;
471 }
472 };
473}
474ecdsa_impl!(
475 P256,
476 "P-256",
477 P256SigningKey,
478 P256VerifyingKey,
479 P256Signature,
480 P256Point,
481);
482ecdsa_impl!(
483 P384,
484 "P-384",
485 P384SigningKey,
486 P384VerifyingKey,
487 P384Signature,
488 P384Point,
489);
490
491macro_rules! hash_impl {
492 (
493 $name:ident,
494 $doc:expr
495 ) => {
496 #[doc = concat!($doc, ".")]
497 #[derive(Clone, Debug, Default)]
498 pub struct $name(sha2::$name);
499
500 impl Hash for $name {
501 const ID: HashId = HashId::$name;
502
503 type DigestSize = <sha2::$name as OutputSizeUser>::OutputSize;
504 const DIGEST_SIZE: usize =
505 <<sha2::$name as OutputSizeUser>::OutputSize as Unsigned>::USIZE;
506
507 const BLOCK_SIZE: usize = <sha2::$name as BlockSizeUser>::BlockSize::USIZE;
508 type Block = Block<{ Self::BLOCK_SIZE }>;
509
510 #[inline]
511 fn new() -> Self {
512 Self(<sha2::$name as sha2::Digest>::new())
513 }
514
515 #[inline]
516 fn update(&mut self, data: &[u8]) {
517 sha2::Digest::update(&mut self.0, data)
518 }
519
520 #[inline]
521 fn digest(self) -> Digest<Self::DigestSize> {
522 Digest::from_array(sha2::Digest::finalize(self.0).into())
523 }
524
525 #[inline]
526 fn hash(data: &[u8]) -> Digest<Self::DigestSize> {
527 Digest::from_array(<sha2::$name as sha2::Digest>::digest(data).into())
528 }
529 }
530 };
531}
532hash_impl!(Sha256, "SHA-256");
533hash_impl!(Sha384, "SHA-384");
534hash_impl!(Sha512, "SHA-512");
535
536hkdf_impl!(HkdfSha256, "HKDF-SHA256", Sha256);
537hkdf_impl!(HkdfSha384, "HKDF-SHA384", Sha384);
538hkdf_impl!(HkdfSha512, "HKDF-SHA512", Sha512);
539
540hmac_impl!(HmacSha256, "HMAC-SHA256", Sha256);
541hmac_impl!(HmacSha384, "HMAC-SHA384", Sha384);
542hmac_impl!(HmacSha512, "HMAC-SHA512", Sha512);
543
544struct RngWrapper<'a, R>(&'a mut R);
546
547impl<R> CryptoRng for RngWrapper<'_, R> {}
548
549impl<R: Csprng> RngCore for RngWrapper<'_, R> {
550 fn next_u32(&mut self) -> u32 {
551 impls::next_u32_via_fill(self)
552 }
553
554 fn next_u64(&mut self) -> u64 {
555 impls::next_u64_via_fill(self)
556 }
557
558 fn fill_bytes(&mut self, dst: &mut [u8]) {
559 self.0.fill_bytes(dst)
560 }
561
562 fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), rand_core::Error> {
563 self.fill_bytes(dst);
564 Ok(())
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571
572 mod aead_tests {
573 use super::*;
574 use crate::test_util::test_aead;
575
576 test_aead!(aes256gcm, Aes256Gcm, AeadTest::AesGcm);
577
578 #[cfg(feature = "committing-aead")]
579 mod committing {
580 use super::*;
581
582 test_aead!(cmd1_aead_aes256_gcm, Cmt1Aes256Gcm);
583 test_aead!(cmd4_aead_aes256_gcm, Cmt4Aes256Gcm);
584 }
585 }
586
587 mod ecdh_tests {
588 use super::*;
589 use crate::test_util::vectors::{test_ecdh, EcdhTest};
590
591 #[test]
592 fn test_ecdh_p256() {
593 test_ecdh::<P256>(EcdhTest::EcdhSecp256r1Ecpoint);
594 }
595
596 #[test]
597 fn test_ecdh_p384() {
598 test_ecdh::<P384>(EcdhTest::EcdhSecp384r1Ecpoint);
599 }
600 }
601
602 mod ecdsa_tests {
603 use super::*;
604 use crate::test_util::test_signer;
605
606 test_signer!(p256, P256, EcdsaTest::EcdsaSecp256r1Sha256);
607 test_signer!(p384, P384, EcdsaTest::EcdsaSecp384r1Sha384);
608 }
609
610 mod hkdf_tests {
611 use super::*;
612 use crate::test_util::test_kdf;
613
614 test_kdf!(test_hkdf_sha256, HkdfSha256, HkdfTest::HkdfSha256);
615 test_kdf!(test_hkdf_sha384, HkdfSha384, HkdfTest::HkdfSha384);
616 test_kdf!(test_hkdf_sha512, HkdfSha512, HkdfTest::HkdfSha512);
617 }
618
619 mod hmac_tests {
620 use super::*;
621 use crate::test_util::test_mac;
622
623 test_mac!(test_hmac_sha256, HmacSha256, MacTest::HmacSha256);
624 test_mac!(test_hmac_sha384, HmacSha384, MacTest::HmacSha384);
625 test_mac!(test_hmac_sha512, HmacSha512, MacTest::HmacSha512);
626 }
627
628 mod hpke_tests {
629 use super::*;
630 use crate::test_util::test_hpke;
631
632 test_hpke!(
633 sha256,
634 DhKemP256HkdfSha256,
635 HkdfSha256,
636 Aes256Gcm,
637 HpkeTest::HpkeDhKemP256HkdfSha256HkdfSha256Aes256Gcm,
638 );
639 test_hpke!(
640 sha512,
641 DhKemP256HkdfSha256,
642 HkdfSha512,
643 Aes256Gcm,
644 HpkeTest::HpkeDhKemP256HkdfSha256HkdfSha512Aes256Gcm,
645 );
646 }
647}