1
+ use masking:: PeekInterface ;
2
+ use ring:: hmac;
3
+
1
4
use crate :: error;
2
5
3
6
///
@@ -13,3 +16,172 @@ impl super::Encode<Vec<u8>, Vec<u8>> for Sha512 {
13
16
Ok ( digest. as_ref ( ) . to_vec ( ) )
14
17
}
15
18
}
19
+
20
+ ///
21
+ /// Type providing encoding functional to perform HMAC-SHA512 hashing
22
+ ///
23
+ /// # Example
24
+ ///
25
+ ///```
26
+ /// use tartarus::crypto::sha::HmacSha512;
27
+ /// use tartarus::crypto::Encode;
28
+ ///
29
+ /// let data = "Hello, World!";
30
+ /// let key = "key";
31
+ /// let algo = HmacSha512::<1>::new(key.as_bytes().to_vec().into());
32
+ /// let hash = algo.encode(data.as_bytes().to_vec()).unwrap();
33
+ ///
34
+ /// ```
35
+ ///
36
+ /// This will not compile if `N` is less than or equal to 0.
37
+ ///
38
+ /// ```compile_fail
39
+ ///
40
+ /// use tartarus::crypto::sha::HmacSha512;
41
+ /// use tartarus::crypto::Encode;
42
+ ///
43
+ /// let key = "key";
44
+ /// let algo = HmacSha512::<0>::new(key.as_bytes().to_vec().into());
45
+ ///
46
+ ///
47
+ /// ```
48
+ ///
49
+ ///
50
+ pub struct HmacSha512 < const N : usize = 1 > ( masking:: Secret < Vec < u8 > > ) ;
51
+
52
+ impl < const N : usize > HmacSha512 < N > {
53
+ pub fn new ( key : masking:: Secret < Vec < u8 > > ) -> Self {
54
+ #[ allow( clippy:: let_unit_value) ]
55
+ let _ = <Self as AssertGt0 >:: VALID ;
56
+
57
+ Self ( key)
58
+ }
59
+ }
60
+
61
+ impl < const N : usize > std:: fmt:: Display for HmacSha512 < N > {
62
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
63
+ write ! ( f, "HmacSha512<{}>" , N )
64
+ }
65
+ }
66
+
67
+ impl < const N : usize > super :: Encode < Vec < u8 > , Vec < u8 > > for HmacSha512 < N > {
68
+ type ReturnType < T > = Result < T , error:: ContainerError < error:: CryptoError > > ;
69
+
70
+ fn encode ( & self , input : Vec < u8 > ) -> Self :: ReturnType < Vec < u8 > > {
71
+ let key = hmac:: Key :: new ( ring:: hmac:: HMAC_SHA512 , self . 0 . peek ( ) ) ;
72
+ let first = hmac:: sign ( & key, & input) ;
73
+
74
+ let signature = ( 0 ..=( N - 1 ) ) . fold ( first, |input, _| hmac:: sign ( & key, input. as_ref ( ) ) ) ;
75
+
76
+ Ok ( signature. as_ref ( ) . to_vec ( ) )
77
+ }
78
+ }
79
+
80
+ trait AssertGt0 {
81
+ const VALID : ( ) ;
82
+ }
83
+
84
+ impl < const N : usize > AssertGt0 for HmacSha512 < N > {
85
+ const VALID : ( ) = assert ! ( N > 0 ) ;
86
+ }
87
+
88
+ #[ cfg( test) ]
89
+ mod tests {
90
+ #![ allow( clippy:: unwrap_used, clippy:: expect_used) ]
91
+ //!
92
+ //! Testing HMAC-SHA512 encoding consists of 3 variables.
93
+ //! 1. The input data
94
+ //! 2. The Key
95
+ //! 3. The `N` value
96
+ //!
97
+
98
+ use crate :: crypto:: Encode ;
99
+
100
+ use super :: * ;
101
+
102
+ #[ test]
103
+ fn test_input_data_equal ( ) {
104
+ let data1 = "Hello, World!" ;
105
+ let data2 = "Hello, World!" ;
106
+ let key = "key" ;
107
+
108
+ let algo = HmacSha512 :: < 1 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
109
+
110
+ let hash1 = algo. encode ( data1. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
111
+ let hash2 = algo. encode ( data2. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
112
+
113
+ assert_eq ! ( hash1, hash2) ;
114
+ }
115
+
116
+ #[ test]
117
+ fn test_input_data_not_equal ( ) {
118
+ let data1 = "Hello, World!" ;
119
+ let data2 = "Hello, world" ;
120
+ let key = "key" ;
121
+
122
+ let algo = HmacSha512 :: < 1 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
123
+
124
+ let hash1 = algo. encode ( data1. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
125
+ let hash2 = algo. encode ( data2. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
126
+
127
+ assert_ne ! ( hash1, hash2) ;
128
+ }
129
+
130
+ #[ test]
131
+ fn test_key_not_equal ( ) {
132
+ let data = "Hello, World!" ;
133
+ let key1 = "key1" ;
134
+ let key2 = "key2" ;
135
+
136
+ let algo1 = HmacSha512 :: < 1 > :: new ( key1. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
137
+ let algo2 = HmacSha512 :: < 1 > :: new ( key2. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
138
+
139
+ let hash1 = algo1. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
140
+ let hash2 = algo2. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
141
+
142
+ assert_ne ! ( hash1, hash2) ;
143
+ }
144
+
145
+ #[ test]
146
+ fn test_key_equal ( ) {
147
+ let data = "Hello, World!" ;
148
+ let key1 = "key" ;
149
+ let key2 = "key" ;
150
+
151
+ let algo1 = HmacSha512 :: < 1 > :: new ( key1. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
152
+ let algo2 = HmacSha512 :: < 1 > :: new ( key2. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
153
+
154
+ let hash1 = algo1. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
155
+ let hash2 = algo2. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
156
+
157
+ assert_eq ! ( hash1, hash2) ;
158
+ }
159
+
160
+ #[ test]
161
+ fn test_n_equal ( ) {
162
+ let data = "Hello, World!" ;
163
+ let key = "key" ;
164
+
165
+ let algo1 = HmacSha512 :: < 10 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
166
+ let algo2 = HmacSha512 :: < 10 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
167
+
168
+ let hash1 = algo1. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
169
+ let hash2 = algo2. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
170
+
171
+ assert_eq ! ( hash1, hash2) ;
172
+ }
173
+
174
+ #[ test]
175
+ fn test_n_not_equal ( ) {
176
+ let data = "Hello, World!" ;
177
+ let key = "key" ;
178
+
179
+ let algo1 = HmacSha512 :: < 10 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
180
+ let algo2 = HmacSha512 :: < 20 > :: new ( key. as_bytes ( ) . to_vec ( ) . into ( ) ) ;
181
+
182
+ let hash1 = algo1. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
183
+ let hash2 = algo2. encode ( data. as_bytes ( ) . to_vec ( ) ) . unwrap ( ) ;
184
+
185
+ assert_ne ! ( hash1, hash2) ;
186
+ }
187
+ }
0 commit comments