aws_lc_rs/kdf/
sskdf.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4#![allow(clippy::module_name_repetitions)]
5
6use crate::aws_lc::{SSKDF_digest, SSKDF_hmac, EVP_MD};
7
8use crate::digest::{match_digest_type, AlgorithmID};
9use crate::error::Unspecified;
10use crate::ptr::ConstPointer;
11
12/// SSKDF with HMAC-SHA224
13#[allow(dead_code)]
14const SSKDF_HMAC_SHA224: SskdfHmacAlgorithm = SskdfHmacAlgorithm {
15    id: SskdfHmacAlgorithmId::Sha224,
16};
17
18/// SSKDF with HMAC-SHA256
19#[allow(dead_code)]
20const SSKDF_HMAC_SHA256: SskdfHmacAlgorithm = SskdfHmacAlgorithm {
21    id: SskdfHmacAlgorithmId::Sha256,
22};
23
24/// SSKDF with HMAC-SHA384
25#[allow(dead_code)]
26const SSKDF_HMAC_SHA384: SskdfHmacAlgorithm = SskdfHmacAlgorithm {
27    id: SskdfHmacAlgorithmId::Sha384,
28};
29
30/// SSKDF with HMAC-SHA512
31#[allow(dead_code)]
32const SSKDF_HMAC_SHA512: SskdfHmacAlgorithm = SskdfHmacAlgorithm {
33    id: SskdfHmacAlgorithmId::Sha512,
34};
35
36/// SSKDF with SHA224
37#[allow(dead_code)]
38const SSKDF_DIGEST_SHA224: SskdfDigestAlgorithm = SskdfDigestAlgorithm {
39    id: SskdfDigestAlgorithmId::Sha224,
40};
41
42/// SSKDF with SHA256
43#[allow(dead_code)]
44const SSKDF_DIGEST_SHA256: SskdfDigestAlgorithm = SskdfDigestAlgorithm {
45    id: SskdfDigestAlgorithmId::Sha256,
46};
47
48/// SSKDF with SHA384
49#[allow(dead_code)]
50const SSKDF_DIGEST_SHA384: SskdfDigestAlgorithm = SskdfDigestAlgorithm {
51    id: SskdfDigestAlgorithmId::Sha384,
52};
53
54/// SSKDF with SHA512
55#[allow(dead_code)]
56const SSKDF_DIGEST_SHA512: SskdfDigestAlgorithm = SskdfDigestAlgorithm {
57    id: SskdfDigestAlgorithmId::Sha512,
58};
59
60/// Retrieve [`SskdfHmacAlgorithm`] using the [`SskdfHmacAlgorithmId`] specified by `id`.
61#[must_use]
62pub const fn get_sskdf_hmac_algorithm(
63    id: SskdfHmacAlgorithmId,
64) -> Option<&'static SskdfHmacAlgorithm> {
65    {
66        match id {
67            SskdfHmacAlgorithmId::Sha224 => Some(&SSKDF_HMAC_SHA224),
68            SskdfHmacAlgorithmId::Sha256 => Some(&SSKDF_HMAC_SHA256),
69            SskdfHmacAlgorithmId::Sha384 => Some(&SSKDF_HMAC_SHA384),
70            SskdfHmacAlgorithmId::Sha512 => Some(&SSKDF_HMAC_SHA512),
71        }
72    }
73}
74
75/// Retrieve [`SskdfDigestAlgorithm`] using the [`SskdfDigestAlgorithmId`] specified by `id`.
76#[must_use]
77pub const fn get_sskdf_digest_algorithm(
78    id: SskdfDigestAlgorithmId,
79) -> Option<&'static SskdfDigestAlgorithm> {
80    {
81        match id {
82            SskdfDigestAlgorithmId::Sha224 => Some(&SSKDF_DIGEST_SHA224),
83            SskdfDigestAlgorithmId::Sha256 => Some(&SSKDF_DIGEST_SHA256),
84            SskdfDigestAlgorithmId::Sha384 => Some(&SSKDF_DIGEST_SHA384),
85            SskdfDigestAlgorithmId::Sha512 => Some(&SSKDF_DIGEST_SHA512),
86        }
87    }
88}
89
90/// SSKDF algorithm using HMAC
91pub struct SskdfHmacAlgorithm {
92    id: SskdfHmacAlgorithmId,
93}
94
95impl SskdfHmacAlgorithm {
96    /// Returns the SSKDF HMAC Algorithm Identifier
97    #[must_use]
98    pub fn id(&self) -> SskdfHmacAlgorithmId {
99        self.id
100    }
101
102    #[must_use]
103    fn get_evp_md(&self) -> ConstPointer<EVP_MD> {
104        match_digest_type(match self.id {
105            SskdfHmacAlgorithmId::Sha224 => &AlgorithmID::SHA224,
106            SskdfHmacAlgorithmId::Sha256 => &AlgorithmID::SHA256,
107            SskdfHmacAlgorithmId::Sha384 => &AlgorithmID::SHA384,
108            SskdfHmacAlgorithmId::Sha512 => &AlgorithmID::SHA512,
109        })
110    }
111}
112
113impl PartialEq for SskdfHmacAlgorithm {
114    fn eq(&self, other: &Self) -> bool {
115        self.id == other.id
116    }
117}
118
119impl Eq for SskdfHmacAlgorithm {}
120
121impl core::fmt::Debug for SskdfHmacAlgorithm {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        core::fmt::Debug::fmt(&self.id, f)
124    }
125}
126
127/// SSKDF algorithm using digest
128pub struct SskdfDigestAlgorithm {
129    id: SskdfDigestAlgorithmId,
130}
131
132impl SskdfDigestAlgorithm {
133    /// Returns the SSKDF Algorithm Identifier
134    #[must_use]
135    pub fn id(&self) -> SskdfDigestAlgorithmId {
136        self.id
137    }
138
139    #[must_use]
140    fn get_evp_md(&self) -> ConstPointer<EVP_MD> {
141        match_digest_type(match self.id {
142            SskdfDigestAlgorithmId::Sha224 => &AlgorithmID::SHA224,
143            SskdfDigestAlgorithmId::Sha256 => &AlgorithmID::SHA256,
144            SskdfDigestAlgorithmId::Sha384 => &AlgorithmID::SHA384,
145            SskdfDigestAlgorithmId::Sha512 => &AlgorithmID::SHA512,
146        })
147    }
148}
149
150impl PartialEq for SskdfDigestAlgorithm {
151    fn eq(&self, other: &Self) -> bool {
152        self.id == other.id
153    }
154}
155
156impl Eq for SskdfDigestAlgorithm {}
157
158impl core::fmt::Debug for SskdfDigestAlgorithm {
159    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
160        core::fmt::Debug::fmt(&self.id, f)
161    }
162}
163
164/// Single-step (One-step) Key Derivation Function Digest Algorithm Identifier
165#[non_exhaustive]
166#[derive(Clone, Copy, PartialEq, Eq, Debug)]
167pub enum SskdfDigestAlgorithmId {
168    /// SSKDF with SHA224
169    Sha224,
170
171    /// SSKDF with SHA256
172    Sha256,
173
174    /// SSKDF with SHA384
175    Sha384,
176
177    /// SSKDF with SHA512
178    Sha512,
179}
180
181/// Single-step (One-step) Key Derivation Function HMAC Algorithm Identifier
182#[non_exhaustive]
183#[derive(Clone, Copy, PartialEq, Eq, Debug)]
184pub enum SskdfHmacAlgorithmId {
185    /// SSKDF with HMAC-SHA224
186    Sha224,
187
188    /// SSKDF with HMAC-SHA256
189    Sha256,
190
191    /// SSKDF with HMAC-SHA384
192    Sha384,
193
194    /// SSKDF with HMAC-SHA512
195    Sha512,
196}
197
198/// # Single-step Key Derivation Function using HMAC
199///
200/// This algorithm may be referred to as "Single-Step KDF" or "NIST Concatenation KDF" by other
201/// implementors.
202///
203/// ## Input Validation and Defaults
204/// * `output.len()`, `secret.len()`, `info.len()` each must be <= 2^30.
205/// * The default salt, an all zero byte string with length equal to the digest block length, is used
206///   if `salt.len() == 0`.
207/// * `output.len() > 0 and `secret.len() > 0`
208///
209/// ## Implementation Notes
210///
211/// This implementation adheres to the algorithm specified in Section 4 of the
212/// NIST Special Publication 800-56C Revision 2 published on August 2020.
213/// Using Option 2 for the auxiliary function H.
214///
215/// Specification is available at <https://doi.org/10.6028/NIST.SP.800-56Cr2>
216///
217/// # Errors
218/// `Unspecified` is returned if input validation fails or an unexpected error occurs.
219pub fn sskdf_hmac(
220    algorithm: &'static SskdfHmacAlgorithm,
221    secret: &[u8],
222    info: &[u8],
223    salt: &[u8],
224    output: &mut [u8],
225) -> Result<(), Unspecified> {
226    let evp_md = algorithm.get_evp_md();
227    let out_len = output.len();
228    if 1 != unsafe {
229        SSKDF_hmac(
230            output.as_mut_ptr(),
231            out_len,
232            *evp_md,
233            secret.as_ptr(),
234            secret.len(),
235            info.as_ptr(),
236            info.len(),
237            salt.as_ptr(),
238            salt.len(),
239        )
240    } {
241        return Err(Unspecified);
242    }
243    Ok(())
244}
245
246/// # Single-step Key Derivation Function using digest
247///
248/// This algorithm may be referred to as "Single-Step KDF" or "NIST Concatenation KDF" by other
249/// implementors.
250///
251/// ## Input Validation and Defaults
252/// * `output.len()`, `secret.len()`, `info.len()` each must be <= 2^30.
253/// * `output.len() > 0 and `secret.len() > 0`
254///
255/// ## Implementation Notes
256///
257/// This implementation adheres to the algorithm specified in Section 4 of the
258/// NIST Special Publication 800-56C Revision 2 published on August 2020.
259/// Using Option 1 for the auxiliary function H.
260///
261/// Specification is available at <https://doi.org/10.6028/NIST.SP.800-56Cr2>
262///
263/// # Errors
264/// `Unspecified` is returned if input validation fails or an unexpected error occurs.
265pub fn sskdf_digest(
266    algorithm: &'static SskdfDigestAlgorithm,
267    secret: &[u8],
268    info: &[u8],
269    output: &mut [u8],
270) -> Result<(), Unspecified> {
271    let evp_md = algorithm.get_evp_md();
272    let out_len = output.len();
273    if 1 != unsafe {
274        SSKDF_digest(
275            output.as_mut_ptr(),
276            out_len,
277            *evp_md,
278            secret.as_ptr(),
279            secret.len(),
280            info.as_ptr(),
281            info.len(),
282        )
283    } {
284        return Err(Unspecified);
285    }
286    Ok(())
287}