Contiki-NG
sha256.c
Go to the documentation of this file.
1/*
2 * Original file:
3 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
4 * All rights reserved.
5 *
6 * Port to Contiki:
7 * Copyright (c) 2013, ADVANSEE - http://www.advansee.com/
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36/**
37 * \addtogroup cc2538-sha256
38 * @{
39 *
40 * \file
41 * Implementation of the cc2538 SHA-256 driver
42 */
43#include "contiki.h"
44#include "sys/cc.h"
45#include "dev/rom-util.h"
46#include "dev/aes.h"
47#include "dev/sha256.h"
48#include "reg.h"
49
50#include <stdbool.h>
51#include <stdint.h>
52/*---------------------------------------------------------------------------*/
53#define BLOCK_SIZE 64
54#define OUTPUT_LEN 32
55/*---------------------------------------------------------------------------*/
56/** \brief Starts a new hash session in hardware
57 * \param state Hash state
58 * \param data Pointer to input message
59 * \param hash Destination of the hash (32 bytes)
60 * \return \c CRYPTO_SUCCESS if successful, or CRYPTO/SHA256 error code
61 */
62static uint8_t
63new_hash(sha256_state_t *state, const void *data, void *hash)
64{
65 /* Workaround for AES registers not retained after PM2 */
69
70 /* Configure master control module and enable DMA path to the SHA-256 engine
71 * + Digest readout */
73
74 /* Clear any outstanding events */
76
77 /* Configure hash engine
78 * Indicate start of a new hash session and SHA-256 */
81
82 /* If the final digest is required (pad the input DMA data), write the
83 * following register */
84 if(state->final_digest) {
85 /* Write length of the message (lo) */
86 REG(AES_HASH_LENGTH_IN_L) = (uint32_t)state->length;
87 /* Write length of the message (hi) */
88 REG(AES_HASH_LENGTH_IN_H) = (uint32_t)(state->length >> 32);
89 /* Pad the DMA-ed data */
91 }
92
93 /* Enable DMA channel 0 for message data */
95 /* Base address of the data in ext. memory */
96 REG(AES_DMAC_CH0_EXTADDR) = (uint32_t)data;
97 if(state->final_digest) {
98 /* Input data length in bytes, equal to the message */
99 REG(AES_DMAC_CH0_DMALENGTH) = state->curlen;
100 } else {
101 REG(AES_DMAC_CH0_DMALENGTH) = BLOCK_SIZE;
102 }
103
104 /* Enable DMA channel 1 for result digest */
106 /* Base address of the digest buffer */
107 REG(AES_DMAC_CH1_EXTADDR) = (uint32_t)hash;
108 /* Length of the result digest */
109 REG(AES_DMAC_CH1_DMALENGTH) = OUTPUT_LEN;
110
111 /* Wait for completion of the operation */
113
115 /* Clear the DMA error */
117 /* Disable master control / DMA clock */
118 REG(AES_CTRL_ALG_SEL) = 0x00000000;
119 return CRYPTO_DMA_BUS_ERROR;
120 }
121
122 /* Clear the interrupt */
125 /* Disable master control / DMA clock */
126 REG(AES_CTRL_ALG_SEL) = 0x00000000;
127 /* Clear mode */
128 REG(AES_AES_CTRL) = 0x00000000;
129
130 return CRYPTO_SUCCESS;
131}
132/*---------------------------------------------------------------------------*/
133/** \brief Resumes an already started hash session in hardware
134 * \param state Hash state
135 * \param data Pointer to the input message
136 * \param hash Pointer to the destination of the hash (32 bytes)
137 * \return \c CRYPTO_SUCCESS if successful, or CRYPTO/SHA256 error code
138 */
139static uint8_t
140resume_hash(sha256_state_t *state, const void *data, void *hash)
141{
142 /* Workaround for AES registers not retained after PM2 */
146
147 /* Configure master control module and enable the DMA path to the SHA-256
148 * engine */
150
151 /* Clear any outstanding events */
153
154 /* Configure hash engine
155 * Indicate the start of a resumed hash session and SHA-256 */
157
158 /* If the final digest is required (pad the input DMA data) */
159 if(state->final_digest) {
160 /* Write length of the message (lo) */
161 REG(AES_HASH_LENGTH_IN_L) = (uint32_t)state->length;
162 /* Write length of the message (hi) */
163 REG(AES_HASH_LENGTH_IN_H) = (uint32_t)(state->length >> 32);
164 }
165
166 /* Write the initial digest */
167 REG(AES_HASH_DIGEST_A) = (uint32_t)state->state[0];
168 REG(AES_HASH_DIGEST_B) = (uint32_t)state->state[1];
169 REG(AES_HASH_DIGEST_C) = (uint32_t)state->state[2];
170 REG(AES_HASH_DIGEST_D) = (uint32_t)state->state[3];
171 REG(AES_HASH_DIGEST_E) = (uint32_t)state->state[4];
172 REG(AES_HASH_DIGEST_F) = (uint32_t)state->state[5];
173 REG(AES_HASH_DIGEST_G) = (uint32_t)state->state[6];
174 REG(AES_HASH_DIGEST_H) = (uint32_t)state->state[7];
175
176 /* If final digest, pad the DMA-ed data */
177 if(state->final_digest) {
179 }
180
181 /* Enable DMA channel 0 for message data */
183 /* Base address of the data in ext. memory */
184 REG(AES_DMAC_CH0_EXTADDR) = (uint32_t)data;
185 /* Input data length in bytes, equal to the message */
186 if(state->final_digest) {
187 REG(AES_DMAC_CH0_DMALENGTH) = state->curlen;
188 } else {
189 REG(AES_DMAC_CH0_DMALENGTH) = BLOCK_SIZE;
190 }
191
192 /* Wait for completion of the operation */
194
195 /* Check for any DMA Bus errors */
197 /* Clear the DMA error */
199 /* Disable master control / DMA clock */
200 REG(AES_CTRL_ALG_SEL) = 0x00000000;
201 return CRYPTO_DMA_BUS_ERROR;
202 }
203
204 /* Read digest */
205 ((uint32_t *)hash)[0] = REG(AES_HASH_DIGEST_A);
206 ((uint32_t *)hash)[1] = REG(AES_HASH_DIGEST_B);
207 ((uint32_t *)hash)[2] = REG(AES_HASH_DIGEST_C);
208 ((uint32_t *)hash)[3] = REG(AES_HASH_DIGEST_D);
209 ((uint32_t *)hash)[4] = REG(AES_HASH_DIGEST_E);
210 ((uint32_t *)hash)[5] = REG(AES_HASH_DIGEST_F);
211 ((uint32_t *)hash)[6] = REG(AES_HASH_DIGEST_G);
212 ((uint32_t *)hash)[7] = REG(AES_HASH_DIGEST_H);
213
214 /* Acknowledge reading of the digest */
216
217 /* Clear the interrupt */
220 /* Disable master control / DMA clock */
221 REG(AES_CTRL_ALG_SEL) = 0x00000000;
222 /* Clear mode */
223 REG(AES_AES_CTRL) = 0x00000000;
224
225 return CRYPTO_SUCCESS;
226}
227/*---------------------------------------------------------------------------*/
228uint8_t
229sha256_init(sha256_state_t *state)
230{
231 if(state == NULL) {
232 return CRYPTO_NULL_ERROR;
233 }
234
235 state->curlen = 0;
236 state->length = 0;
237 state->new_digest = true;
238 state->final_digest = false;
239 return CRYPTO_SUCCESS;
240}
241/*---------------------------------------------------------------------------*/
242uint8_t
243sha256_process(sha256_state_t *state, const void *data, uint32_t len)
244{
245 uint32_t n;
246 uint8_t ret;
247
248 if(state == NULL || data == NULL) {
249 return CRYPTO_NULL_ERROR;
250 }
251
252 if(state->curlen > sizeof(state->buf)) {
253 return CRYPTO_INVALID_PARAM;
254 }
255
256 if(REG(AES_CTRL_ALG_SEL) != 0x00000000) {
257 return CRYPTO_RESOURCE_IN_USE;
258 }
259
260 if(len > 0 && state->new_digest) {
261 if(state->curlen == 0 && len > BLOCK_SIZE) {
262 rom_util_memcpy(state->buf, data, BLOCK_SIZE);
263 ret = new_hash(state, state->buf, state->state);
264 if(ret != CRYPTO_SUCCESS) {
265 return ret;
266 }
267 state->new_digest = false;
268 state->length += BLOCK_SIZE << 3;
269 data += BLOCK_SIZE;
270 len -= BLOCK_SIZE;
271 } else {
272 n = MIN(len, BLOCK_SIZE - state->curlen);
273 rom_util_memcpy(&state->buf[state->curlen], data, n);
274 state->curlen += n;
275 data += n;
276 len -= n;
277 if(state->curlen == BLOCK_SIZE && len > 0) {
278 ret = new_hash(state, state->buf, state->state);
279 if(ret != CRYPTO_SUCCESS) {
280 return ret;
281 }
282 state->new_digest = false;
283 state->length += BLOCK_SIZE << 3;
284 state->curlen = 0;
285 }
286 }
287 }
288
289 while(len > 0 && !state->new_digest) {
290 if(state->curlen == 0 && len > BLOCK_SIZE) {
291 rom_util_memcpy(state->buf, data, BLOCK_SIZE);
292 ret = resume_hash(state, state->buf, state->state);
293 if(ret != CRYPTO_SUCCESS) {
294 return ret;
295 }
296 state->length += BLOCK_SIZE << 3;
297 data += BLOCK_SIZE;
298 len -= BLOCK_SIZE;
299 } else {
300 n = MIN(len, BLOCK_SIZE - state->curlen);
301 rom_util_memcpy(&state->buf[state->curlen], data, n);
302 state->curlen += n;
303 data += n;
304 len -= n;
305 if(state->curlen == BLOCK_SIZE && len > 0) {
306 ret = resume_hash(state, state->buf, state->state);
307 if(ret != CRYPTO_SUCCESS) {
308 return ret;
309 }
310 state->length += BLOCK_SIZE << 3;
311 state->curlen = 0;
312 }
313 }
314 }
315
316 return CRYPTO_SUCCESS;
317}
318/*---------------------------------------------------------------------------*/
319uint8_t
320sha256_done(sha256_state_t *state, void *hash)
321{
322 uint8_t ret;
323
324 if(state == NULL || hash == NULL) {
325 return CRYPTO_NULL_ERROR;
326 }
327
328 if(state->curlen > sizeof(state->buf)) {
329 return CRYPTO_INVALID_PARAM;
330 }
331
332 if(REG(AES_CTRL_ALG_SEL) != 0x00000000) {
333 return CRYPTO_RESOURCE_IN_USE;
334 }
335
336 /* Increase the length of the message */
337 state->length += state->curlen << 3;
338 state->final_digest = true;
339 if(state->new_digest) {
340 ret = new_hash(state, state->buf, hash);
341 if(ret != CRYPTO_SUCCESS) {
342 return ret;
343 }
344 } else {
345 ret = resume_hash(state, state->buf, hash);
346 if(ret != CRYPTO_SUCCESS) {
347 return ret;
348 }
349 }
350 state->new_digest = false;
351 state->final_digest = false;
352
353 return CRYPTO_SUCCESS;
354}
355
356/** @} */
Header file for the cc2538 AES driver.
Default definitions of C compiler quirk work-arounds.
#define AES_CTRL_INT_CLR
Interrupt clear.
Definition: aes.h:135
#define AES_CTRL_INT_CLR_DMA_BUS_ERR
Clear DMA bus error status.
Definition: aes.h:381
#define AES_HASH_DIGEST_C
Hash digest.
Definition: aes.h:124
#define AES_DMAC_CH1_CTRL
Channel 1 control.
Definition: aes.h:65
#define AES_CTRL_INT_CFG
Interrupt configuration.
Definition: aes.h:133
#define AES_CTRL_INT_CFG_LEVEL
Level interrupt type.
Definition: aes.h:366
#define AES_DMAC_CH1_DMALENGTH
Channel 1 DMA length.
Definition: aes.h:67
#define AES_HASH_IO_BUF_CTRL_PAD_DMA_MESSAGE
Hash engine message padding required.
Definition: aes.h:316
#define AES_CTRL_INT_EN_DMA_IN_DONE
DMA input done interrupt enabled.
Definition: aes.h:372
#define AES_AES_CTRL
AES input/output buffer control and mode.
Definition: aes.h:90
#define AES_CTRL_ALG_SEL_HASH
Select hash engine as DMA destination.
Definition: aes.h:343
#define AES_CTRL_INT_STAT_DMA_BUS_ERR
DMA bus error detected.
Definition: aes.h:405
#define AES_HASH_DIGEST_D
Hash digest.
Definition: aes.h:125
#define AES_HASH_DIGEST_E
Hash digest.
Definition: aes.h:126
#define AES_CTRL_ALG_SEL_TAG
DMA operation includes TAG.
Definition: aes.h:342
#define AES_HASH_LENGTH_IN_L
Hash length.
Definition: aes.h:120
#define AES_HASH_DIGEST_A
Hash digest.
Definition: aes.h:122
#define AES_DMAC_CH0_CTRL
Channel 0 control.
Definition: aes.h:60
#define AES_DMAC_CH_CTRL_EN
Channel enable.
Definition: aes.h:146
#define AES_HASH_MODE_IN_NEW_HASH
New hash session.
Definition: aes.h:335
#define AES_HASH_DIGEST_H
Hash digest.
Definition: aes.h:129
#define AES_HASH_LENGTH_IN_H
Hash length.
Definition: aes.h:121
#define AES_CTRL_INT_CLR_DMA_IN_DONE
Clear DMA in done interrupt.
Definition: aes.h:387
#define AES_DMAC_CH0_EXTADDR
Channel 0 external address.
Definition: aes.h:61
#define AES_CTRL_INT_EN_RESULT_AV
Result available interrupt enabled.
Definition: aes.h:374
#define AES_DMAC_CH1_EXTADDR
Channel 1 external address.
Definition: aes.h:66
#define AES_HASH_DIGEST_G
Hash digest.
Definition: aes.h:128
#define AES_HASH_MODE_IN_SHA256_MODE
Hash mode.
Definition: aes.h:333
#define AES_HASH_IO_BUF_CTRL_OUTPUT_FULL
Output buffer registers available.
Definition: aes.h:326
#define AES_HASH_DIGEST_F
Hash digest.
Definition: aes.h:127
#define AES_CTRL_INT_CLR_RESULT_AV
Clear result available interrupt.
Definition: aes.h:389
#define AES_HASH_IO_BUF_CTRL
Input/output buffer control and status.
Definition: aes.h:118
#define AES_HASH_MODE_IN
Hash mode.
Definition: aes.h:119
#define AES_CTRL_ALG_SEL
Algorithm select.
Definition: aes.h:130
#define AES_CTRL_INT_STAT
Interrupt status.
Definition: aes.h:137
#define AES_DMAC_CH0_DMALENGTH
Channel 0 DMA length.
Definition: aes.h:62
#define AES_CTRL_INT_EN
Interrupt enable.
Definition: aes.h:134
#define AES_HASH_DIGEST_B
Hash digest.
Definition: aes.h:123
#define AES_CTRL_INT_STAT_RESULT_AV
Result available interrupt status.
Definition: aes.h:413
static uint8_t resume_hash(sha256_state_t *state, const void *data, void *hash)
Resumes an already started hash session in hardware.
Definition: sha256.c:140
static uint8_t new_hash(sha256_state_t *state, const void *data, void *hash)
Starts a new hash session in hardware.
Definition: sha256.c:63
uint8_t sha256_done(sha256_state_t *state, void *hash)
Terminates hash session to get the digest.
Definition: sha256.c:320
uint8_t sha256_init(sha256_state_t *state)
Initializes the hash state.
Definition: sha256.c:229
uint8_t sha256_process(sha256_state_t *state, const void *data, uint32_t len)
Processes a block of memory through the hash.
Definition: sha256.c:243
Header file with register manipulation macro definitions.
Header file for the cc2538 ROM utility function library driver.
Header file for the cc2538 SHA-256 driver.