Skip to main content

sha2/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![warn(missing_docs, unreachable_pub)]
5#![allow(clippy::needless_range_loop)]
6
7#[rustfmt::skip]
8mod consts;
9
10#[cfg(any(feature = "sha256", feature = "sha256_224"))]
11mod sha256;
12
13#[cfg(all(feature = "compress", any(feature = "sha256", feature = "sha256_224")))]
14#[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
15pub use sha256::compress256;
16
17#[cfg(any(
18    feature = "sha512",
19    feature = "sha512_224",
20    feature = "sha512_256",
21    feature = "sha512_384"
22))]
23mod sha512;
24
25#[cfg(all(
26    feature = "compress",
27    any(
28        feature = "sha512",
29        feature = "sha512_224",
30        feature = "sha512_256",
31        feature = "sha512_384"
32    )
33))]
34#[cfg_attr(docsrs, doc(cfg(feature = "compress")))]
35pub use sha512::compress512;
36
37// ---------------------------------------------------------------------------
38// Inner helpers
39// ---------------------------------------------------------------------------
40
41#[cfg(any(feature = "sha256", feature = "sha256_224"))]
42fn sha256_inner(iv: [u32; 8], data: &[u8]) -> [u8; 32] {
43    let mut state = iv;
44    let blocks: usize = data.len() >> 6;
45    let remaining: usize = data.len() & 63;
46
47    // Process complete blocks
48    for i in 0..blocks {
49        let block: &[u8; 64] = data[i * 64..][..64].try_into().unwrap();
50        sha256::compress256(&mut state, &[*block]);
51    }
52
53    // Process final block with padding
54    let total_bits = (data.len() as u64) << 3;
55    let mut final_block: [u8; 64] = [0u8; 64];
56    final_block[..remaining].copy_from_slice(&data[blocks * 64..]);
57    final_block[remaining] = 0x80;
58
59    // If we don't have room for the length, we need two blocks
60    if remaining >= 56 {
61        sha256::compress256(&mut state, &[final_block]);
62        final_block = [0u8; 64];
63    }
64
65    // Append length in bits as big-endian u64
66    final_block[56..64].copy_from_slice(&total_bits.to_be_bytes());
67    sha256::compress256(&mut state, &[final_block]);
68
69    // Convert state to output bytes
70    let mut out = [0u8; 32];
71    for i in 0..8 {
72        let bytes = state[i].to_be_bytes();
73        out[i * 4] = bytes[0];
74        out[i * 4 + 1] = bytes[1];
75        out[i * 4 + 2] = bytes[2];
76        out[i * 4 + 3] = bytes[3];
77    }
78    out
79}
80
81#[cfg(any(
82    feature = "sha512",
83    feature = "sha512_224",
84    feature = "sha512_256",
85    feature = "sha512_384"
86))]
87fn sha512_inner(iv: [u64; 8], data: &[u8]) -> [u8; 64] {
88    let mut state = iv;
89    let blocks: usize = data.len() >> 7;
90    let remaining: usize = data.len() & 127;
91
92    // Process complete blocks
93    for i in 0..blocks {
94        let block: &[u8; 128] = data[i * 128..][..128].try_into().unwrap();
95        sha512::compress512(&mut state, &[*block]);
96    }
97
98    // Process final block with padding
99    let total_bits = (data.len() as u128) << 3;
100    let mut final_block: [u8; 128] = [0u8; 128];
101    final_block[..remaining].copy_from_slice(&data[blocks * 128..]);
102    final_block[remaining] = 0x80;
103
104    // If we don't have room for the length, we need two blocks
105    if remaining >= 112 {
106        sha512::compress512(&mut state, &[final_block]);
107        final_block = [0u8; 128];
108    }
109
110    // Append length in bits as big-endian u128
111    final_block[112..128].copy_from_slice(&total_bits.to_be_bytes());
112    sha512::compress512(&mut state, &[final_block]);
113
114    // Convert state to output bytes
115    let mut out = [0u8; 64];
116    for i in 0..8 {
117        let bytes = state[i].to_be_bytes();
118        out[i * 8] = bytes[0];
119        out[i * 8 + 1] = bytes[1];
120        out[i * 8 + 2] = bytes[2];
121        out[i * 8 + 3] = bytes[3];
122        out[i * 8 + 4] = bytes[4];
123        out[i * 8 + 5] = bytes[5];
124        out[i * 8 + 6] = bytes[6];
125        out[i * 8 + 7] = bytes[7];
126    }
127    out
128}
129
130// ---------------------------------------------------------------------------
131// Public API
132// ---------------------------------------------------------------------------
133
134/// Compute the SHA-256 hash of `data`, returning a 32-byte digest.
135///
136/// # Examples
137///
138/// ```
139/// use sha2::sha256;
140/// use hex_literal::hex;
141///
142/// let hash = sha256(b"hello world");
143/// assert_eq!(hash, hex!("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"));
144/// ```
145#[cfg(feature = "sha256")]
146#[cfg_attr(docsrs, doc(cfg(feature = "sha256")))]
147#[must_use]
148pub fn sha256(data: &[u8]) -> [u8; 32] {
149    sha256_inner(consts::H256_256, data)
150}
151
152/// Compute the SHA-224 hash of `data`, returning a 28-byte digest.
153///
154/// # Examples
155///
156/// ```
157/// use sha2::sha224;
158/// use hex_literal::hex;
159///
160/// let hash = sha224(b"abc");
161/// assert_eq!(hash, hex!("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"));
162/// ```
163#[cfg(feature = "sha256_224")]
164#[cfg_attr(docsrs, doc(cfg(feature = "sha256_224")))]
165#[must_use]
166pub fn sha224(data: &[u8]) -> [u8; 28] {
167    let out = sha256_inner(consts::H256_224, data);
168    out[..28].try_into().unwrap()
169}
170
171/// Compute the SHA-512 hash of `data`, returning a 64-byte digest.
172///
173/// # Examples
174///
175/// ```
176/// use sha2::sha512;
177/// use hex_literal::hex;
178///
179/// let hash = sha512(b"hello world");
180/// assert_eq!(hash, hex!(
181///     "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f"
182///     "989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
183/// ));
184/// ```
185#[cfg(feature = "sha512")]
186#[cfg_attr(docsrs, doc(cfg(feature = "sha512")))]
187#[must_use]
188pub fn sha512(data: &[u8]) -> [u8; 64] {
189    sha512_inner(consts::H512_512, data)
190}
191
192/// Compute the SHA-512/224 hash of `data`, returning a 28-byte digest.
193///
194/// # Examples
195///
196/// ```
197/// use sha2::sha512_224;
198/// use hex_literal::hex;
199///
200/// let hash = sha512_224(b"abc");
201/// assert_eq!(hash, hex!("4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"));
202/// ```
203#[cfg(feature = "sha512_224")]
204#[cfg_attr(docsrs, doc(cfg(feature = "sha512_224")))]
205#[must_use]
206pub fn sha512_224(data: &[u8]) -> [u8; 28] {
207    let out = sha512_inner(consts::H512_224, data);
208    out[..28].try_into().unwrap()
209}
210
211/// Compute the SHA-512/256 hash of `data`, returning a 32-byte digest.
212///
213/// # Examples
214///
215/// ```
216/// use sha2::sha512_256;
217/// use hex_literal::hex;
218///
219/// let hash = sha512_256(b"abc");
220/// assert_eq!(hash, hex!("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"));
221/// ```
222#[cfg(feature = "sha512_256")]
223#[cfg_attr(docsrs, doc(cfg(feature = "sha512_256")))]
224#[must_use]
225pub fn sha512_256(data: &[u8]) -> [u8; 32] {
226    let out = sha512_inner(consts::H512_256, data);
227    out[..32].try_into().unwrap()
228}
229
230/// Compute the SHA-384 hash of `data`, returning a 48-byte digest.
231///
232/// # Examples
233///
234/// ```
235/// use sha2::sha384;
236/// use hex_literal::hex;
237///
238/// let hash = sha384(b"abc");
239/// assert_eq!(hash, hex!(
240///     "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"
241///     "8086072ba1e7cc2358baeca134c825a7"
242/// ));
243/// ```
244#[cfg(feature = "sha512_384")]
245#[cfg_attr(docsrs, doc(cfg(feature = "sha512_384")))]
246#[must_use]
247pub fn sha384(data: &[u8]) -> [u8; 48] {
248    let out = sha512_inner(consts::H512_384, data);
249    out[..48].try_into().unwrap()
250}