hw/ip/hmac/rtl/hmac_core.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // HMAC Core implementation
6:
7: module hmac_core import hmac_pkg::*; (
8: input clk_i,
9: input rst_ni,
10:
11: input [255:0] secret_key, // {word0, word1, ..., word7}
12:
13: input wipe_secret,
14: input [31:0] wipe_v,
15:
16: input hmac_en,
17:
18: input reg_hash_start,
19: input reg_hash_process,
20: output logic hash_done,
21: output logic sha_hash_start,
22: output logic sha_hash_process,
23: input sha_hash_done,
24:
25: // fifo
26: output logic sha_rvalid,
27: output sha_fifo_t sha_rdata,
28: input sha_rready,
29:
30: input fifo_rvalid,
31: input sha_fifo_t fifo_rdata,
32: output logic fifo_rready,
33:
34: // fifo control (select and fifo write data)
35: output logic fifo_wsel, // 0: from reg, 1: from digest
36: output logic fifo_wvalid,
37: output logic [2:0] fifo_wdata_sel, // 0: digest[0] .. 7: digest[7]
38: input fifo_wready,
39:
40: input [63:0] message_length,
41: output [63:0] sha_message_length
42: );
43:
44: localparam int unsigned BlockSize = 512;
45: localparam int unsigned BlockSizeBits = $clog2(BlockSize);
46: localparam int unsigned HashWordBits = $clog2($bits(sha_word_t));
47:
48: logic hash_start; // generated from internal state machine
49: logic hash_process; // generated from internal state machine to trigger hash
50: logic hmac_hash_done;
51:
52: logic [BlockSize-1:0] i_pad ;
53: logic [BlockSize-1:0] o_pad ;
54:
55: logic [63:0] txcount;
56: logic [BlockSizeBits-HashWordBits-1:0] pad_index;
57: logic clr_txcount, inc_txcount;
58:
59: logic hmac_sha_rvalid;
60:
61: typedef enum logic [1:0] {
62: SelIPad,
63: SelOPad,
64: SelFifo
65: } sel_rdata_t;
66:
67: sel_rdata_t sel_rdata;
68:
69: typedef enum logic {
70: SelIPadMsg,
71: SelOPadMsg
72: } sel_msglen_t;
73:
74: sel_msglen_t sel_msglen;
75:
76: typedef enum logic {
77: Inner, // Update when state goes to StIPad
78: Outer // Update when state enters StOPad
79: } round_t ;
80:
81: logic update_round ;
82: round_t round_q, round_d;
83:
84: typedef enum logic [2:0] {
85: StIdle,
86: StIPad,
87: StMsg, // Actual Msg, and Digest both
88: StPushToMsgFifo, // Digest --> Msg Fifo
89: StWaitResp, // Hash done( by checking processed_length? or hash_done)
90: StOPad,
91: StDone // hmac_done
92: } st_e ;
93:
94: st_e st_q, st_d;
95:
96: logic clr_fifo_wdata_sel;
97: logic txcnt_eq_blksz ;
98:
99: logic reg_hash_process_flag;
100:
101: assign sha_hash_start = (hmac_en) ? hash_start : reg_hash_start ;
102: assign sha_hash_process = (hmac_en) ? reg_hash_process | hash_process : reg_hash_process ;
103: assign hash_done = (hmac_en) ? hmac_hash_done : sha_hash_done ;
104:
105: assign pad_index = txcount[BlockSizeBits-1:HashWordBits];
106:
107: assign i_pad = {secret_key, {(BlockSize-256){1'b0}}} ^ {(BlockSize/8){8'h36}};
108: assign o_pad = {secret_key, {(BlockSize-256){1'b0}}} ^ {(BlockSize/8){8'h5c}};
109:
110:
111: assign fifo_rready = (hmac_en) ? (st_q == StMsg) & sha_rready : sha_rready ;
112: // sha_rvalid is controlled by State Machine below.
113: assign sha_rvalid = (!hmac_en) ? fifo_rvalid : hmac_sha_rvalid ;
114: assign sha_rdata =
115: (!hmac_en) ? fifo_rdata :
116: (sel_rdata == SelIPad) ? '{data: i_pad[(BlockSize-1)-32*pad_index-:32], mask: '1} :
117: (sel_rdata == SelOPad) ? '{data: o_pad[(BlockSize-1)-32*pad_index-:32], mask: '1} :
118: (sel_rdata == SelFifo) ? fifo_rdata :
119: '{default: '0};
120:
121: assign sha_message_length = (!hmac_en) ? message_length :
122: (sel_msglen == SelIPadMsg) ? message_length + BlockSize :
123: (sel_msglen == SelOPadMsg) ? BlockSize + 256 :
124: '0 ;
125:
126: assign txcnt_eq_blksz = (txcount[BlockSizeBits:0] == BlockSize);
127:
128: assign inc_txcount = sha_rready && sha_rvalid;
129:
130: // txcount
131: // Looks like txcount can be removed entirely here in hmac_core
132: // In the first round (InnerPaddedKey), it can just watch process and hash_done
133: // In the second round, it only needs count 256 bits for hash digest to trigger
134: // hash_process to SHA2
135: always_ff @(posedge clk_i or negedge rst_ni) begin
136: if (!rst_ni) begin
137: txcount <= '0;
138: end else if (clr_txcount) begin
139: txcount <= '0;
140: end else if (inc_txcount) begin
141: txcount[63:5] <= txcount[63:5] + 1'b1;
142: end
143: end
144:
145: // reg_hash_process trigger logic
146: always_ff @(posedge clk_i or negedge rst_ni) begin
147: if (!rst_ni) begin
148: reg_hash_process_flag <= 1'b0;
149: end else if (reg_hash_process) begin
150: reg_hash_process_flag <= 1'b1;
151: end else if (hmac_hash_done || reg_hash_start) begin
152: reg_hash_process_flag <= 1'b0;
153: end
154: end
155:
156: always_ff @(posedge clk_i or negedge rst_ni) begin
157: if (!rst_ni) begin
158: round_q <= Inner;
159: end else if (update_round) begin
160: round_q <= round_d;
161: end
162: end
163:
164: always_ff @(posedge clk_i or negedge rst_ni) begin
165: if (!rst_ni) begin
166: fifo_wdata_sel <= 3'h 0;
167: end else if (clr_fifo_wdata_sel) begin
168: fifo_wdata_sel <= 3'h 0;
169: end else if (fifo_wsel && fifo_wvalid) begin
170: fifo_wdata_sel <= fifo_wdata_sel + 1'b1;
171: end
172: end
173:
174: assign sel_msglen = (round_q == Inner) ? SelIPadMsg : SelOPadMsg ;
175:
176: always_ff @(posedge clk_i or negedge rst_ni) begin : state_ff
177: if (!rst_ni) st_q <= StIdle;
178: else st_q <= st_d;
179: end
180:
181: always_comb begin : next_state
182: hmac_hash_done = 1'b0;
183: hmac_sha_rvalid = 1'b0;
184:
185: clr_txcount = 1'b0;
186:
187: update_round = 1'b0;
188: round_d = Inner;
189:
190: fifo_wsel = 1'b0; // from register
191: fifo_wvalid = 1'b0;
192:
193: clr_fifo_wdata_sel = 1'b1;
194:
195: sel_rdata = SelFifo;
196:
197: hash_start = 1'b0;
198: hash_process = 1'b0;
199:
200: unique case (st_q)
201: StIdle: begin
202: if (hmac_en && reg_hash_start) begin
203: st_d = StIPad;
204:
205: clr_txcount = 1'b1;
206: update_round = 1'b1;
207: round_d = Inner;
208: hash_start = 1'b1;
209: end else begin
210: st_d = StIdle;
211: end
212: end
213:
214: StIPad: begin
215: sel_rdata = SelIPad;
216:
217: if (txcnt_eq_blksz) begin
218: st_d = StMsg;
219:
220: hmac_sha_rvalid = 1'b0; // block new read request
221: end else begin
222: st_d = StIPad;
223:
224: hmac_sha_rvalid = 1'b1;
225: end
226: end
227:
228: StMsg: begin
229: sel_rdata = SelFifo;
230:
231: if ( (((round_q == Inner) && reg_hash_process_flag) || (round_q == Outer))
232: && (txcount >= sha_message_length)) begin
233: st_d = StWaitResp;
234:
235: hmac_sha_rvalid = 1'b0; // block
236: hash_process = (round_q == Outer);
237: end else begin
238: st_d = StMsg;
239:
240: hmac_sha_rvalid = fifo_rvalid;
241: end
242: end
243:
244: StWaitResp: begin
245: hmac_sha_rvalid = 1'b0;
246:
247: if (sha_hash_done) begin
248: if (round_q == Outer) begin
249: st_d = StDone;
250: end else begin // round_q == Inner
251: st_d = StPushToMsgFifo;
252: end
253: end else begin
254: st_d = StWaitResp;
255: end
256: end
257:
258: StPushToMsgFifo: begin
259: hmac_sha_rvalid = 1'b0;
260: fifo_wsel = 1'b1;
261: fifo_wvalid = 1'b1;
262: clr_fifo_wdata_sel = 1'b0;
263:
264: if (fifo_wready && fifo_wdata_sel == 3'h7) begin
265: st_d = StOPad;
266:
267: clr_txcount = 1'b1;
268: update_round = 1'b1;
269: round_d = Outer;
270: hash_start = 1'b1;
271: end else begin
272: st_d = StPushToMsgFifo;
273:
274: end
275: end
276:
277: StOPad: begin
278: sel_rdata = SelOPad;
279:
280: if (txcnt_eq_blksz) begin
281: st_d = StMsg;
282:
283: hmac_sha_rvalid = 1'b0; // block new read request
284: end else begin
285: st_d = StOPad;
286:
287: hmac_sha_rvalid = 1'b1;
288: end
289: end
290:
291: StDone: begin
292: // raise interrupt (hash_done)
293: st_d = StIdle;
294:
295: hmac_hash_done = 1'b1;
296: end
297:
298: default: begin
299: st_d = StIdle;
300: end
301:
302: endcase
303: end
304: endmodule
305: