Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
chacha.c
00001 /** 00002 * @file chacha.c 00003 * @brief ChaCha encryption algorithm 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneCrypto Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include "crypto.h" 00034 #include "chacha.h" 00035 00036 //Check crypto library configuration 00037 #if (CHACHA_SUPPORT == ENABLED) 00038 00039 //ChaCha quarter-round function 00040 #define CHACHA_QUARTER_ROUND(a, b, c, d) \ 00041 { \ 00042 a += b; d ^= a; d = ROL32(d, 16); \ 00043 c += d; b ^= c; b = ROL32(b, 12); \ 00044 a += b; d ^= a; d = ROL32(d, 8); \ 00045 c += d; b ^= c; b = ROL32(b, 7); \ 00046 } 00047 00048 00049 /** 00050 * @brief Initialize ChaCha context using the supplied key and nonce 00051 * @param[in] context Pointer to the ChaCha context to initialize 00052 * @param[in] nr Number of rounds to be applied (8, 12 or 20) 00053 * @param[in] key Pointer to the key 00054 * @param[in] keyLength Length of the key, in bytes (16 or 32) 00055 * @param[in] nonce Pointer to the nonce 00056 * @param[in] nonceLength Length of the nonce, in bytes (8 or 12) 00057 * @return Error code 00058 **/ 00059 00060 error_t chachaInit(ChachaContext *context, uint_t nr, const uint8_t *key, 00061 size_t keyLength, const uint8_t *nonce, size_t nonceLength) 00062 { 00063 uint32_t *w; 00064 00065 //The number of rounds must be 8, 12 or 20 00066 if(nr != 8 && nr != 12 && nr != 20) 00067 return ERROR_INVALID_PARAMETER; 00068 00069 //Save the number of rounds to be applied 00070 context->nr = nr; 00071 00072 //Point to the state 00073 w = context->state; 00074 00075 //Check the length of the key 00076 if(keyLength == 16) 00077 { 00078 //The first four input words are constants 00079 w[0] = 0x61707865; 00080 w[1] = 0x3120646E; 00081 w[2] = 0x79622D36; 00082 w[3] = 0x6B206574; 00083 00084 //Input words 4 through 7 are taken from the 128-bit key, by reading 00085 //the bytes in little-endian order, in 4-byte chunks 00086 w[4] = LOAD32LE(key); 00087 w[5] = LOAD32LE(key + 4); 00088 w[6] = LOAD32LE(key + 8); 00089 w[7] = LOAD32LE(key + 12); 00090 00091 //Input words 8 through 11 are taken from the 128-bit key, again by 00092 //reading the bytes in little-endian order, in 4-byte chunks 00093 w[8] = LOAD32LE(key); 00094 w[9] = LOAD32LE(key + 4); 00095 w[10] = LOAD32LE(key + 8); 00096 w[11] = LOAD32LE(key + 12); 00097 } 00098 else if(keyLength == 32) 00099 { 00100 //The first four input words are constants 00101 w[0] = 0x61707865; 00102 w[1] = 0x3320646E; 00103 w[2] = 0x79622D32; 00104 w[3] = 0x6B206574; 00105 00106 //Input words 4 through 11 are taken from the 256-bit key, by reading 00107 //the bytes in little-endian order, in 4-byte chunks 00108 w[4] = LOAD32LE(key); 00109 w[5] = LOAD32LE(key + 4); 00110 w[6] = LOAD32LE(key + 8); 00111 w[7] = LOAD32LE(key + 12); 00112 w[8] = LOAD32LE(key + 16); 00113 w[9] = LOAD32LE(key + 20); 00114 w[10] = LOAD32LE(key + 24); 00115 w[11] = LOAD32LE(key + 28); 00116 } 00117 else 00118 { 00119 //Invalid key length 00120 return ERROR_INVALID_PARAMETER; 00121 } 00122 00123 //Check the length of the nonce 00124 if(nonceLength == 8) 00125 { 00126 //Input words 12 and 13 are a block counter, with word 12 00127 //overflowing into word 13 00128 w[12] = 0; 00129 w[13] = 0; 00130 00131 //Input words 14 and 15 are taken from an 64-bit nonce, by reading 00132 //the bytes in little-endian order, in 4-byte chunks 00133 w[14] = LOAD32LE(nonce); 00134 w[15] = LOAD32LE(nonce + 4); 00135 } 00136 else if(nonceLength == 12) 00137 { 00138 //Input word 12 is a block counter 00139 w[12] = 0; 00140 00141 //Input words 13 to 15 are taken from an 96-bit nonce, by reading 00142 //the bytes in little-endian order, in 4-byte chunks 00143 w[13] = LOAD32LE(nonce); 00144 w[14] = LOAD32LE(nonce + 4); 00145 w[15] = LOAD32LE(nonce + 8); 00146 } 00147 else 00148 { 00149 //Invalid nonce length 00150 return ERROR_INVALID_PARAMETER; 00151 } 00152 00153 //The keystream block is empty 00154 context->pos = 0; 00155 00156 //No error to report 00157 return NO_ERROR; 00158 } 00159 00160 00161 /** 00162 * @brief Encrypt/decrypt data with the ChaCha algorithm 00163 * @param[in] context Pointer to the ChaCha context 00164 * @param[in] input Pointer to the data to encrypt/decrypt (optional) 00165 * @param[in] output Pointer to the resulting data (optional) 00166 * @param[in] length Number of bytes to be processed 00167 **/ 00168 00169 void chachaCipher(ChachaContext *context, const uint8_t *input, 00170 uint8_t *output, size_t length) 00171 { 00172 uint_t i; 00173 uint_t n; 00174 uint8_t *k; 00175 00176 //Encryption loop 00177 while(length > 0) 00178 { 00179 //Check whether a new keystream block must be generated 00180 if(context->pos == 0 || context->pos >= 64) 00181 { 00182 //ChaCha successively calls the ChaCha block function, with the same key 00183 //and nonce, and with successively increasing block counter parameters 00184 chachaProcessBlock(context); 00185 00186 //Increment block counter 00187 context->state[12]++; 00188 00189 //Propagate the carry if necessary 00190 if(context->state[12] == 0) 00191 context->state[13]++; 00192 00193 //Rewind to the beginning of the keystream block 00194 context->pos = 0; 00195 } 00196 00197 //Compute the number of bytes to encrypt/decrypt at a time 00198 n = MIN(length, 64 - context->pos); 00199 00200 //Valid output pointer? 00201 if(output != NULL) 00202 { 00203 //Point to the keystream 00204 k = (uint8_t *) context->block + context->pos; 00205 00206 //Valid input pointer? 00207 if(input != NULL) 00208 { 00209 //XOR the input data with the keystream 00210 for(i = 0; i < n; i++) 00211 output[i] = input[i] ^ k[i]; 00212 00213 //Advance input pointer 00214 input += n; 00215 } 00216 else 00217 { 00218 //Output the keystream 00219 for(i = 0; i < n; i++) 00220 output[i] = k[i]; 00221 } 00222 00223 //Advance output pointer 00224 output += n; 00225 } 00226 00227 //Current position in the keystream block 00228 context->pos += n; 00229 //Remaining bytes to process 00230 length -= n; 00231 } 00232 } 00233 00234 00235 /** 00236 * @brief Generate a keystream block 00237 * @param[in] context Pointer to the ChaCha context 00238 **/ 00239 00240 void chachaProcessBlock(ChachaContext *context) 00241 { 00242 uint_t i; 00243 uint32_t *w; 00244 00245 //Point to the working state 00246 w = (uint32_t *) context->block; 00247 00248 //Copy the state to the working state 00249 for(i = 0; i < 16; i++) 00250 w[i] = context->state[i]; 00251 00252 //ChaCha runs 8, 12 or 20 rounds, alternating between column rounds 00253 //and diagonal rounds 00254 for(i = 0; i < context->nr; i += 2) 00255 { 00256 //The column rounds apply the quarter-round function to the four 00257 //columns, from left to right 00258 CHACHA_QUARTER_ROUND(w[0], w[4], w[8], w[12]); 00259 CHACHA_QUARTER_ROUND(w[1], w[5], w[9], w[13]); 00260 CHACHA_QUARTER_ROUND(w[2], w[6], w[10], w[14]); 00261 CHACHA_QUARTER_ROUND(w[3], w[7], w[11], w[15]); 00262 00263 //The diagonal rounds apply the quarter-round function to the top-left, 00264 //bottom-right diagonal, followed by the pattern shifted one place to 00265 //the right, for three more quarter-rounds 00266 CHACHA_QUARTER_ROUND(w[0], w[5], w[10], w[15]); 00267 CHACHA_QUARTER_ROUND(w[1], w[6], w[11], w[12]); 00268 CHACHA_QUARTER_ROUND(w[2], w[7], w[8], w[13]); 00269 CHACHA_QUARTER_ROUND(w[3], w[4], w[9], w[14]); 00270 } 00271 00272 //Add the original input words to the output words 00273 for(i = 0; i < 16; i++) 00274 w[i] += context->state[i]; 00275 00276 //Serialize the result by sequencing the words one-by-one in 00277 //little-endian order 00278 for(i = 0; i < 16; i++) 00279 w[i] = htole32(w[i]); 00280 } 00281 00282 #endif 00283
Generated on Tue Jul 12 2022 17:10:12 by
1.7.2