1 /******************************************************************************
2 * Filename: sha2.c
3 * Revised: 2020-09-14 11:12:36 +0200 (Mon, 14 Sep 2020)
4 * Revision: 58614
5 *
6 * Description: Driver for the SHA-2 functions of the crypto module
7 *
8 * Copyright (c) 2015 - 2020, Texas Instruments Incorporated
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * 1) Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * 2) Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 *
21 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
22 * be used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ******************************************************************************/
38
39 #include "sha2.h"
40
41 //*****************************************************************************
42 //
43 // Handle support for DriverLib in ROM:
44 // This section will undo prototype renaming made in the header file
45 //
46 //*****************************************************************************
47 #if !defined(DOXYGEN)
48 #undef SHA2StartDMAOperation
49 #define SHA2StartDMAOperation NOROM_SHA2StartDMAOperation
50 #undef SHA2WaitForIRQFlags
51 #define SHA2WaitForIRQFlags NOROM_SHA2WaitForIRQFlags
52 #undef SHA2ComputeInitialHash
53 #define SHA2ComputeInitialHash NOROM_SHA2ComputeInitialHash
54 #undef SHA2ComputeIntermediateHash
55 #define SHA2ComputeIntermediateHash NOROM_SHA2ComputeIntermediateHash
56 #undef SHA2ComputeFinalHash
57 #define SHA2ComputeFinalHash NOROM_SHA2ComputeFinalHash
58 #undef SHA2ComputeHash
59 #define SHA2ComputeHash NOROM_SHA2ComputeHash
60 #endif
61
62
63 static uint32_t SHA2ExecuteHash(const uint8_t *message, uint8_t *resultDigest, uint32_t *intermediateDigest, uint32_t totalMsgLength, uint32_t messageLength, uint32_t hashAlgorithm, bool initialHash, bool finalHash);
64
65
66 //*****************************************************************************
67 //
68 // Start a SHA-2 DMA operation.
69 //
70 //*****************************************************************************
SHA2StartDMAOperation(uint8_t * channel0Addr,uint32_t channel0Length,uint8_t * channel1Addr,uint32_t channel1Length)71 void SHA2StartDMAOperation(uint8_t *channel0Addr, uint32_t channel0Length, uint8_t *channel1Addr, uint32_t channel1Length)
72 {
73
74 // Clear any outstanding events.
75 HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = CRYPTO_IRQCLR_RESULT_AVAIL_M | CRYPTO_IRQEN_DMA_IN_DONE_M;
76
77 while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & (CRYPTO_IRQSTAT_DMA_IN_DONE_M | CRYPTO_IRQSTAT_RESULT_AVAIL_M));
78
79 if (channel0Addr) {
80 // Configure the DMA controller - enable both DMA channels.
81 HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH0CTL, CRYPTO_DMACH0CTL_EN_BITN) = 1;
82 // Base address of the payload data in ext. memory.
83 HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0EXTADDR) = (uint32_t)channel0Addr;
84
85 // Payload data length in bytes, equal to the cipher text length.
86 HWREG(CRYPTO_BASE + CRYPTO_O_DMACH0LEN) = channel0Length;
87 }
88
89 if (channel1Addr) {
90 // Enable DMA channel 1.
91 HWREGBITW(CRYPTO_BASE + CRYPTO_O_DMACH1CTL, CRYPTO_DMACH1CTL_EN_BITN) = 1;
92
93 // Base address of the output data buffer.
94 HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1EXTADDR) = (uint32_t)channel1Addr;
95
96 // Output data length in bytes, equal to the cipher text length.
97 HWREG(CRYPTO_BASE + CRYPTO_O_DMACH1LEN) = channel1Length;
98 }
99 }
100
101 //*****************************************************************************
102 //
103 // Poll the IRQ status register and return.
104 //
105 //*****************************************************************************
SHA2WaitForIRQFlags(uint32_t irqFlags)106 uint32_t SHA2WaitForIRQFlags(uint32_t irqFlags)
107 {
108 uint32_t irqTrigger = 0;
109 // Wait for the DMA operation to complete. Add a delay to make sure we are
110 // not flooding the bus with requests too much.
111 do {
112 CPUdelay(1);
113 }
114 while(!(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & irqFlags & (CRYPTO_IRQSTAT_DMA_IN_DONE_M | CRYPTO_IRQSTAT_RESULT_AVAIL_M)));
115
116 // Save the IRQ trigger source
117 irqTrigger = HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT);
118
119 // Clear IRQ flags
120 HWREG(CRYPTO_BASE + CRYPTO_O_IRQCLR) = irqFlags;
121
122 while(HWREG(CRYPTO_BASE + CRYPTO_O_IRQSTAT) & irqFlags & (CRYPTO_IRQSTAT_DMA_IN_DONE_M | CRYPTO_IRQSTAT_RESULT_AVAIL_M));
123
124 return irqTrigger;
125 }
126
127 //*****************************************************************************
128 //
129 // Start a new SHA-2 hash operation.
130 //
131 //*****************************************************************************
SHA2ComputeInitialHash(const uint8_t * message,uint32_t * intermediateDigest,uint32_t hashAlgorithm,uint32_t initialMessageLength)132 uint32_t SHA2ComputeInitialHash(const uint8_t *message, uint32_t *intermediateDigest, uint32_t hashAlgorithm, uint32_t initialMessageLength)
133 {
134 ASSERT(message);
135 ASSERT((hashAlgorithm == SHA2_MODE_SELECT_SHA224) ||
136 (hashAlgorithm == SHA2_MODE_SELECT_SHA256) ||
137 (hashAlgorithm == SHA2_MODE_SELECT_SHA384) ||
138 (hashAlgorithm == SHA2_MODE_SELECT_SHA512));
139 ASSERT(!(intermediateDigest == NULL) && !((uint32_t)intermediateDigest & 0x03));
140
141 return SHA2ExecuteHash(message, (uint8_t *)intermediateDigest, intermediateDigest, initialMessageLength, initialMessageLength, hashAlgorithm, true, false);
142 }
143
144 //*****************************************************************************
145 //
146 // Start an intermediate SHA-2 hash operation.
147 //
148 //*****************************************************************************
SHA2ComputeIntermediateHash(const uint8_t * message,uint32_t * intermediateDigest,uint32_t hashAlgorithm,uint32_t intermediateMessageLength)149 uint32_t SHA2ComputeIntermediateHash(const uint8_t *message, uint32_t *intermediateDigest, uint32_t hashAlgorithm, uint32_t intermediateMessageLength)
150 {
151 ASSERT(message);
152 ASSERT(!(intermediateDigest == NULL) && !((uint32_t)intermediateDigest & 0x03));
153 ASSERT((hashAlgorithm == SHA2_MODE_SELECT_SHA224) ||
154 (hashAlgorithm == SHA2_MODE_SELECT_SHA256) ||
155 (hashAlgorithm == SHA2_MODE_SELECT_SHA384) ||
156 (hashAlgorithm == SHA2_MODE_SELECT_SHA512));
157
158 return SHA2ExecuteHash(message, (uint8_t *)intermediateDigest, intermediateDigest, 0, intermediateMessageLength, hashAlgorithm, false, false);
159 }
160
161 //*****************************************************************************
162 //
163 // Start an intermediate SHA-2 hash operation and finalize it.
164 //
165 //*****************************************************************************
SHA2ComputeFinalHash(const uint8_t * message,uint8_t * resultDigest,uint32_t * intermediateDigest,uint32_t totalMsgLength,uint32_t messageLength,uint32_t hashAlgorithm)166 uint32_t SHA2ComputeFinalHash(const uint8_t *message, uint8_t *resultDigest, uint32_t *intermediateDigest, uint32_t totalMsgLength, uint32_t messageLength, uint32_t hashAlgorithm)
167 {
168 ASSERT(message);
169 ASSERT(totalMsgLength);
170 ASSERT(!(intermediateDigest == NULL) && !((uint32_t)intermediateDigest & 0x03));
171 ASSERT(resultDigest);
172 ASSERT((hashAlgorithm == SHA2_MODE_SELECT_SHA224) ||
173 (hashAlgorithm == SHA2_MODE_SELECT_SHA256) ||
174 (hashAlgorithm == SHA2_MODE_SELECT_SHA384) ||
175 (hashAlgorithm == SHA2_MODE_SELECT_SHA512));
176
177 return SHA2ExecuteHash(message, resultDigest, intermediateDigest, totalMsgLength, messageLength, hashAlgorithm, false, true);
178 }
179
180 //*****************************************************************************
181 //
182 // Start and finalize a new SHA-2 hash operation.
183 //
184 //*****************************************************************************
SHA2ComputeHash(const uint8_t * message,uint8_t * resultDigest,uint32_t totalMsgLength,uint32_t hashAlgorithm)185 uint32_t SHA2ComputeHash(const uint8_t *message, uint8_t *resultDigest, uint32_t totalMsgLength, uint32_t hashAlgorithm)
186 {
187 ASSERT(message);
188 ASSERT(totalMsgLength);
189 ASSERT(resultDigest);
190 ASSERT((hashAlgorithm == SHA2_MODE_SELECT_SHA224) ||
191 (hashAlgorithm == SHA2_MODE_SELECT_SHA256) ||
192 (hashAlgorithm == SHA2_MODE_SELECT_SHA384) ||
193 (hashAlgorithm == SHA2_MODE_SELECT_SHA512));
194
195 return SHA2ExecuteHash(message, resultDigest, 0, totalMsgLength, totalMsgLength, hashAlgorithm, true, true);
196 }
197
198 //*****************************************************************************
199 //
200 // Start any SHA-2 hash operation.
201 //
202 //*****************************************************************************
SHA2ExecuteHash(const uint8_t * message,uint8_t * resultDigest,uint32_t * intermediateDigest,uint32_t totalMsgLength,uint32_t messageLength,uint32_t hashAlgorithm,bool initialHash,bool finalHash)203 static uint32_t SHA2ExecuteHash(const uint8_t *message, uint8_t *resultDigest, uint32_t *intermediateDigest, uint32_t totalMsgLength, uint32_t messageLength, uint32_t hashAlgorithm, bool initialHash, bool finalHash)
204 {
205 uint8_t digestLength = 0;
206 uint32_t dmaAlgorithmSelect = 0;
207
208 SHA2ClearDigestAvailableFlag();
209
210 switch (hashAlgorithm) {
211 case SHA2_MODE_SELECT_SHA224:
212 digestLength = SHA2_SHA224_DIGEST_LENGTH_BYTES;
213 dmaAlgorithmSelect = SHA2_ALGSEL_SHA256;
214 break;
215 case SHA2_MODE_SELECT_SHA256:
216 digestLength = SHA2_SHA256_DIGEST_LENGTH_BYTES;
217 dmaAlgorithmSelect = SHA2_ALGSEL_SHA256;
218 break;
219 case SHA2_MODE_SELECT_SHA384:
220 digestLength = SHA2_SHA384_DIGEST_LENGTH_BYTES;
221 dmaAlgorithmSelect = SHA2_ALGSEL_SHA512;
222 break;
223 case SHA2_MODE_SELECT_SHA512:
224 digestLength = SHA2_SHA512_DIGEST_LENGTH_BYTES;
225 dmaAlgorithmSelect = SHA2_ALGSEL_SHA512;
226 break;
227 default:
228 return SHA2_INVALID_ALGORITHM;
229 }
230
231 if (initialHash && finalHash) {
232 // The empty string is a perfectly valid message. It obviously has a length of 0. The DMA cannot
233 // handle running with a transfer length of 0. This workaround depends on the hash engine adding the
234 // trailing 1 bit and 0-padding bits after the DMAtransfer is complete and not in the DMA itself.
235 // totalMsgLength is purposefully not altered as it is appended to the end of the message during finalization
236 // and determines how many padding-bytes are added.
237 // Altering totalMsgLength would alter the final hash digest.
238 // Because totalMsgLength specifies that the message is of length 0, the content of the byte loaded
239 // through the DMA is irrelevant. It is overwritten internally in the hash engine.
240 messageLength = messageLength ? messageLength : 1;
241 }
242
243 // Setting the incorrect number of bits here leads to the calculation of the correct result
244 // but a failure to read them out.
245 // The tag bit is set to read out the digest via DMA rather than through the slave interface.
246 SHA2SelectAlgorithm(dmaAlgorithmSelect | (resultDigest ? SHA2_ALGSEL_TAG : 0));
247 SHA2IntClear(SHA2_DMA_IN_DONE | SHA2_RESULT_RDY);
248 SHA2IntEnable(SHA2_DMA_IN_DONE | SHA2_RESULT_RDY);
249
250 HWREG(CRYPTO_BASE + CRYPTO_O_HASHMODE) = hashAlgorithm | (initialHash ? CRYPTO_HASHMODE_NEW_HASH_M : 0);
251
252 // Only load the intermediate digest if requested.
253 if (intermediateDigest && !initialHash) {
254 SHA2SetDigest(intermediateDigest, digestLength);
255 }
256
257 // If this is the final hash, finalization is required. This means appending a 1 bit, padding the message until this section
258 // is 448 bytes long, and adding the 64 bit total length of the message in bits. Thankfully, this is all done in hardware.
259 if (finalHash) {
260 // This specific length must be specified in bits not bytes.
261 SHA2SetMessageLength(totalMsgLength * 8);
262 HWREG(CRYPTO_BASE + CRYPTO_O_HASHIOBUFCTRL) = CRYPTO_HASHIOBUFCTRL_PAD_DMA_MESSAGE_M;
263
264 }
265
266 // The cast is fine in this case. SHA2StartDMAOperation channel one serves as input and no one does
267 // hash operations in-place.
268 SHA2StartDMAOperation((uint8_t *)message, messageLength, resultDigest, digestLength);
269
270 return SHA2_SUCCESS;
271 }
272