Skip to main content

crypto_core/error/
kdf.rs

1// SPDX-FileCopyrightText: 2026 ReallyMe LLC
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5/// Password-based key derivation algorithm identifier.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum KdfAlgorithm {
9    /// Argon2id memory-hard KDF.
10    Argon2id,
11    /// PBKDF2 password-based KDF conforming to RFC 8018.
12    Pbkdf2,
13    /// NIST Concat KDF as profiled by JOSE/JWA ECDH-ES.
14    ConcatKdf,
15    /// KMAC256 from NIST SP 800-185.
16    Kmac256,
17}
18
19impl core::fmt::Display for KdfAlgorithm {
20    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21        let detail = match self {
22            KdfAlgorithm::Argon2id => "Argon2id",
23            KdfAlgorithm::Pbkdf2 => "PBKDF2",
24            KdfAlgorithm::ConcatKdf => "Concat KDF",
25            KdfAlgorithm::Kmac256 => "KMAC256",
26        };
27        write!(f, "{detail}")
28    }
29}
30
31/// Versioned parameter profile for the KDF.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33#[non_exhaustive]
34pub enum KdfProfile {
35    /// Argon2id parameter profile version 1.
36    Argon2idV1,
37    /// Argon2id parameter profile version 2.
38    Argon2idV2,
39    /// PBKDF2 using HMAC-SHA-256 as the PRF.
40    Pbkdf2HmacSha256,
41    /// PBKDF2 using HMAC-SHA-512 as the PRF.
42    Pbkdf2HmacSha512,
43    /// JWA ECDH-ES Concat KDF using SHA-256.
44    JwaEcdhEsSha256,
45    /// NIST SP 800-185 KMAC256 with caller-supplied input and customization.
46    Sp800185Kmac256,
47}
48
49impl core::fmt::Display for KdfProfile {
50    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51        let detail = match self {
52            KdfProfile::Argon2idV1 => "Argon2id v1",
53            KdfProfile::Argon2idV2 => "Argon2id v2",
54            KdfProfile::Pbkdf2HmacSha256 => "PBKDF2-HMAC-SHA-256",
55            KdfProfile::Pbkdf2HmacSha512 => "PBKDF2-HMAC-SHA-512",
56            KdfProfile::JwaEcdhEsSha256 => "JWA ECDH-ES Concat KDF SHA-256",
57            KdfProfile::Sp800185Kmac256 => "SP 800-185 KMAC256",
58        };
59        write!(f, "{detail}")
60    }
61}
62
63/// Specific reason a KDF operation failed.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65#[non_exhaustive]
66pub enum KdfFailureKind {
67    /// The secret/password input had an unacceptable length.
68    InvalidSecretLength,
69    /// The salt input had an unacceptable length.
70    InvalidSaltLength,
71    /// The requested output length was unacceptable.
72    InvalidOutputLength,
73    /// The iteration count was zero or outside this API's accepted range.
74    InvalidIterationCount,
75    /// The supplied KDF parameters were invalid.
76    InvalidParams,
77    /// The derivation itself did not succeed.
78    DerivationFailed,
79    /// The combined iteration and output-block work exceeds the public bound.
80    ResourceLimitExceeded,
81}
82
83impl core::fmt::Display for KdfFailureKind {
84    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85        let detail = match self {
86            KdfFailureKind::InvalidSecretLength => "invalid secret length",
87            KdfFailureKind::InvalidSaltLength => "invalid salt length",
88            KdfFailureKind::InvalidOutputLength => "invalid output length",
89            KdfFailureKind::InvalidIterationCount => "invalid iteration count",
90            KdfFailureKind::InvalidParams => "invalid parameters",
91            KdfFailureKind::ResourceLimitExceeded => "resource limit exceeded",
92            KdfFailureKind::DerivationFailed => "derivation failed",
93        };
94        write!(f, "{detail}")
95    }
96}
97
98/// Hash function underlying an HKDF operation.
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100#[non_exhaustive]
101pub enum HkdfHash {
102    /// HKDF using SHA-2-256.
103    Sha2_256,
104    /// HKDF using SHA-2-384.
105    Sha2_384,
106    /// HKDF using SHA-3-256.
107    Sha3_256,
108}
109
110impl core::fmt::Display for HkdfHash {
111    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112        let detail = match self {
113            HkdfHash::Sha2_256 => "SHA2-256",
114            HkdfHash::Sha2_384 => "SHA2-384",
115            HkdfHash::Sha3_256 => "SHA3-256",
116        };
117        write!(f, "{detail}")
118    }
119}
120
121/// Specific reason an HKDF operation failed.
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123#[non_exhaustive]
124pub enum HkdfFailureKind {
125    /// The input key material had an unacceptable length.
126    InvalidIkmLength,
127    /// The domain-separation tag had an unacceptable length.
128    InvalidDomainTagLength,
129    /// The domain-separation tag contained an invalid byte.
130    InvalidDomainTagByte,
131    /// An input length exceeded the representable range.
132    LengthOverflow,
133    /// The requested output length was unacceptable.
134    InvalidOutputLength,
135    /// The HKDF expand step did not succeed.
136    ExpandFailed,
137}
138
139impl core::fmt::Display for HkdfFailureKind {
140    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141        let detail = match self {
142            HkdfFailureKind::InvalidIkmLength => "invalid input key material length",
143            HkdfFailureKind::InvalidDomainTagLength => "invalid domain tag length",
144            HkdfFailureKind::InvalidDomainTagByte => "invalid domain tag byte",
145            HkdfFailureKind::LengthOverflow => "length overflow",
146            HkdfFailureKind::InvalidOutputLength => "invalid output length",
147            HkdfFailureKind::ExpandFailed => "expand failed",
148        };
149        write!(f, "{detail}")
150    }
151}