bouncycastle_sha3/lib.rs
1//! Implements SHA3 as per NIST FIPS 202.
2//!
3//! # Examples
4//! ## Hash
5//! Hash functionality is accessed via the [`Hash`] trait,
6//! which is implemented by [`SHA3_224`], [`SHA3_256`], [`SHA3_384`] and [`SHA3_512`].
7//!
8//! The simplest usage is via the one-shot functions.
9//! ```
10//! use bouncycastle_core::traits::Hash;
11//! use bouncycastle_sha3 as sha3;
12//!
13//! let data: &[u8] = b"Hello, world!";
14//! let output: Vec<u8> = sha3::SHA3_256::new().hash(data);
15//! ```
16//!
17//! More advanced usage will require creating a SHA3 or SHAKE object to hold state between successive calls,
18//! for example if input is received in chunks and not all available at the same time:
19//!
20//! ```
21//! use bouncycastle_core::traits::Hash;
22//! use bouncycastle_sha3 as sha3;
23//!
24//! let data: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F
25//! \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F
26//! \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F
27//! \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F";
28//! let mut sha3 = sha3::SHA3_256::new();
29//!
30//! for chunk in data.chunks(16) {
31//! sha3.do_update(chunk);
32//! }
33//!
34//! let output: Vec<u8> = sha3.do_final();
35//! ```
36//!
37//! It is also possible to provide input where the final byte contains less than 8 bits of data (ie is a partial byte);
38//! for example, the following code uses only 3 bits of the final byte:
39//! ```
40//! use bouncycastle_core::traits::Hash;
41//! use bouncycastle_sha3 as sha3;
42//!
43//! let data: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
44//! let mut sha3 = sha3::SHA3_256::new();
45//! sha3.do_update(&data[..data.len()-1]);
46//! let final_byte = data[data.len()-1];
47//! let output: Vec<u8> = sha3.do_final_partial_bits(final_byte, 3).expect("Failed to finalize hash state.");
48//! ```
49//!
50//! ## XOF
51//! SHA3 offers Extendable-Output Functions in the form of SHAKE, which is accessed through the [`XOF`] trait,
52//! which is implemented by [`SHAKE128`] and [`SHAKE256`].
53//! The difference from [`Hash`] is that SHAKE can produce output of any length.
54//!
55//! The simplest usage is via the static functions. The following example produces a 16 byte (128-bit) and 16KiB output:
56//!```
57//! use bouncycastle_core::traits::XOF;
58//! use bouncycastle_sha3 as sha3;
59//!
60//! let data: &[u8] = b"Hello, world!";
61//! let output_16byte: Vec<u8> = sha3::SHAKE128::new().hash_xof(data, 16);
62//! let output_16KiB: Vec<u8> = sha3::SHAKE128::new().hash_xof(data, 16 * 1024);
63//! ```
64//!
65//! As with [`Hash`] above, the [`XOF`] trait has streaming APIs in the form of [`XOF::absorb`] and [`XOF::squeeze`].
66//! Unlike [`Hash::do_final`], [`XOF::squeeze`] can be called multiple times.
67//! Note, however, that once you start squeezing, you can no longer absorb more input -- [`XOF::absorb`]
68//! will throw a [`HashError::InvalidState`], but the SHAKE object will still be usable for squeezing
69//! as if the erroneous `absorb` call never happened.
70//!
71//! The following code produces the same output as the previous example:
72//!```
73//! use bouncycastle_core::traits::XOF;
74//! use bouncycastle_sha3 as sha3;
75//!
76//! let data: &[u8] = b"Hello, world!";
77//! let mut shake = sha3::SHAKE128::new();
78//! shake.absorb(data).expect("infallible before squeeze");
79//! let output_16byte: Vec<u8> = shake.squeeze(16);
80//!
81//! let mut shake = sha3::SHAKE128::new();
82//! let mut output_16KiB: Vec<u8> = vec![];
83//! for i in 0..16 { output_16KiB.extend_from_slice(&shake.squeeze(1024)) }
84//! ```
85//!
86//! ## KDF
87//! SHA3 offers Key Derivation Functions in the form of KDF, which is accessed through the [`KDF`] trait,
88//! which is implemented by all SHA3 and SHAKE variants.
89//! [`KDF`] acts on [`KeyMaterial`] objects as both the input and output values.
90//! In the case of SHA3, the [`KDF`] interfaces are simple wrapper functions around the underlying SHA3 or SHAKE
91//! primitive that correctly maintains the length and entropy metadata of the key material that it is acting on.
92//! This is intended to act as a developer ait to prevent some classes of developer mistakes, such as
93//! deriving a cryptographic key from uninitialized (aka zeroized) input key material, or using low-entropy
94//! input key material to derive a MAC, symmetric, or asymmetric key.
95//!
96//! ```
97//! use bouncycastle_core::traits::KDF;
98//! use bouncycastle_core::key_material::{KeyMaterial256, KeyType};
99//! use bouncycastle_sha3 as sha3;
100//!
101//! let input_key = KeyMaterial256::from_bytes(b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F").unwrap();
102//! let output_key = sha3::SHA3_256::new().derive_key(&input_key, b"Additional input").unwrap();
103//!```
104//! In the previous example, since [`KeyMaterial::from_bytes`] cannot know the amount of entropy in the input data,
105//! it automatically tags it as [`KeyType::Unknown`], and thus [`SHA3Internal::derive_key`] produces an output key
106//! which also has type [`KeyType::Unknown`].
107//! This would also be the case even if the input had type
108//! [`KeyType::CryptographicRandom`] since the input [`KeyMaterial`] is 16 bytes but [`SHA3_256`] needs at least 32 bytes of
109//! full-entropy input key material in order to be able to produce full entropy output key material.
110//!
111//! # Suspending and resuming execution
112//!
113//! When hashing a large message, it can be advantageous to be able to suspend the operation
114//! to a cache and resume it later; for example if waiting for the message to stream over a slow network
115//! connection.
116//!
117//! For this reason, all SHA3 algorithms impl [`Suspendable`].
118//!
119//!```rust
120//! use bouncycastle_sha3 as sha3;
121//! use bouncycastle_core::traits::{Hash, Suspendable};
122//!
123//! let msg_part1 = b"The quick brown fox";
124//! let msg_part2 = b" jumped over the lazy dog";
125//!
126//! let mut sha3 = sha3::SHA3_256::new();
127//! sha3.do_update(msg_part1);
128//!
129//! // suspend the in-progress extract while "waiting" for the second part of the message.
130//! let serialized_state = sha3.suspend();
131//!
132//! // ...
133//! // do other things in the meantime
134//! // ...
135//!
136//! // ... later, possibly on another host: resume from the serialized state.
137//! let mut sha3_resumed = sha3::SHA3_256::from_suspended(serialized_state).unwrap();
138//! sha3_resumed.do_update(msg_part2);
139//! let h: Vec<u8> = sha3_resumed.do_final();
140//! ```
141
142#![forbid(unsafe_code)]
143#![forbid(missing_docs)]
144#![allow(private_bounds)]
145
146use crate::keccak::KeccakSize;
147use bouncycastle_core::traits::{Algorithm, AlgorithmOID, HashAlgParams, SecurityStrength};
148
149// imports needed for docs
150#[allow(unused_imports)]
151use bouncycastle_core::errors::HashError;
152#[allow(unused_imports)]
153use bouncycastle_core::key_material::{KeyMaterial, KeyType};
154#[allow(unused_imports)]
155use bouncycastle_core::traits::{Hash, KDF, Suspendable, XOF};
156// end of doc-only imports
157
158mod keccak;
159mod sha3;
160mod shake;
161
162/*** String constants ***/
163///
164pub const SHA3_224_NAME: &str = "SHA3-224";
165///
166pub const SHA3_256_NAME: &str = "SHA3-256";
167///
168pub const SHA3_384_NAME: &str = "SHA3-384";
169///
170pub const SHA3_512_NAME: &str = "SHA3-512";
171///
172pub const SHAKE128_NAME: &str = "SHAKE128";
173///
174pub const SHAKE256_NAME: &str = "SHAKE256";
175
176/*** pub types ***/
177pub use sha3::SHA3Internal;
178pub use shake::SHAKEInternal;
179
180pub use keccak::SUSPENDED_SHA3_STATE_LEN;
181
182/// Public type for SHA3_224.
183pub type SHA3_224 = SHA3Internal<SHA3_224Params>;
184/// Public type for SHA3_256.
185pub type SHA3_256 = SHA3Internal<SHA3_256Params>;
186/// Public type for SHA3_384.
187pub type SHA3_384 = SHA3Internal<SHA3_384Params>;
188/// Public type for SHA3_512.
189pub type SHA3_512 = SHA3Internal<SHA3_512Params>;
190/// Public type for SHAKE128.
191pub type SHAKE128 = SHAKEInternal<SHAKE128Params>;
192/// Public type for SHAKE256.
193pub type SHAKE256 = SHAKEInternal<SHAKE256Params>;
194
195/*** Param traits ***/
196
197/// Private trait on purpose so that only the NIST-approved params can be used.
198trait SHA3Params: HashAlgParams {
199 const SIZE: KeccakSize;
200 /// A tag, unique across all SHA3 *and* SHAKE variants, identifying which variant produced a
201 /// serialized state. Distinguishing same-rate variants (e.g. SHA3-256 vs SHAKE256) requires
202 /// this to be distinct from every value used by [`SHAKEParams::STATE_TAG`]. Never reuse a value.
203 const STATE_TAG: u8;
204}
205
206// TODO: it would probably be more elegant to macro these.
207
208impl HashAlgParams for SHA3_224 {
209 const OUTPUT_LEN: usize = 28;
210 // const BLOCK_LEN: usize = 64;
211 const BLOCK_LEN: usize = 144; // FIPS 202 Table 3
212}
213/// The parameters for SHA3_224.
214#[derive(Clone)]
215pub struct SHA3_224Params;
216impl Algorithm for SHA3_224Params {
217 const ALG_NAME: &'static str = SHA3_224_NAME;
218 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_112bit;
219}
220impl HashAlgParams for SHA3_224Params {
221 const OUTPUT_LEN: usize = 28;
222 // const BLOCK_LEN: usize = 64;
223 const BLOCK_LEN: usize = 144; // FIPS 202 Table 3
224}
225impl SHA3Params for SHA3_224Params {
226 const SIZE: KeccakSize = KeccakSize::_224;
227 const STATE_TAG: u8 = 1;
228}
229/// Assigned by NIST in the Computer Security Objects Register: id-sha3-224 { hashAlgs 7 }
230impl AlgorithmOID for SHA3_224 {
231 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 7];
232 const OID_DER: &'static [u8] =
233 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x07];
234}
235
236impl HashAlgParams for SHA3_256 {
237 const OUTPUT_LEN: usize = 32;
238 // const BLOCK_LEN: usize = 64;
239 const BLOCK_LEN: usize = 136; // FIPS 202 Table 3
240}
241/// The parameters for SHA3_256.
242#[derive(Clone)]
243pub struct SHA3_256Params;
244impl Algorithm for SHA3_256Params {
245 const ALG_NAME: &'static str = SHA3_256_NAME;
246 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
247}
248impl HashAlgParams for SHA3_256Params {
249 const OUTPUT_LEN: usize = 32;
250 // const BLOCK_LEN: usize = 64;
251 const BLOCK_LEN: usize = 136; // FIPS 202 Table 3
252}
253impl SHA3Params for SHA3_256Params {
254 const SIZE: KeccakSize = KeccakSize::_256;
255 const STATE_TAG: u8 = 2;
256}
257/// Assigned by NIST in the Computer Security Objects Register: id-sha3-256 { hashAlgs 8 }
258impl AlgorithmOID for SHA3_256 {
259 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 8];
260 const OID_DER: &'static [u8] =
261 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08];
262}
263/// The parameters for SHA3_384.
264#[derive(Clone)]
265pub struct SHA3_384Params;
266impl HashAlgParams for SHA3_384 {
267 const OUTPUT_LEN: usize = 48;
268 // const BLOCK_LEN: usize = 128;
269 const BLOCK_LEN: usize = 104; // FIPS 202 Table 3
270}
271impl Algorithm for SHA3_384Params {
272 const ALG_NAME: &'static str = SHA3_384_NAME;
273 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_192bit;
274}
275impl HashAlgParams for SHA3_384Params {
276 const OUTPUT_LEN: usize = 48;
277 // const BLOCK_LEN: usize = 128;
278 const BLOCK_LEN: usize = 104; // FIPS 202 Table 3
279}
280impl SHA3Params for SHA3_384Params {
281 const SIZE: KeccakSize = KeccakSize::_384;
282 const STATE_TAG: u8 = 3;
283}
284/// Assigned by NIST in the Computer Security Objects Register: id-sha3-384 { hashAlgs 9 }
285impl AlgorithmOID for SHA3_384 {
286 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 9];
287 const OID_DER: &'static [u8] =
288 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09];
289}
290/// The parameters for SHA3_512.
291#[derive(Clone)]
292pub struct SHA3_512Params;
293impl HashAlgParams for SHA3_512 {
294 const OUTPUT_LEN: usize = 64;
295 // const BLOCK_LEN: usize = 128;
296 const BLOCK_LEN: usize = 72; // FIPS 202 Table 3
297}
298impl Algorithm for SHA3_512Params {
299 const ALG_NAME: &'static str = SHA3_512_NAME;
300 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
301}
302impl HashAlgParams for SHA3_512Params {
303 const OUTPUT_LEN: usize = 64;
304 // const BLOCK_LEN: usize = 128;
305 const BLOCK_LEN: usize = 72; // FIPS 202 Table 3
306}
307impl SHA3Params for SHA3_512Params {
308 const SIZE: KeccakSize = KeccakSize::_512;
309 const STATE_TAG: u8 = 4;
310}
311/// Assigned by NIST in the Computer Security Objects Register: id-sha3-512 { hashAlgs 10 }
312impl AlgorithmOID for SHA3_512 {
313 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 10];
314 const OID_DER: &'static [u8] =
315 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a];
316}
317
318trait SHAKEParams: Algorithm {
319 const SIZE: KeccakSize;
320 /// See [`SHA3Params::STATE_TAG`]. Must be distinct from every SHA3 *and* SHAKE variant's tag.
321 const STATE_TAG: u8;
322}
323/// The parameters for SHAKE128.
324#[derive(Clone)]
325pub struct SHAKE128Params;
326impl Algorithm for SHAKE128Params {
327 const ALG_NAME: &'static str = SHAKE128_NAME;
328 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
329}
330impl SHAKEParams for SHAKE128Params {
331 const SIZE: KeccakSize = KeccakSize::_128;
332 const STATE_TAG: u8 = 5;
333}
334/// Assigned by NIST in the Computer Security Objects Register: id-shake128 { hashAlgs 11 }
335impl AlgorithmOID for SHAKE128 {
336 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 11];
337 const OID_DER: &'static [u8] =
338 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0b];
339}
340/// The parameters for SHAKE256.
341#[derive(Clone)]
342pub struct SHAKE256Params;
343impl Algorithm for SHAKE256Params {
344 const ALG_NAME: &'static str = SHAKE256_NAME;
345 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
346}
347impl SHAKEParams for SHAKE256Params {
348 const SIZE: KeccakSize = KeccakSize::_256;
349 const STATE_TAG: u8 = 6;
350}
351/// Assigned by NIST in the Computer Security Objects Register: id-shake256 { hashAlgs 12 }
352impl AlgorithmOID for SHAKE256 {
353 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 2, 12];
354 const OID_DER: &'static [u8] =
355 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0c];
356}