script/dom/webcrypto/subtlecrypto/cshake_operation.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use cshake::digest::{ExtendableOutput, Update};
6use cshake::{CShake128, CShake256};
7
8use crate::dom::bindings::error::Error;
9use crate::dom::subtlecrypto::{CryptoAlgorithm, SubtleCShakeParams};
10
11/// <https://wicg.github.io/webcrypto-modern-algos/#cshake-operations-digest>
12pub(crate) fn digest(
13 normalized_algorithm: &SubtleCShakeParams,
14 message: &[u8],
15) -> Result<Vec<u8>, Error> {
16 // Step 1. Let outputLength be the outputLength member of normalizedAlgorithm.
17 let output_length = normalized_algorithm.output_length;
18
19 // Step 2. Let functionName be the functionName member of normalizedAlgorithm if present or the
20 // empty octet string otherwise.
21 let function_name = normalized_algorithm.function_name.as_deref().unwrap_or(&[]);
22
23 // Step 3. Let customization be the customization member of normalizedAlgorithm if present or
24 // the empty octet string otherwise.
25 let customization = normalized_algorithm.customization.as_deref().unwrap_or(&[]);
26
27 // Step 4.
28 // If the name member of normalizedAlgorithm is a case-sensitive string match for "cSHAKE128":
29 // Let result be the result of performing the cSHAKE128 function defined in Section 3 of
30 // [NIST-SP800-185] using message as the X input parameter, length as the L input
31 // parameter, functionName as the N input parameter, and customization as the S input
32 // parameter.
33 // If the name member of normalizedAlgorithm is a case-sensitive string match for "cSHAKE256":
34 // Let result be the result of performing the cSHAKE256 function defined in Section 3 of
35 // [NIST-SP800-185] using message as the X input parameter, length as the L input
36 // parameter, functionName as the N input parameter, and customization as the S input
37 // parameter.
38 // Step 5. If performing the operation results in an error, then throw an OperationError.
39 let mut result = vec![0u8; output_length.div_ceil(8) as usize];
40 match normalized_algorithm.name {
41 CryptoAlgorithm::CShake128 => {
42 let mut hasher = CShake128::new_with_function_name(function_name, customization);
43 hasher.update(message);
44 hasher.finalize_xof_into(&mut result);
45 },
46 CryptoAlgorithm::CShake256 => {
47 let mut hasher = CShake256::new_with_function_name(function_name, customization);
48 hasher.update(message);
49 hasher.finalize_xof_into(&mut result);
50 },
51 algorithm_name => {
52 return Err(Error::NotSupported(Some(format!(
53 "{} is not supported",
54 algorithm_name.as_str()
55 ))));
56 },
57 }
58
59 // Step 6. Return a byte sequence containing result.
60 if !output_length.is_multiple_of(8) {
61 // Clean excess bits in the last byte of result.
62 let mask = u8::MAX << (8 - output_length % 8);
63 if let Some(last_byte) = result.last_mut() {
64 *last_byte &= mask;
65 }
66 }
67 Ok(result)
68}