script/dom/subtlecrypto/
hkdf_operation.rs1use hkdf::Hkdf;
6use js::context::JSContext;
7use sha1::Sha1;
8use sha2::{Sha256, Sha384, Sha512};
9
10use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{KeyType, KeyUsage};
11use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
12use crate::dom::bindings::error::Error;
13use crate::dom::bindings::root::DomRoot;
14use crate::dom::cryptokey::{CryptoKey, Handle};
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::subtlecrypto::{
17 CryptoAlgorithm, KeyAlgorithmAndDerivatives, NormalizedAlgorithm, SubtleHkdfParams,
18 SubtleKeyAlgorithm,
19};
20
21pub(crate) fn derive_bits(
23 normalized_algorithm: &SubtleHkdfParams,
24 key: &CryptoKey,
25 length: Option<u32>,
26) -> Result<Vec<u8>, Error> {
27 let Some(length) = length else {
29 return Err(Error::Operation(Some("length is null".into())));
30 };
31 if length % 8 != 0 {
32 return Err(Error::Operation(Some(
33 "length is not a multiple of 8".into(),
34 )));
35 };
36
37 let Handle::HkdfSecret(key_derivation_key) = key.handle() else {
39 return Err(Error::Operation(Some(
40 "The [[handle]] internal slot is not from an HKDF key".into(),
41 )));
42 };
43
44 let mut result = vec![0u8; length as usize / 8];
53 match normalized_algorithm.hash.name() {
54 CryptoAlgorithm::Sha1 => {
55 Hkdf::<Sha1>::new(Some(&normalized_algorithm.salt), key_derivation_key)
56 .expand(&normalized_algorithm.info, &mut result)
57 .map_err(|error| Error::Operation(Some(error.to_string())))?
58 },
59 CryptoAlgorithm::Sha256 => {
60 Hkdf::<Sha256>::new(Some(&normalized_algorithm.salt), key_derivation_key)
61 .expand(&normalized_algorithm.info, &mut result)
62 .map_err(|error| Error::Operation(Some(error.to_string())))?
63 },
64 CryptoAlgorithm::Sha384 => {
65 Hkdf::<Sha384>::new(Some(&normalized_algorithm.salt), key_derivation_key)
66 .expand(&normalized_algorithm.info, &mut result)
67 .map_err(|error| Error::Operation(Some(error.to_string())))?
68 },
69 CryptoAlgorithm::Sha512 => {
70 Hkdf::<Sha512>::new(Some(&normalized_algorithm.salt), key_derivation_key)
71 .expand(&normalized_algorithm.info, &mut result)
72 .map_err(|error| Error::Operation(Some(error.to_string())))?
73 },
74 algorithm_name => {
75 return Err(Error::Operation(Some(format!(
76 "Invalid hash algorithm: {}",
77 algorithm_name.as_str()
78 ))));
79 },
80 }
81
82 Ok(result)
84}
85
86pub(crate) fn import_key(
88 cx: &mut JSContext,
89 global: &GlobalScope,
90 format: KeyFormat,
91 key_data: &[u8],
92 extractable: bool,
93 usages: Vec<KeyUsage>,
94) -> Result<DomRoot<CryptoKey>, Error> {
95 if matches!(format, KeyFormat::Raw | KeyFormat::Raw_secret) {
99 if usages
102 .iter()
103 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
104 usages.is_empty()
105 {
106 return Err(Error::Syntax(Some(
107 "Usages contains an entry which is not \"deriveKey\" or \"deriveBits\"".into(),
108 )));
109 }
110
111 if extractable {
113 return Err(Error::Syntax(Some("'extractable' is not false".into())));
114 }
115
116 let algorithm = SubtleKeyAlgorithm {
122 name: CryptoAlgorithm::Hkdf,
123 };
124 let key = CryptoKey::new(
125 cx,
126 global,
127 KeyType::Secret,
128 extractable,
129 KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm),
130 usages,
131 Handle::HkdfSecret(key_data.to_vec()),
132 );
133
134 Ok(key)
136 }
137 else {
139 Err(Error::NotSupported(Some(
141 "Formats different than \"raw\" are unsupported".into(),
142 )))
143 }
144}
145
146pub(crate) fn get_key_length() -> Result<Option<u32>, Error> {
148 Ok(None)
150}