1use std::ops::Deref;
6
7use serde::{Deserialize, Serialize};
8use tls_codec::{
9 SecretVLBytes, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize, VLBytes,
10};
11
12#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
13#[repr(u16)]
14pub enum AeadType {
16 Aes128Gcm = 0x0001,
18
19 Aes256Gcm = 0x0002,
21
22 ChaCha20Poly1305 = 0x0003,
24}
25
26impl AeadType {
27 pub const fn tag_size(&self) -> usize {
29 match self {
30 AeadType::Aes128Gcm => 16,
31 AeadType::Aes256Gcm => 16,
32 AeadType::ChaCha20Poly1305 => 16,
33 }
34 }
35
36 pub const fn key_size(&self) -> usize {
38 match self {
39 AeadType::Aes128Gcm => 16,
40 AeadType::Aes256Gcm => 32,
41 AeadType::ChaCha20Poly1305 => 32,
42 }
43 }
44
45 pub const fn nonce_size(&self) -> usize {
47 match self {
48 AeadType::Aes128Gcm | AeadType::Aes256Gcm | AeadType::ChaCha20Poly1305 => 12,
49 }
50 }
51}
52
53#[derive(Debug, PartialEq, Eq, Clone, Copy)]
54#[repr(u8)]
55#[allow(non_camel_case_types)]
56pub enum HashType {
58 Sha2_256 = 0x04,
59 Sha2_384 = 0x05,
60 Sha2_512 = 0x06,
61}
62
63impl HashType {
64 #[inline]
66 pub const fn size(&self) -> usize {
67 match self {
68 HashType::Sha2_256 => 32,
69 HashType::Sha2_384 => 48,
70 HashType::Sha2_512 => 64,
71 }
72 }
73}
74
75#[allow(non_camel_case_types)]
77#[allow(clippy::upper_case_acronyms)]
78#[derive(
79 Copy,
80 Hash,
81 Eq,
82 PartialEq,
83 Clone,
84 Debug,
85 Serialize,
86 Deserialize,
87 TlsSerialize,
88 TlsDeserialize,
89 TlsDeserializeBytes,
90 TlsSize,
91)]
92#[repr(u16)]
93pub enum SignatureScheme {
94 ECDSA_SECP256R1_SHA256 = 0x0403,
96 ECDSA_SECP384R1_SHA384 = 0x0503,
98 ECDSA_SECP521R1_SHA512 = 0x0603,
100 ED25519 = 0x0807,
102 ED448 = 0x0808,
104}
105
106impl TryFrom<u16> for SignatureScheme {
107 type Error = String;
108
109 fn try_from(value: u16) -> Result<Self, Self::Error> {
110 match value {
111 0x0403 => Ok(SignatureScheme::ECDSA_SECP256R1_SHA256),
112 0x0503 => Ok(SignatureScheme::ECDSA_SECP384R1_SHA384),
113 0x0603 => Ok(SignatureScheme::ECDSA_SECP521R1_SHA512),
114 0x0807 => Ok(SignatureScheme::ED25519),
115 0x0808 => Ok(SignatureScheme::ED448),
116 _ => Err(format!("Unsupported SignatureScheme: {value}")),
117 }
118 }
119}
120
121#[derive(Debug, PartialEq, Eq, Clone, Copy)]
123pub enum CryptoError {
124 CryptoLibraryError,
125 AeadDecryptionError,
126 HpkeDecryptionError,
127 HpkeEncryptionError,
128 UnsupportedSignatureScheme,
129 KdfLabelTooLarge,
130 KdfSerializationError,
131 HkdfOutputLengthInvalid,
132 InsufficientRandomness,
133 InvalidSignature,
134 UnsupportedAeadAlgorithm,
135 UnsupportedKdf,
136 InvalidLength,
137 UnsupportedHashAlgorithm,
138 SignatureEncodingError,
139 SignatureDecodingError,
140 SenderSetupError,
141 ReceiverSetupError,
142 ExporterError,
143 UnsupportedCiphersuite,
144 TlsSerializationError,
145 TooMuchData,
146 SigningError,
147 InvalidPublicKey,
148}
149
150impl std::fmt::Display for CryptoError {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 write!(f, "{self:?}")
153 }
154}
155
156impl std::error::Error for CryptoError {}
157
158#[derive(Debug)]
162pub struct HpkeConfig(pub HpkeKemType, pub HpkeKdfType, pub HpkeAeadType);
163
164#[derive(PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
166#[repr(u16)]
167pub enum HpkeKemType {
168 DhKemP256 = 0x0010,
170
171 DhKemP384 = 0x0011,
173
174 DhKemP521 = 0x0012,
176
177 DhKem25519 = 0x0020,
179
180 DhKem448 = 0x0021,
182
183 XWingKemDraft6 = 0x004D,
185}
186
187#[derive(PartialEq, Eq, Copy, Clone, Debug, Serialize, Deserialize)]
189#[repr(u16)]
190pub enum HpkeKdfType {
191 HkdfSha256 = 0x0001,
193
194 HkdfSha384 = 0x0002,
196
197 HkdfSha512 = 0x0003,
199}
200
201#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
203#[repr(u16)]
204pub enum HpkeAeadType {
205 AesGcm128 = 0x0001,
207
208 AesGcm256 = 0x0002,
210
211 ChaCha20Poly1305 = 0x0003,
213
214 Export = 0xFFFF,
216}
217
218#[derive(
227 Debug,
228 PartialEq,
229 Eq,
230 Clone,
231 Serialize,
232 Deserialize,
233 TlsSerialize,
234 TlsDeserialize,
235 TlsDeserializeBytes,
236 TlsSize,
237)]
238pub struct HpkeCiphertext {
239 pub kem_output: VLBytes,
240 pub ciphertext: VLBytes,
241}
242
243#[derive(
245 Debug,
246 Clone,
247 serde::Serialize,
248 serde::Deserialize,
249 TlsSerialize,
250 TlsDeserialize,
251 TlsDeserializeBytes,
252 TlsSize,
253)]
254#[cfg_attr(feature = "test-utils", derive(PartialEq, Eq))]
255#[serde(transparent)]
256pub struct HpkePrivateKey(SecretVLBytes);
257
258impl From<Vec<u8>> for HpkePrivateKey {
259 fn from(bytes: Vec<u8>) -> Self {
260 Self(bytes.into())
261 }
262}
263
264impl From<&[u8]> for HpkePrivateKey {
265 fn from(bytes: &[u8]) -> Self {
266 Self(bytes.into())
267 }
268}
269
270impl std::ops::Deref for HpkePrivateKey {
271 type Target = [u8];
272
273 fn deref(&self) -> &Self::Target {
274 self.0.as_slice()
275 }
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct HpkeKeyPair {
281 pub private: HpkePrivateKey,
282 pub public: Vec<u8>,
283}
284
285pub type KemOutput = Vec<u8>;
286#[derive(Clone, Debug)]
287pub struct ExporterSecret(SecretVLBytes);
288
289impl Deref for ExporterSecret {
290 type Target = [u8];
291
292 fn deref(&self) -> &Self::Target {
293 self.0.as_slice()
294 }
295}
296
297impl From<Vec<u8>> for ExporterSecret {
298 fn from(secret: Vec<u8>) -> Self {
299 Self(secret.into())
300 }
301}
302
303#[derive(
307 Clone,
308 Copy,
309 Debug,
310 PartialEq,
311 Eq,
312 Serialize,
313 Deserialize,
314 TlsSerialize,
315 TlsDeserialize,
316 TlsDeserializeBytes,
317 TlsSize,
318)]
319pub struct VerifiableCiphersuite(u16);
320
321impl VerifiableCiphersuite {
322 pub fn new(value: u16) -> Self {
323 Self(value)
324 }
325}
326
327impl From<Ciphersuite> for VerifiableCiphersuite {
328 fn from(value: Ciphersuite) -> Self {
329 Self(value as u16)
330 }
331}
332
333impl TryFrom<VerifiableCiphersuite> for Ciphersuite {
334 type Error = tls_codec::Error;
335
336 fn try_from(value: VerifiableCiphersuite) -> Result<Self, Self::Error> {
337 Ciphersuite::try_from(value.0)
338 }
339}
340
341#[allow(non_camel_case_types)]
343#[allow(clippy::upper_case_acronyms)]
344#[derive(
345 Debug,
346 Clone,
347 Copy,
348 PartialEq,
349 Eq,
350 PartialOrd,
351 Ord,
352 Hash,
353 Serialize,
354 Deserialize,
355 TlsDeserialize,
356 TlsDeserializeBytes,
357 TlsSerialize,
358 TlsSize,
359)]
360#[repr(u16)]
361pub enum Ciphersuite {
362 MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 = 0x0001,
364
365 MLS_128_DHKEMP256_AES128GCM_SHA256_P256 = 0x0002,
367
368 MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 = 0x0003,
370
371 MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 = 0x0004,
373
374 MLS_256_DHKEMP521_AES256GCM_SHA512_P521 = 0x0005,
376
377 MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 = 0x0006,
379
380 MLS_256_DHKEMP384_AES256GCM_SHA384_P384 = 0x0007,
382
383 MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 = 0x004D,
385}
386
387impl core::fmt::Display for Ciphersuite {
388 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389 write!(f, "{self:?}")
390 }
391}
392
393impl From<Ciphersuite> for u16 {
394 #[inline(always)]
395 fn from(s: Ciphersuite) -> u16 {
396 s as u16
397 }
398}
399
400impl From<&Ciphersuite> for u16 {
401 #[inline(always)]
402 fn from(s: &Ciphersuite) -> u16 {
403 *s as u16
404 }
405}
406
407impl TryFrom<u16> for Ciphersuite {
408 type Error = tls_codec::Error;
409
410 #[inline(always)]
411 fn try_from(v: u16) -> Result<Self, Self::Error> {
412 match v {
413 0x0001 => Ok(Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519),
414 0x0002 => Ok(Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256),
415 0x0003 => Ok(Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519),
416 0x0004 => Ok(Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448),
417 0x0005 => Ok(Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521),
418 0x0006 => Ok(Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448),
419 0x0007 => Ok(Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384),
420 0x004D => Ok(Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519),
421 _ => Err(Self::Error::DecodingError(format!(
422 "{v} is not a valid ciphersuite value"
423 ))),
424 }
425 }
426}
427
428impl From<Ciphersuite> for SignatureScheme {
429 #[inline(always)]
430 fn from(ciphersuite_name: Ciphersuite) -> Self {
431 ciphersuite_name.signature_algorithm()
432 }
433}
434
435impl From<Ciphersuite> for AeadType {
436 #[inline(always)]
437 fn from(ciphersuite_name: Ciphersuite) -> Self {
438 ciphersuite_name.aead_algorithm()
439 }
440}
441
442impl From<Ciphersuite> for HpkeKemType {
443 #[inline(always)]
444 fn from(ciphersuite_name: Ciphersuite) -> Self {
445 ciphersuite_name.hpke_kem_algorithm()
446 }
447}
448
449impl From<Ciphersuite> for HpkeAeadType {
450 #[inline(always)]
451 fn from(ciphersuite_name: Ciphersuite) -> Self {
452 ciphersuite_name.hpke_aead_algorithm()
453 }
454}
455
456impl From<Ciphersuite> for HpkeKdfType {
457 #[inline(always)]
458 fn from(ciphersuite_name: Ciphersuite) -> Self {
459 ciphersuite_name.hpke_kdf_algorithm()
460 }
461}
462
463impl From<Ciphersuite> for HashType {
464 #[inline(always)]
465 fn from(ciphersuite_name: Ciphersuite) -> Self {
466 ciphersuite_name.hash_algorithm()
467 }
468}
469
470impl Ciphersuite {
471 #[inline]
473 pub const fn hash_algorithm(&self) -> HashType {
474 match self {
475 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
476 | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256
477 | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
478 | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => HashType::Sha2_256,
479 Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HashType::Sha2_384,
480 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
481 | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
482 | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => HashType::Sha2_512,
483 }
484 }
485
486 #[inline]
488 pub const fn signature_algorithm(&self) -> SignatureScheme {
489 match self {
490 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
491 | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
492 | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
493 SignatureScheme::ED25519
494 }
495 Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => {
496 SignatureScheme::ECDSA_SECP256R1_SHA256
497 }
498 Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => {
499 SignatureScheme::ECDSA_SECP521R1_SHA512
500 }
501 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
502 | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
503 SignatureScheme::ED448
504 }
505 Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => {
506 SignatureScheme::ECDSA_SECP384R1_SHA384
507 }
508 }
509 }
510
511 #[inline]
513 pub const fn aead_algorithm(&self) -> AeadType {
514 match self {
515 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
516 | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => AeadType::Aes128Gcm,
517 Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
518 | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448
519 | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
520 AeadType::ChaCha20Poly1305
521 }
522 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
523 | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
524 | Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => AeadType::Aes256Gcm,
525 }
526 }
527
528 #[inline]
530 pub const fn hpke_kdf_algorithm(&self) -> HpkeKdfType {
531 match self {
532 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
533 | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256
534 | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
535 | Self::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => HpkeKdfType::HkdfSha256,
536 Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HpkeKdfType::HkdfSha384,
537 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
538 | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521
539 | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
540 HpkeKdfType::HkdfSha512
541 }
542 }
543 }
544
545 #[inline]
547 pub const fn hpke_kem_algorithm(&self) -> HpkeKemType {
548 match self {
549 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
550 | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 => {
551 HpkeKemType::DhKem25519
552 }
553 Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => HpkeKemType::DhKemP256,
554 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
555 | Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => HpkeKemType::DhKem448,
556 Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384 => HpkeKemType::DhKemP384,
557 Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => HpkeKemType::DhKemP521,
558 Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
559 HpkeKemType::XWingKemDraft6
560 }
561 }
562 }
563
564 #[inline]
566 pub const fn hpke_aead_algorithm(&self) -> HpkeAeadType {
567 match self {
568 Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
569 | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => HpkeAeadType::AesGcm128,
570 Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
571 | Ciphersuite::MLS_256_XWING_CHACHA20POLY1305_SHA256_Ed25519 => {
572 HpkeAeadType::ChaCha20Poly1305
573 }
574 Ciphersuite::MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448
575 | Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384
576 | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => HpkeAeadType::AesGcm256,
577 Ciphersuite::MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 => {
578 HpkeAeadType::ChaCha20Poly1305
579 }
580 }
581 }
582
583 #[inline]
585 pub const fn hpke_config(&self) -> HpkeConfig {
586 HpkeConfig(
587 self.hpke_kem_algorithm(),
588 self.hpke_kdf_algorithm(),
589 self.hpke_aead_algorithm(),
590 )
591 }
592
593 #[inline]
595 pub const fn hash_length(&self) -> usize {
596 self.hash_algorithm().size()
597 }
598
599 #[inline]
601 pub const fn mac_length(&self) -> usize {
602 self.aead_algorithm().tag_size()
603 }
604
605 #[inline]
607 pub const fn aead_key_length(&self) -> usize {
608 self.aead_algorithm().key_size()
609 }
610
611 #[inline]
613 pub const fn aead_nonce_length(&self) -> usize {
614 self.aead_algorithm().nonce_size()
615 }
616}