1use crypto_core::{CryptoError, HkdfFailureKind, HkdfHash};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum HkdfSuite {
10 Sha2_256,
12 Sha3_256,
14}
15
16impl HkdfSuite {
17 pub const fn hash(self) -> HkdfHash {
19 match self {
20 Self::Sha2_256 => HkdfHash::Sha2_256,
21 Self::Sha3_256 => HkdfHash::Sha3_256,
22 }
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum DomainKeyPurpose {
29 AeadContentKey,
31 AeadWrapKey,
33 AuthProofKey,
35 ManifestCommitmentKey,
37}
38
39impl DomainKeyPurpose {
40 pub(crate) const fn as_bytes(self) -> &'static [u8] {
41 match self {
42 Self::AeadContentKey => b"aead_content_key",
43 Self::AeadWrapKey => b"aead_wrap_key",
44 Self::AuthProofKey => b"auth_proof_key",
45 Self::ManifestCommitmentKey => b"manifest_commitment_key",
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct DomainTag {
53 bytes: Vec<u8>,
54}
55
56impl DomainTag {
57 pub fn from_slice(input: &[u8]) -> Result<Self, CryptoError> {
60 if input.is_empty() || input.len() > 48 {
61 return Err(CryptoError::Hkdf {
62 hash: HkdfHash::Sha3_256,
63 kind: HkdfFailureKind::InvalidDomainTagLength,
64 });
65 }
66
67 for byte in input {
68 let is_lower_alpha = byte.is_ascii_lowercase();
69 let is_digit = byte.is_ascii_digit();
70 let is_punctuation = matches!(*byte, b'/' | b'_' | b'-');
71 if !(is_lower_alpha || is_digit || is_punctuation) {
72 return Err(CryptoError::Hkdf {
73 hash: HkdfHash::Sha3_256,
74 kind: HkdfFailureKind::InvalidDomainTagByte,
75 });
76 }
77 }
78
79 Ok(Self {
80 bytes: input.to_vec(),
81 })
82 }
83
84 pub fn as_bytes(&self) -> &[u8] {
86 &self.bytes
87 }
88}