script_webcrypto/subtlecrypto/
hkdf_operation.rs1use hkdf::Hkdf;
6use js::context::JSContext;
7use script_bindings::codegen::GenericBindings::CryptoKeyBinding::{KeyType, KeyUsage};
8use script_bindings::codegen::GenericBindings::SubtleCryptoBinding::KeyFormat;
9use script_bindings::error::Error;
10use script_bindings::root::DomRoot;
11use sha1::Sha1;
12use sha2::{Sha256, Sha384, Sha512};
13
14use crate::cryptokey::{CryptoKey, Handle, KeyUsageSliceHelper};
15use crate::subtlecrypto::{
16 CryptoAlgorithm, HkdfParams, KeyAlgorithm, KeyAlgorithmAndDerivatives, NormalizedAlgorithm,
17};
18use crate::traits::Equivalence;
19
20pub(crate) fn derive_bits<D: Equivalence>(
22 normalized_algorithm: &HkdfParams,
23 key: &CryptoKey<D>,
24 length: Option<u32>,
25) -> Result<Vec<u8>, Error> {
26 let Some(length) = length else {
28 return Err(Error::Operation(Some("length is null".into())));
29 };
30 if length % 8 != 0 {
31 return Err(Error::Operation(Some(
32 "length is not a multiple of 8".into(),
33 )));
34 };
35
36 let hash_length = match normalized_algorithm.hash.name() {
39 CryptoAlgorithm::Sha1 => 160,
40 CryptoAlgorithm::Sha256 => 256,
41 CryptoAlgorithm::Sha384 => 384,
42 CryptoAlgorithm::Sha512 => 512,
43 algorithm_name => {
44 return Err(Error::Operation(Some(format!(
45 "Invalid hash algorithm: {}",
46 algorithm_name.as_str()
47 ))));
48 },
49 };
50
51 if length > 255 * hash_length {
53 return Err(Error::Operation(Some(
54 "length is greater than 255 * hashLength".into(),
55 )));
56 }
57
58 let Handle::HkdfSecret(key_derivation_key) = key.handle() else {
60 return Err(Error::Operation(Some(
61 "The [[handle]] internal slot is not from an HKDF key".into(),
62 )));
63 };
64
65 let mut result = vec![0u8; length as usize / 8];
74 match normalized_algorithm.hash.name() {
75 CryptoAlgorithm::Sha1 => {
76 Hkdf::<Sha1>::new(Some(&normalized_algorithm.salt), key_derivation_key)
77 .expand(&normalized_algorithm.info, &mut result)
78 .map_err(|error| Error::Operation(Some(error.to_string())))?
79 },
80 CryptoAlgorithm::Sha256 => {
81 Hkdf::<Sha256>::new(Some(&normalized_algorithm.salt), key_derivation_key)
82 .expand(&normalized_algorithm.info, &mut result)
83 .map_err(|error| Error::Operation(Some(error.to_string())))?
84 },
85 CryptoAlgorithm::Sha384 => {
86 Hkdf::<Sha384>::new(Some(&normalized_algorithm.salt), key_derivation_key)
87 .expand(&normalized_algorithm.info, &mut result)
88 .map_err(|error| Error::Operation(Some(error.to_string())))?
89 },
90 CryptoAlgorithm::Sha512 => {
91 Hkdf::<Sha512>::new(Some(&normalized_algorithm.salt), key_derivation_key)
92 .expand(&normalized_algorithm.info, &mut result)
93 .map_err(|error| Error::Operation(Some(error.to_string())))?
94 },
95 algorithm_name => {
96 return Err(Error::Operation(Some(format!(
97 "Invalid hash algorithm: {}",
98 algorithm_name.as_str()
99 ))));
100 },
101 }
102
103 Ok(result)
105}
106
107pub(crate) fn import_key<D: Equivalence>(
109 cx: &mut JSContext,
110 global: &D::GlobalScope,
111 format: KeyFormat,
112 key_data: &[u8],
113 extractable: bool,
114 usages: Vec<KeyUsage>,
115) -> Result<DomRoot<CryptoKey<D>>, Error> {
116 if matches!(format, KeyFormat::Raw | KeyFormat::Raw_secret) {
120 usages.ensure_only_contain_entries_from(&[KeyUsage::DeriveKey, KeyUsage::DeriveBits])?;
123
124 if extractable {
126 return Err(Error::Syntax(Some("'extractable' is not false".into())));
127 }
128
129 let algorithm = KeyAlgorithm {
135 name: CryptoAlgorithm::Hkdf,
136 };
137 let key = CryptoKey::new(
138 cx,
139 global,
140 KeyType::Secret,
141 extractable,
142 KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm),
143 usages.normalized_value(),
144 Handle::HkdfSecret(key_data.to_vec().into()),
145 );
146
147 Ok(key)
149 }
150 else {
152 Err(Error::NotSupported(Some(
154 "Formats different than \"raw\" are unsupported".into(),
155 )))
156 }
157}
158
159pub(crate) fn get_key_length() -> Result<Option<u32>, Error> {
161 Ok(None)
163}