@@ -100,8 +100,9 @@ pub enum DataType {
100
100
101
101
/// Stores the state of the HASH peripheral for suspending/resuming
102
102
/// digest calculation.
103
- pub struct Context {
103
+ pub struct Context < ' c > {
104
104
first_word_sent : bool ,
105
+ key_sent : bool ,
105
106
buffer : [ u8 ; HASH_BUFFER_LEN ] ,
106
107
buflen : usize ,
107
108
algo : Algorithm ,
@@ -110,8 +111,11 @@ pub struct Context {
110
111
str : u32 ,
111
112
cr : u32 ,
112
113
csr : [ u32 ; NUM_CONTEXT_REGS ] ,
114
+ key : HmacKey < ' c > ,
113
115
}
114
116
117
+ type HmacKey < ' k > = Option < & ' k [ u8 ] > ;
118
+
115
119
/// HASH driver.
116
120
pub struct Hash < ' d , T : Instance , D = NoDma > {
117
121
_peripheral : PeripheralRef < ' d , T > ,
@@ -140,10 +144,11 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
140
144
}
141
145
142
146
/// Starts computation of a new hash and returns the saved peripheral state.
143
- pub fn start ( & mut self , algorithm : Algorithm , format : DataType ) -> Context {
147
+ pub fn start < ' c > ( & mut self , algorithm : Algorithm , format : DataType , key : HmacKey < ' c > ) -> Context < ' c > {
144
148
// Define a context for this new computation.
145
149
let mut ctx = Context {
146
150
first_word_sent : false ,
151
+ key_sent : false ,
147
152
buffer : [ 0 ; HASH_BUFFER_LEN ] ,
148
153
buflen : 0 ,
149
154
algo : algorithm,
@@ -152,6 +157,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
152
157
str : 0 ,
153
158
cr : 0 ,
154
159
csr : [ 0 ; NUM_CONTEXT_REGS ] ,
160
+ key,
155
161
} ;
156
162
157
163
// Set the data type in the peripheral.
@@ -181,6 +187,14 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
181
187
#[ cfg( any( hash_v3, hash_v4) ) ]
182
188
T :: regs ( ) . cr ( ) . modify ( |w| w. set_algo ( ctx. algo as u8 ) ) ;
183
189
190
+ // Configure HMAC mode if a key is provided.
191
+ if let Some ( key) = ctx. key {
192
+ T :: regs ( ) . cr ( ) . modify ( |w| w. set_mode ( true ) ) ;
193
+ if key. len ( ) > 64 {
194
+ T :: regs ( ) . cr ( ) . modify ( |w| w. set_lkey ( true ) ) ;
195
+ }
196
+ }
197
+
184
198
T :: regs ( ) . cr ( ) . modify ( |w| w. set_init ( true ) ) ;
185
199
186
200
// Store and return the state of the peripheral.
@@ -191,18 +205,30 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
191
205
/// Restores the peripheral state using the given context,
192
206
/// then updates the state with the provided data.
193
207
/// Peripheral state is saved upon return.
194
- pub fn update_blocking ( & mut self , ctx : & mut Context , input : & [ u8 ] ) {
208
+ pub fn update_blocking < ' c > ( & mut self , ctx : & mut Context < ' c > , input : & [ u8 ] ) {
209
+ // Restore the peripheral state.
210
+ self . load_context ( & ctx) ;
211
+
212
+ // Load the HMAC key if provided.
213
+ if !ctx. key_sent {
214
+ if let Some ( key) = ctx. key {
215
+ self . accumulate_blocking ( key) ;
216
+ T :: regs ( ) . str ( ) . write ( |w| w. set_dcal ( true ) ) ;
217
+ // Block waiting for digest.
218
+ while !T :: regs ( ) . sr ( ) . read ( ) . dinis ( ) { }
219
+ }
220
+ ctx. key_sent = true ;
221
+ }
222
+
195
223
let mut data_waiting = input. len ( ) + ctx. buflen ;
196
224
if data_waiting < DIGEST_BLOCK_SIZE || ( data_waiting < ctx. buffer . len ( ) && !ctx. first_word_sent ) {
197
225
// There isn't enough data to digest a block, so append it to the buffer.
198
226
ctx. buffer [ ctx. buflen ..ctx. buflen + input. len ( ) ] . copy_from_slice ( input) ;
199
227
ctx. buflen += input. len ( ) ;
228
+ self . store_context ( ctx) ;
200
229
return ;
201
230
}
202
231
203
- // Restore the peripheral state.
204
- self . load_context ( & ctx) ;
205
-
206
232
let mut ilen_remaining = input. len ( ) ;
207
233
let mut input_start = 0 ;
208
234
@@ -261,21 +287,30 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
261
287
/// then updates the state with the provided data.
262
288
/// Peripheral state is saved upon return.
263
289
#[ cfg( hash_v2) ]
264
- pub async fn update ( & mut self , ctx : & mut Context , input : & [ u8 ] )
290
+ pub async fn update < ' c > ( & mut self , ctx : & mut Context < ' c > , input : & [ u8 ] )
265
291
where
266
292
D : crate :: hash:: Dma < T > ,
267
293
{
294
+ // Restore the peripheral state.
295
+ self . load_context ( & ctx) ;
296
+
297
+ // Load the HMAC key if provided.
298
+ if !ctx. key_sent {
299
+ if let Some ( key) = ctx. key {
300
+ self . accumulate ( key) . await ;
301
+ }
302
+ ctx. key_sent = true ;
303
+ }
304
+
268
305
let data_waiting = input. len ( ) + ctx. buflen ;
269
306
if data_waiting < DIGEST_BLOCK_SIZE {
270
307
// There isn't enough data to digest a block, so append it to the buffer.
271
308
ctx. buffer [ ctx. buflen ..ctx. buflen + input. len ( ) ] . copy_from_slice ( input) ;
272
309
ctx. buflen += input. len ( ) ;
310
+ self . store_context ( ctx) ;
273
311
return ;
274
312
}
275
313
276
- // Restore the peripheral state.
277
- self . load_context ( & ctx) ;
278
-
279
314
// Enable multiple DMA transfers.
280
315
T :: regs ( ) . cr ( ) . modify ( |w| w. set_mdmat ( true ) ) ;
281
316
@@ -319,7 +354,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
319
354
/// The digest buffer must be large enough to accomodate a digest for the selected algorithm.
320
355
/// The largest returned digest size is 128 bytes for SHA-512.
321
356
/// Panics if the supplied digest buffer is too short.
322
- pub fn finish_blocking ( & mut self , mut ctx : Context , digest : & mut [ u8 ] ) -> usize {
357
+ pub fn finish_blocking < ' c > ( & mut self , mut ctx : Context < ' c > , digest : & mut [ u8 ] ) -> usize {
323
358
// Restore the peripheral state.
324
359
self . load_context ( & ctx) ;
325
360
@@ -330,7 +365,14 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
330
365
//Start the digest calculation.
331
366
T :: regs ( ) . str ( ) . write ( |w| w. set_dcal ( true ) ) ;
332
367
333
- // Block waiting for digest.
368
+ // Load the HMAC key if provided.
369
+ if let Some ( key) = ctx. key {
370
+ while !T :: regs ( ) . sr ( ) . read ( ) . dinis ( ) { }
371
+ self . accumulate_blocking ( key) ;
372
+ T :: regs ( ) . str ( ) . write ( |w| w. set_dcal ( true ) ) ;
373
+ }
374
+
375
+ // Block until digest computation is complete.
334
376
while !T :: regs ( ) . sr ( ) . read ( ) . dcis ( ) { }
335
377
336
378
// Return the digest.
@@ -370,7 +412,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
370
412
/// The largest returned digest size is 128 bytes for SHA-512.
371
413
/// Panics if the supplied digest buffer is too short.
372
414
#[ cfg( hash_v2) ]
373
- pub async fn finish ( & mut self , mut ctx : Context , digest : & mut [ u8 ] ) -> usize
415
+ pub async fn finish < ' c > ( & mut self , mut ctx : Context < ' c > , digest : & mut [ u8 ] ) -> usize
374
416
where
375
417
D : crate :: hash:: Dma < T > ,
376
418
{
@@ -384,6 +426,11 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
384
426
self . accumulate ( & ctx. buffer [ 0 ..ctx. buflen ] ) . await ;
385
427
ctx. buflen = 0 ;
386
428
429
+ // Load the HMAC key if provided.
430
+ if let Some ( key) = ctx. key {
431
+ self . accumulate ( key) . await ;
432
+ }
433
+
387
434
// Wait for completion.
388
435
poll_fn ( |cx| {
389
436
// Check if already done.
@@ -484,7 +531,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
484
531
}
485
532
486
533
/// Save the peripheral state to a context.
487
- fn store_context ( & mut self , ctx : & mut Context ) {
534
+ fn store_context < ' c > ( & mut self , ctx : & mut Context < ' c > ) {
488
535
// Block waiting for data in ready.
489
536
while !T :: regs ( ) . sr ( ) . read ( ) . dinis ( ) { }
490
537
0 commit comments