script_webcrypto/subtlecrypto/
pbkdf2_operation.rs1use js::context::JSContext;
6use pbkdf2::pbkdf2_hmac;
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, KeyAlgorithm, KeyAlgorithmAndDerivatives, NormalizedAlgorithm, Pbkdf2Params,
17};
18use crate::traits::Equivalence;
19
20pub(crate) fn derive_bits<D: Equivalence>(
22 normalized_algorithm: &Pbkdf2Params,
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 if normalized_algorithm.iterations == 0 {
39 return Err(Error::Operation(Some(
40 "Normalized algorithm's iterations is zero".into(),
41 )));
42 }
43
44 if length == 0 {
46 return Ok(Vec::new());
47 }
48
49 let Handle::Pbkdf2Password(password) = key.handle() else {
59 return Err(Error::Operation(Some(
60 "[[handle]] internal slot of key is not a PBKDF2 password".into(),
61 )));
62 };
63 let mut result = vec![0; length as usize / 8];
64 match normalized_algorithm.hash.name() {
65 CryptoAlgorithm::Sha1 => {
66 pbkdf2_hmac::<Sha1>(
67 password,
68 &normalized_algorithm.salt,
69 normalized_algorithm.iterations,
70 &mut result,
71 );
72 },
73 CryptoAlgorithm::Sha256 => {
74 pbkdf2_hmac::<Sha256>(
75 password,
76 &normalized_algorithm.salt,
77 normalized_algorithm.iterations,
78 &mut result,
79 );
80 },
81 CryptoAlgorithm::Sha384 => {
82 pbkdf2_hmac::<Sha384>(
83 password,
84 &normalized_algorithm.salt,
85 normalized_algorithm.iterations,
86 &mut result,
87 );
88 },
89 CryptoAlgorithm::Sha512 => {
90 pbkdf2_hmac::<Sha512>(
91 password,
92 &normalized_algorithm.salt,
93 normalized_algorithm.iterations,
94 &mut result,
95 );
96 },
97 _ => {
98 return Err(Error::NotSupported(Some(
99 "Normalized algorithm's hash name is not supported".into(),
100 )));
101 },
102 };
103
104 Ok(result)
106}
107
108pub(crate) fn import_key<D: Equivalence>(
110 cx: &mut JSContext,
111 global: &D::GlobalScope,
112 format: KeyFormat,
113 key_data: &[u8],
114 extractable: bool,
115 usages: Vec<KeyUsage>,
116) -> Result<DomRoot<CryptoKey<D>>, Error> {
117 if !matches!(format, KeyFormat::Raw | KeyFormat::Raw_secret) {
119 return Err(Error::NotSupported(Some("Format is not raw".into())));
120 }
121
122 usages.ensure_only_contain_entries_from(&[KeyUsage::DeriveKey, KeyUsage::DeriveBits])?;
125
126 if extractable {
128 return Err(Error::Syntax(Some("Extractable is not false".into())));
129 }
130
131 let algorithm = KeyAlgorithm {
137 name: CryptoAlgorithm::Pbkdf2,
138 };
139 let key = CryptoKey::new(
140 cx,
141 global,
142 KeyType::Secret,
143 extractable,
144 KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm),
145 usages.normalized_value(),
146 Handle::Pbkdf2Password(key_data.to_vec().into()),
147 );
148
149 Ok(key)
151}
152
153pub(crate) fn get_key_length() -> Result<Option<u32>, Error> {
155 Ok(None)
157}