script/dom/webcrypto/subtlecrypto/
pbkdf2_operation.rs1use std::num::NonZero;
6
7use aws_lc_rs::pbkdf2;
8use js::context::JSContext;
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, KeyUsageVecHelper};
15use crate::dom::globalscope::GlobalScope;
16use crate::dom::subtlecrypto::{
17 CryptoAlgorithm, KeyAlgorithm, KeyAlgorithmAndDerivatives, NormalizedAlgorithm, Pbkdf2Params,
18};
19
20pub(crate) fn derive_bits(
22 normalized_algorithm: &Pbkdf2Params,
23 key: &CryptoKey,
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 Ok(iterations) = NonZero::<u32>::try_from(normalized_algorithm.iterations) else {
38 return Err(Error::Operation(Some(
39 "Normalized algorithm's iterations is zero".into(),
40 )));
41 };
42
43 if length == 0 {
45 return Ok(Vec::new());
46 }
47
48 let prf = match normalized_algorithm.hash.name() {
51 CryptoAlgorithm::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
52 CryptoAlgorithm::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
53 CryptoAlgorithm::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
54 CryptoAlgorithm::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
55 _ => {
56 return Err(Error::NotSupported(Some(
57 "Normalized algorithm's hash name is not supported".into(),
58 )));
59 },
60 };
61
62 let mut result = vec![0; length as usize / 8];
69 pbkdf2::derive(
70 prf,
71 iterations,
72 &normalized_algorithm.salt,
73 key.handle().as_bytes(),
74 &mut result,
75 );
76
77 Ok(result)
83}
84
85pub(crate) fn import_key(
87 cx: &mut JSContext,
88 global: &GlobalScope,
89 format: KeyFormat,
90 key_data: &[u8],
91 extractable: bool,
92 usages: Vec<KeyUsage>,
93) -> Result<DomRoot<CryptoKey>, Error> {
94 if !matches!(format, KeyFormat::Raw | KeyFormat::Raw_secret) {
96 return Err(Error::NotSupported(Some("Format is not raw".into())));
97 }
98
99 if usages
101 .iter()
102 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
103 usages.is_empty()
104 {
105 return Err(Error::Syntax(Some(
106 "Usages is empty or contains a value that is not a 'deriveKey' or 'deriveBits'".into(),
107 )));
108 }
109
110 if extractable {
112 return Err(Error::Syntax(Some("Extractable is not false".into())));
113 }
114
115 let algorithm = KeyAlgorithm {
121 name: CryptoAlgorithm::Pbkdf2,
122 };
123 let key = CryptoKey::new(
124 cx,
125 global,
126 KeyType::Secret,
127 extractable,
128 KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm),
129 usages.normalized_value(),
130 Handle::Pbkdf2(key_data.to_vec().into()),
131 );
132
133 Ok(key)
135}
136
137pub(crate) fn get_key_length() -> Result<Option<u32>, Error> {
139 Ok(None)
141}