script/dom/subtlecrypto/
argon2_operation.rs1use argon2::{Argon2, AssociatedData, ParamsBuilder, Version};
6
7use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{KeyType, KeyUsage};
8use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
9use crate::dom::bindings::error::Error;
10use crate::dom::bindings::root::DomRoot;
11use crate::dom::cryptokey::{CryptoKey, Handle};
12use crate::dom::globalscope::GlobalScope;
13use crate::dom::subtlecrypto::{
14 ALG_ARGON2D, ALG_ARGON2I, ALG_ARGON2ID, KeyAlgorithmAndDerivatives, SubtleAlgorithm,
15 SubtleArgon2Params, SubtleKeyAlgorithm,
16};
17use crate::script_runtime::CanGc;
18
19pub(crate) fn derive_bits(
21 normalized_algorithm: &SubtleArgon2Params,
22 key: &CryptoKey,
23 length: Option<u32>,
24) -> Result<Vec<u8>, Error> {
25 let length = length.ok_or(Error::Operation(Some(
27 "Length for deriving bits is null".to_string(),
28 )))?;
29 if length < 32 {
30 return Err(Error::Operation(Some(
31 "Length for deriving bits is less than 32".to_string(),
32 )));
33 }
34
35 if normalized_algorithm
38 .version
39 .is_some_and(|version| version != 19)
40 {
41 return Err(Error::Operation(Some(
42 "Argon2 version is not 19 (0x13)".to_string(),
43 )));
44 }
45
46 if normalized_algorithm.parallelism == 0 || normalized_algorithm.parallelism > 16777215 {
49 return Err(Error::Operation(Some(
50 "Argon2 parallelism is zero, or greater than 16777215 (2^24-1)".to_string(),
51 )));
52 }
53
54 if normalized_algorithm.memory < 8 * normalized_algorithm.parallelism {
57 return Err(Error::Operation(Some(
58 "Argon2 memory is less than 8 times the parallelism".to_string(),
59 )));
60 }
61
62 if normalized_algorithm.passes == 0 {
64 return Err(Error::Operation(Some("Argon2 passes is zero".to_string())));
65 }
66
67 let type_ = match normalized_algorithm.name.as_str() {
75 ALG_ARGON2D => argon2::Algorithm::Argon2d,
76 ALG_ARGON2I => argon2::Algorithm::Argon2i,
77 ALG_ARGON2ID => argon2::Algorithm::Argon2id,
78 _ => {
79 return Err(Error::NotSupported(Some(format!(
80 "Unknown Argon2 algorithm name: {}",
81 normalized_algorithm.name
82 ))));
83 },
84 };
85
86 let Handle::Argon2Password(password) = key.handle() else {
98 return Err(Error::Operation(Some(
99 "Key handle is not an Argon2 password".to_string(),
100 )));
101 };
102 let mut params_builder = ParamsBuilder::new();
103 if let Some(associated_data) = &normalized_algorithm.associated_data {
104 let _ = params_builder.data(AssociatedData::new(associated_data).map_err(|_| {
105 Error::Operation(Some(
106 "Argon2 fails to add associated data to parameter builder".to_string(),
107 ))
108 })?);
109 }
110 let params = params_builder
111 .p_cost(normalized_algorithm.parallelism)
112 .m_cost(normalized_algorithm.memory)
113 .t_cost(normalized_algorithm.passes)
114 .build()
115 .map_err(|_| Error::Operation(Some("Argon2 fails to build parameters".to_string())))?;
116 let argon2_context = match &normalized_algorithm.secret_value {
117 Some(secret) => Argon2::new_with_secret(secret, type_, Version::V0x13, params)
118 .map_err(|_| Error::Operation(Some("Argon2 fails to create context".to_string())))?,
119 None => Argon2::new(type_, Version::V0x13, params),
120 };
121 let mut result = vec![0u8; length as usize / 8];
122 argon2_context
123 .hash_password_into(password, &normalized_algorithm.nonce, &mut result)
124 .map_err(|_| Error::Operation(Some("Argon2 fails to hash the password".to_string())))?;
125
126 Ok(result)
128}
129
130pub(crate) fn import_key(
132 global: &GlobalScope,
133 normalized_algorithm: &SubtleAlgorithm,
134 format: KeyFormat,
135 key_data: &[u8],
136 extractable: bool,
137 usages: Vec<KeyUsage>,
138 can_gc: CanGc,
139) -> Result<DomRoot<CryptoKey>, Error> {
140 if format != KeyFormat::Raw_secret {
144 return Err(Error::NotSupported(Some(
145 "Import key format is not \"raw-secret\"".to_string(),
146 )));
147 }
148
149 if usages
152 .iter()
153 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits))
154 {
155 return Err(Error::Syntax(Some(
156 "Usages contains a value that is not \"deriveKey\" or \"deriveBits\"".to_string(),
157 )));
158 }
159
160 if extractable {
162 return Err(Error::Syntax(Some("Extrabctable is not false".to_string())));
163 }
164
165 let algorithm = SubtleKeyAlgorithm {
172 name: normalized_algorithm.name.clone(),
173 };
174 let key = CryptoKey::new(
175 global,
176 KeyType::Secret,
177 false,
178 KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm),
179 usages,
180 Handle::Argon2Password(key_data.to_vec()),
181 can_gc,
182 );
183
184 Ok(key)
186}
187
188pub(crate) fn get_key_length() -> Result<Option<u32>, Error> {
190 Ok(None)
192}