44// option. This file may not be copied, modified, or distributed
55// except according to those terms.
66
7+ //! Cryptographic hash functions.
8+ //!
9+ //! This module provides access to NSS's hash function implementations,
10+ //! supporting both SHA-2 and SHA-3 families.
11+
712use std:: convert:: TryFrom as _;
813
914use crate :: {
@@ -13,37 +18,65 @@ use crate::{
1318 Error ,
1419} ;
1520
16- //
17- // Constants
18- //
19-
21+ /// Supported hash algorithms.
22+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
2023pub enum HashAlgorithm {
24+ /// SHA-2 256-bit (32 bytes output)
2125 SHA2_256 ,
26+ /// SHA-2 384-bit (48 bytes output)
2227 SHA2_384 ,
28+ /// SHA-2 512-bit (64 bytes output)
2329 SHA2_512 ,
30+ /// SHA-3 224-bit (28 bytes output)
31+ SHA3_224 ,
32+ /// SHA-3 256-bit (32 bytes output)
33+ SHA3_256 ,
34+ /// SHA-3 384-bit (48 bytes output)
35+ SHA3_384 ,
36+ /// SHA-3 512-bit (64 bytes output)
37+ SHA3_512 ,
2438}
2539
2640const fn hash_alg_to_oid ( alg : & HashAlgorithm ) -> SECOidTag :: Type {
2741 match alg {
2842 HashAlgorithm :: SHA2_256 => SECOidTag :: SEC_OID_SHA256 ,
2943 HashAlgorithm :: SHA2_384 => SECOidTag :: SEC_OID_SHA384 ,
3044 HashAlgorithm :: SHA2_512 => SECOidTag :: SEC_OID_SHA512 ,
45+ HashAlgorithm :: SHA3_224 => SECOidTag :: SEC_OID_SHA3_224 ,
46+ HashAlgorithm :: SHA3_256 => SECOidTag :: SEC_OID_SHA3_256 ,
47+ HashAlgorithm :: SHA3_384 => SECOidTag :: SEC_OID_SHA3_384 ,
48+ HashAlgorithm :: SHA3_512 => SECOidTag :: SEC_OID_SHA3_512 ,
3149 }
3250}
3351
52+ /// Returns the output length in bytes for the given hash algorithm.
3453#[ must_use]
3554pub const fn hash_alg_to_hash_len ( alg : & HashAlgorithm ) -> usize {
3655 match alg {
3756 HashAlgorithm :: SHA2_256 => p11:: SHA256_LENGTH as usize ,
3857 HashAlgorithm :: SHA2_384 => p11:: SHA384_LENGTH as usize ,
3958 HashAlgorithm :: SHA2_512 => p11:: SHA512_LENGTH as usize ,
59+ HashAlgorithm :: SHA3_224 => 28 ,
60+ HashAlgorithm :: SHA3_256 => p11:: SHA3_256_LENGTH as usize ,
61+ HashAlgorithm :: SHA3_384 => p11:: SHA3_384_LENGTH as usize ,
62+ HashAlgorithm :: SHA3_512 => p11:: SHA3_512_LENGTH as usize ,
4063 }
4164}
4265
43- //
44- // Hash function
45- //
46-
66+ /// Compute a cryptographic hash of the input data.
67+ ///
68+ /// # Arguments
69+ ///
70+ /// * `alg` - The hash algorithm to use.
71+ /// * `data` - The data to hash.
72+ ///
73+ /// # Returns
74+ ///
75+ /// The hash digest as a byte vector.
76+ ///
77+ /// # Errors
78+ ///
79+ /// Returns an error if NSS initialization fails or the hash operation fails.
4780pub fn hash ( alg : & HashAlgorithm , data : & [ u8 ] ) -> Result < Vec < u8 > , Error > {
4881 init ( ) ?;
4982
@@ -64,3 +97,184 @@ pub fn hash(alg: &HashAlgorithm, data: &[u8]) -> Result<Vec<u8>, Error> {
6497 } ;
6598 Ok ( digest)
6699}
100+
101+ /// Convenience function for SHA-256 hash.
102+ ///
103+ /// # Errors
104+ ///
105+ /// Returns an error if NSS initialization fails or the hash operation fails.
106+ pub fn sha256 ( data : & [ u8 ] ) -> Result < [ u8 ; 32 ] , Error > {
107+ let digest = hash ( & HashAlgorithm :: SHA2_256 , data) ?;
108+ let mut result = [ 0u8 ; 32 ] ;
109+ result. copy_from_slice ( & digest) ;
110+ Ok ( result)
111+ }
112+
113+ /// Convenience function for SHA-384 hash.
114+ ///
115+ /// # Errors
116+ ///
117+ /// Returns an error if NSS initialization fails or the hash operation fails.
118+ pub fn sha384 ( data : & [ u8 ] ) -> Result < [ u8 ; 48 ] , Error > {
119+ let digest = hash ( & HashAlgorithm :: SHA2_384 , data) ?;
120+ let mut result = [ 0u8 ; 48 ] ;
121+ result. copy_from_slice ( & digest) ;
122+ Ok ( result)
123+ }
124+
125+ /// Convenience function for SHA-512 hash.
126+ ///
127+ /// # Errors
128+ ///
129+ /// Returns an error if NSS initialization fails or the hash operation fails.
130+ pub fn sha512 ( data : & [ u8 ] ) -> Result < [ u8 ; 64 ] , Error > {
131+ let digest = hash ( & HashAlgorithm :: SHA2_512 , data) ?;
132+ let mut result = [ 0u8 ; 64 ] ;
133+ result. copy_from_slice ( & digest) ;
134+ Ok ( result)
135+ }
136+
137+ /// Convenience function for SHA3-224 hash.
138+ ///
139+ /// # Errors
140+ ///
141+ /// Returns an error if NSS initialization fails or the hash operation fails.
142+ pub fn sha3_224 ( data : & [ u8 ] ) -> Result < [ u8 ; 28 ] , Error > {
143+ let digest = hash ( & HashAlgorithm :: SHA3_224 , data) ?;
144+ let mut result = [ 0u8 ; 28 ] ;
145+ result. copy_from_slice ( & digest) ;
146+ Ok ( result)
147+ }
148+
149+ /// Convenience function for SHA3-256 hash.
150+ ///
151+ /// # Errors
152+ ///
153+ /// Returns an error if NSS initialization fails or the hash operation fails.
154+ pub fn sha3_256 ( data : & [ u8 ] ) -> Result < [ u8 ; 32 ] , Error > {
155+ let digest = hash ( & HashAlgorithm :: SHA3_256 , data) ?;
156+ let mut result = [ 0u8 ; 32 ] ;
157+ result. copy_from_slice ( & digest) ;
158+ Ok ( result)
159+ }
160+
161+ /// Convenience function for SHA3-384 hash.
162+ ///
163+ /// # Errors
164+ ///
165+ /// Returns an error if NSS initialization fails or the hash operation fails.
166+ pub fn sha3_384 ( data : & [ u8 ] ) -> Result < [ u8 ; 48 ] , Error > {
167+ let digest = hash ( & HashAlgorithm :: SHA3_384 , data) ?;
168+ let mut result = [ 0u8 ; 48 ] ;
169+ result. copy_from_slice ( & digest) ;
170+ Ok ( result)
171+ }
172+
173+ /// Convenience function for SHA3-512 hash.
174+ ///
175+ /// # Errors
176+ ///
177+ /// Returns an error if NSS initialization fails or the hash operation fails.
178+ pub fn sha3_512 ( data : & [ u8 ] ) -> Result < [ u8 ; 64 ] , Error > {
179+ let digest = hash ( & HashAlgorithm :: SHA3_512 , data) ?;
180+ let mut result = [ 0u8 ; 64 ] ;
181+ result. copy_from_slice ( & digest) ;
182+ Ok ( result)
183+ }
184+
185+ #[ cfg( test) ]
186+ #[ cfg_attr( coverage_nightly, coverage( off) ) ]
187+ mod tests {
188+ use test_fixture:: fixture_init;
189+
190+ use super :: * ;
191+
192+ #[ test]
193+ fn test_sha256 ( ) {
194+ fixture_init ( ) ;
195+ let data = b"hello world" ;
196+ let digest = sha256 ( data) . unwrap ( ) ;
197+ assert_eq ! ( digest. len( ) , 32 ) ;
198+ // Known SHA-256 hash of "hello world"
199+ assert_eq ! (
200+ hex:: encode( digest) ,
201+ "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
202+ ) ;
203+ }
204+
205+ #[ test]
206+ fn test_sha384 ( ) {
207+ fixture_init ( ) ;
208+ let data = b"hello world" ;
209+ let digest = sha384 ( data) . unwrap ( ) ;
210+ assert_eq ! ( digest. len( ) , 48 ) ;
211+ }
212+
213+ #[ test]
214+ fn test_sha512 ( ) {
215+ fixture_init ( ) ;
216+ let data = b"hello world" ;
217+ let digest = sha512 ( data) . unwrap ( ) ;
218+ assert_eq ! ( digest. len( ) , 64 ) ;
219+ }
220+
221+ #[ test]
222+ fn test_sha3_224 ( ) {
223+ fixture_init ( ) ;
224+ let data = b"hello world" ;
225+ let digest = sha3_224 ( data) . unwrap ( ) ;
226+ assert_eq ! ( digest. len( ) , 28 ) ;
227+ }
228+
229+ #[ test]
230+ fn test_sha3_256 ( ) {
231+ fixture_init ( ) ;
232+ let data = b"hello world" ;
233+ let digest = sha3_256 ( data) . unwrap ( ) ;
234+ assert_eq ! ( digest. len( ) , 32 ) ;
235+ // Known SHA3-256 hash of "hello world"
236+ assert_eq ! (
237+ hex:: encode( digest) ,
238+ "644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938"
239+ ) ;
240+ }
241+
242+ #[ test]
243+ fn test_sha3_384 ( ) {
244+ fixture_init ( ) ;
245+ let data = b"hello world" ;
246+ let digest = sha3_384 ( data) . unwrap ( ) ;
247+ assert_eq ! ( digest. len( ) , 48 ) ;
248+ }
249+
250+ #[ test]
251+ fn test_sha3_512 ( ) {
252+ fixture_init ( ) ;
253+ let data = b"hello world" ;
254+ let digest = sha3_512 ( data) . unwrap ( ) ;
255+ assert_eq ! ( digest. len( ) , 64 ) ;
256+ }
257+
258+ #[ test]
259+ fn test_hash_empty ( ) {
260+ fixture_init ( ) ;
261+ let data = b"" ;
262+ let digest = sha256 ( data) . unwrap ( ) ;
263+ // Known SHA-256 hash of empty string
264+ assert_eq ! (
265+ hex:: encode( digest) ,
266+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
267+ ) ;
268+ }
269+
270+ #[ test]
271+ fn test_hash_algorithm_lengths ( ) {
272+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA2_256 ) , 32 ) ;
273+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA2_384 ) , 48 ) ;
274+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA2_512 ) , 64 ) ;
275+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA3_224 ) , 28 ) ;
276+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA3_256 ) , 32 ) ;
277+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA3_384 ) , 48 ) ;
278+ assert_eq ! ( hash_alg_to_hash_len( & HashAlgorithm :: SHA3_512 ) , 64 ) ;
279+ }
280+ }
0 commit comments