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