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