• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::OpenSslHash;
16 use crypto_provider::hkdf::InvalidLength;
17 use std::marker::PhantomData;
18 
19 /// openssl based hkdf implementation
20 pub struct Hkdf<H: OpenSslHash> {
21     _marker: PhantomData<H>,
22     salt: Option<Vec<u8>>,
23     ikm: Vec<u8>,
24 }
25 
26 impl<H: OpenSslHash> crypto_provider::hkdf::Hkdf for Hkdf<H> {
new(salt: Option<&[u8]>, ikm: &[u8]) -> Self27     fn new(salt: Option<&[u8]>, ikm: &[u8]) -> Self {
28         Self {
29             _marker: Default::default(),
30             salt: salt.map(Vec::from),
31             ikm: Vec::from(ikm),
32         }
33     }
34 
expand_multi_info( &self, info_components: &[&[u8]], okm: &mut [u8], ) -> Result<(), InvalidLength>35     fn expand_multi_info(
36         &self,
37         info_components: &[&[u8]],
38         okm: &mut [u8],
39     ) -> Result<(), InvalidLength> {
40         // open ssl will panic in the case of a 0 length okm, but expected behavior is no-op
41         if okm.is_empty() {
42             return Ok(());
43         }
44         let mut ctx = openssl::pkey_ctx::PkeyCtx::new_id(openssl::pkey::Id::HKDF)
45             .expect("hkdf context should not fail");
46         let md = H::get_md();
47         ctx.derive_init().expect("hkdf derive init should not fail");
48         ctx.set_hkdf_md(md).expect("hkdf set md should not fail");
49         self.salt
50             .as_ref()
51             .map(|salt| ctx.set_hkdf_salt(salt.as_slice()));
52         ctx.set_hkdf_key(self.ikm.as_slice())
53             .expect("should be able to set key");
54         ctx.add_hkdf_info(&info_components.concat())
55             .expect("should be able to add info");
56         ctx.derive(Some(okm)).map_err(|_| InvalidLength).map(|_| ())
57     }
58 
expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength>59     fn expand(&self, info: &[u8], okm: &mut [u8]) -> Result<(), InvalidLength> {
60         self.expand_multi_info(&[info], okm)
61     }
62 }
63 
64 #[cfg(test)]
65 mod tests {
66     use crate::Openssl;
67     use core::marker::PhantomData;
68     use crypto_provider::hkdf::testing::*;
69 
70     #[apply(hkdf_test_cases)]
hkdf_tests(testcase: CryptoProviderTestCase<Openssl>)71     fn hkdf_tests(testcase: CryptoProviderTestCase<Openssl>) {
72         testcase(PhantomData);
73     }
74 }
75