1 /*
2 * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "cc3xx_internal_chacha20.h"
9
10 #include "cc_pal_types.h"
11 #include "cc_pal_mem.h"
12 #include "cc_pal_abort.h"
13
14 /** \file cc3xx_internal_chacha20.c
15 *
16 * This file contains the implementation of the internal functions to
17 * perform symmetric encryption and decryption using the Chacha20
18 * algorithm
19 *
20 */
21
22 /* This function interacts directly with the low level driver module */
chacha_block(ChachaContext_t * ctx,const uint8_t * input,uint8_t * output,size_t size)23 static psa_status_t chacha_block(ChachaContext_t *ctx, const uint8_t *input,
24 uint8_t *output, size_t size)
25 {
26 drvError_t drvRc;
27 CCBuffInfo_t inBuffInfo;
28 CCBuffInfo_t outBuffInfo;
29
30 drvRc = SetDataBuffersInfo(input, size, &inBuffInfo,
31 output, size, &outBuffInfo);
32 if (drvRc != 0) {
33 CC_PAL_LOG_ERR("Bad I/O buffers");
34 return PSA_ERROR_INVALID_ARGUMENT;
35 }
36
37 drvRc = ProcessChacha(ctx, &inBuffInfo, &outBuffInfo, size);
38 if (drvRc != 0) {
39 CC_PAL_LOG_ERR("cc3xx_chacha20_update failed: %d", drvRc);
40 return PSA_ERROR_INVALID_ARGUMENT;
41 }
42
43 return PSA_SUCCESS;
44 }
45
46 /** \defgroup internal_chacha20 Internal Chacha20 functions
47 *
48 * Internal functions used by the driver to perform Chacha20 cipher encryption
49 * and decryption
50 *
51 * @{
52 */
cc3xx_chacha20_init(ChachaContext_t * ctx)53 void cc3xx_chacha20_init(ChachaContext_t *ctx)
54 {
55 if (NULL == ctx) {
56 CC_PAL_LOG_ERR("ctx cannot be NULL");
57 return;
58 }
59
60 CC_PalMemSet(ctx, 0, sizeof(ChachaContext_t));
61
62 ctx->inputDataAddrType = DLLI_ADDR;
63 ctx->outputDataAddrType = DLLI_ADDR;
64
65 /* valid range is [0; CHACHA_BLOCK_SIZE_BYTES), while
66 * CHACHA_BLOCK_SIZE_BYTES indicates empty state
67 */
68 ctx->state.keystream_start = CHACHA_BLOCK_SIZE_BYTES;
69 }
70
cc3xx_chacha20_free(ChachaContext_t * ctx)71 void cc3xx_chacha20_free(ChachaContext_t *ctx)
72 {
73 if (NULL == ctx) {
74 CC_PAL_LOG_ERR("ctx cannot be NULL");
75 return;
76 }
77
78 CC_PalMemSet(ctx, 0, sizeof(ChachaContext_t));
79 }
80
cc3xx_chacha20_setkey(ChachaContext_t * ctx,const uint8_t * key,size_t key_size)81 psa_status_t cc3xx_chacha20_setkey(
82 ChachaContext_t *ctx,
83 const uint8_t *key,
84 size_t key_size)
85 {
86 if (ctx == NULL || key == NULL || key_size != CHACHA_256_BIT_KEY_SIZE) {
87 return PSA_ERROR_INVALID_ARGUMENT;
88 }
89
90 CC_PalMemCopy(ctx->keyBuf, key, CHACHA_256_BIT_KEY_SIZE);
91
92 return PSA_SUCCESS;
93 }
94
cc3xx_chacha20_set_nonce(ChachaContext_t * ctx,const uint8_t * nonce,size_t nonce_size)95 psa_status_t cc3xx_chacha20_set_nonce(ChachaContext_t *ctx,
96 const uint8_t *nonce,
97 size_t nonce_size)
98 {
99 if (ctx == NULL || nonce == NULL || nonce_size != CHACHA_IV_96_SIZE_BYTES) {
100 return PSA_ERROR_INVALID_ARGUMENT;
101 }
102 ctx->nonceSize = NONCE_SIZE_96;
103 CC_PalMemCopy(ctx->nonceBuf, nonce, CHACHA_IV_96_SIZE_BYTES);
104
105 return PSA_SUCCESS;
106 }
107
cc3xx_chacha20_set_counter(ChachaContext_t * ctx,uint32_t counter)108 psa_status_t cc3xx_chacha20_set_counter(ChachaContext_t *ctx,
109 uint32_t counter)
110 {
111 if (ctx == NULL) {
112 return PSA_ERROR_INVALID_ARGUMENT;
113 }
114 ctx->blockCounterLsb = counter;
115 ctx->blockCounterMsb = 0;
116
117 /* Calling set_counter has the effect of resetting any
118 * ongoing operation
119 */
120 ctx->state.keystream_start = CHACHA_BLOCK_SIZE_BYTES;
121
122 return PSA_SUCCESS;
123 }
124
cc3xx_chacha20_update(ChachaContext_t * ctx,const uint8_t * input,size_t input_len,uint8_t * output,size_t output_size,size_t * output_len)125 psa_status_t cc3xx_chacha20_update(
126 ChachaContext_t *ctx,
127 const uint8_t *input,
128 size_t input_len,
129 uint8_t *output,
130 size_t output_size,
131 size_t *output_len)
132 {
133 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
134
135 if ((ctx == NULL) || (input == NULL) || (output == NULL) || (output_len == NULL)) {
136 CC_PAL_LOG_ERR("Null pointer exception");
137 return PSA_ERROR_INVALID_ARGUMENT;
138 }
139 *output_len = 0;
140
141 if (input_len == 0) {
142 return PSA_SUCCESS;
143 }
144
145 if (output_size < input_len) {
146 return PSA_ERROR_BUFFER_TOO_SMALL;
147 }
148
149 /* If there is some outstanding state we need to process that first */
150 uint8_t keystream_size =
151 (CHACHA_BLOCK_SIZE_BYTES - ctx->state.keystream_start) > 0 ?
152 (CHACHA_BLOCK_SIZE_BYTES - ctx->state.keystream_start) : 0;
153 size_t size_to_process = keystream_size < input_len ?
154 keystream_size : input_len;
155 if (size_to_process) {
156 for (int i=0; i<size_to_process; i++) {
157 output[i] =
158 ctx->state.keystream[i+ctx->state.keystream_start] ^ input[i];
159 }
160 ctx->state.keystream_start += size_to_process;
161 input_len -= size_to_process;
162 (*output_len) += size_to_process;
163
164 if (input_len == 0) {
165 return PSA_SUCCESS;
166 }
167 }
168
169 size_t process_len =
170 (input_len/CHACHA_BLOCK_SIZE_BYTES)*CHACHA_BLOCK_SIZE_BYTES;
171 if (process_len) {
172 status = chacha_block(ctx, &input[size_to_process],
173 &output[size_to_process], process_len);
174 if (status != PSA_SUCCESS) {
175 *output_len = 0;
176 return status;
177 }
178 (*output_len) += process_len;
179 }
180
181 /* Store the last part of the data that couldn't be processed as separate
182 * block
183 */
184 if (input_len - process_len) {
185 /* Generate a keystream block to keep as state */
186 uint8_t all_zero_input[CHACHA_BLOCK_SIZE_BYTES] = {0};
187 status = chacha_block(ctx, all_zero_input, ctx->state.keystream,
188 CHACHA_BLOCK_SIZE_BYTES);
189 if (status != PSA_SUCCESS) {
190 *output_len = 0;
191 return status;
192 }
193
194 for (int i=0; i<input_len-process_len; i++) {
195 output[i+size_to_process+process_len] =
196 ctx->state.keystream[i] ^ input[i+size_to_process+process_len];
197 }
198
199 (*output_len) += (input_len-process_len);
200
201 /* Update the pointer to the start of the unprocessed keystream */
202 ctx->state.keystream_start = (input_len-process_len);
203 }
204
205 return status;
206 }
207
cc3xx_chacha20_finish(ChachaContext_t * ctx,uint8_t * output,size_t output_size,size_t * output_length)208 psa_status_t cc3xx_chacha20_finish(
209 ChachaContext_t *ctx,
210 uint8_t *output,
211 size_t output_size,
212 size_t *output_length)
213 {
214 (void)ctx;
215 (void)output;
216 (void)output_size;
217 if (output_length == NULL) {
218 return PSA_ERROR_INVALID_ARGUMENT;
219 }
220
221 *output_length = 0;
222
223 return PSA_SUCCESS;
224 }
225 /** @} */ // end of internal_chacha20
226