├── LICENSE.txt ├── README.md ├── examples ├── SpritzBestPractice │ └── SpritzBestPractice.ino ├── SpritzBestPracticePassword │ └── SpritzBestPracticePassword.ino ├── SpritzBestPracticePasswordESP8266 │ └── SpritzBestPracticePasswordESP8266.ino ├── SpritzCryptInplaceTest │ └── SpritzCryptInplaceTest.ino ├── SpritzCryptTest │ └── SpritzCryptTest.ino ├── SpritzHashTest │ └── SpritzHashTest.ino ├── SpritzMACTest │ └── SpritzMACTest.ino └── SpritzStreamTest │ └── SpritzStreamTest.ino ├── extras └── Spritz cipher white paper.pdf ├── keywords.txt ├── library.json ├── library.properties └── src ├── SpritzCipher.c └── SpritzCipher.h /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License: 2 | 3 | Copyright (c) 2015-2020 Abderraouf Adjal 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spritz Library For Arduino 2 | 3 | > Spritz - a spongy RC4-like stream cipher and hash function. 4 | 5 | This library contains a cryptographic pseudo-random number generator, 6 | cryptographic hash and message authentication code (MAC) functions, 7 | can perform symmetric-key authenticated data encryption, and general-purpose 8 | functions for timing-safe comparison and wiping data from memory. 9 | 10 | This C Spritz library can be used to: 11 | 12 | - Hash and authenticate data. 13 | - Perform symmetric-key authenticated data encryption. 14 | - Generate random numbers and strings from entropy/seed. 15 | 16 | [This library's GitHub repository](https://github.com/abderraouf-adjal/ArduinoSpritzCipher). 17 | 18 | [This library's Bitbucket repository](https://bitbucket.org/abderraouf-adjal/arduinospritzcipher) (Backup). 19 | 20 | **Spritz paper:** 21 | 22 | --- 23 | 24 | ## Library Content 25 | 26 | **Read the source code for details.** 27 | 28 | ### Types 29 | 30 | **spritz_ctx** - The context/ctx (contains the state). The state consists of byte registers 31 | {i, j, k, z, w, a}, And an array {s} containing a permutation of {0, 1, ... , SPRITZ_N-1}. 32 | 33 | **uint8_t** - unsigned integer type with width of 8-bit, MIN=0;MAX=255. 34 | 35 | **uint16_t** - unsigned integer type with width of 16-bit, MIN=0;MAX=65,535. 36 | 37 | **uint32_t** - unsigned integer type with width of 32-bit, MIN=0;MAX=4,294,967,295. 38 | 39 | ### Functions 40 | 41 | ```c 42 | uint8_t spritz_compare(const uint8_t *data_a, const uint8_t *data_b, 43 | uint16_t len) 44 | ``` 45 | 46 | Timing-safe comparison for `data_a` and `data_b` equality. 47 | This function can be used to compare the password's hash safely. 48 | 49 | Return equality result. 50 | Zero (0x00) if `data_a` equals `data_b` OR if `len` is zero, 51 | Non-zero value if they are NOT equal. 52 | 53 | ```c 54 | void spritz_memzero(uint8_t *buf, uint16_t len) 55 | ``` 56 | 57 | Wipe `buf` data by replacing it with `len` zeros (0x00). 58 | 59 | ```c 60 | void spritz_state_memzero(spritz_ctx *ctx) 61 | ``` 62 | 63 | Wipe `spritz_ctx`'s data by replacing its data with zeros (0x00). 64 | 65 | If `SPRITZ_WIPE_TRACES_PARANOID` is defined, This function will 66 | wipe the *sensitive* temporary variables in `spritz_ctx`. 67 | 68 | ```c 69 | void spritz_setup(spritz_ctx *ctx, 70 | const uint8_t *key, uint8_t keyLen) 71 | ``` 72 | 73 | Setup the spritz state `spritz_ctx` with a `key` of length `keyLen`. 74 | 75 | ```c 76 | void spritz_setup_withIV(spritz_ctx *ctx, 77 | const uint8_t *key, uint8_t keyLen, 78 | const uint8_t *nonce, uint8_t nonceLen) 79 | ``` 80 | 81 | Setup the spritz state `spritz_ctx` with a `key` and `nonce`/Salt/IV. 82 | 83 | ```c 84 | uint8_t spritz_random8(spritz_ctx *ctx) 85 | ``` 86 | 87 | Generates a random byte (8-bit) from the spritz state `spritz_ctx`. 88 | 89 | ```c 90 | uint32_t spritz_random32(spritz_ctx *ctx) 91 | ``` 92 | 93 | Generates a random 32-bit (4 bytes) from the spritz state `spritz_ctx`. 94 | 95 | ```c 96 | uint32_t spritz_random32_uniform(spritz_ctx *ctx, uint32_t upper_bound) 97 | ``` 98 | 99 | Calculate an uniformly distributed random number less than `upper_bound` avoiding *modulo bias*. 100 | Uniformity is achieved by generating new random numbers until the one 101 | returned is outside the range [0, 2\*\*32 % `upper_bound`). 102 | This guarantees the selected random number will be inside 103 | [2\*\*32 % `upper_bound`, 2\*\*32) which maps back to [0, `upper_bound`) 104 | after reduction modulo `upper_bound`. 105 | 106 | ```c 107 | void spritz_add_entropy(spritz_ctx *ctx, 108 | const uint8_t *entropy, uint16_t len) 109 | ``` 110 | 111 | Add `entropy` to the spritz state `spritz_ctx` using the internal function `absorb()`. 112 | 113 | ```c 114 | void spritz_crypt(spritz_ctx *ctx, 115 | const uint8_t *data, uint16_t dataLen, 116 | uint8_t *dataOut) 117 | ``` 118 | 119 | Encrypt or decrypt `data` chunk by XOR-ing it with the spritz keystream. 120 | 121 | ```c 122 | void spritz_crypt_inplace(spritz_ctx *ctx, 123 | uint8_t *data, uint16_t dataLen) 124 | ``` 125 | 126 | Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream 127 | and put the output in the same buffer `data`. 128 | 129 | ```c 130 | void spritz_hash(uint8_t *digest, uint8_t digestLen, 131 | const uint8_t *data, uint16_t dataLen) 132 | ``` 133 | 134 | Spritz cryptographic hash function. 135 | 136 | ```c 137 | void spritz_mac(uint8_t *digest, uint8_t digestLen, 138 | const uint8_t *msg, uint16_t msgLen, 139 | const uint8_t *key, uint16_t keyLen) 140 | ``` 141 | 142 | Spritz Message Authentication Code (MAC) function. 143 | 144 | ```c 145 | void spritz_hash_setup(spritz_ctx *hash_ctx) 146 | ``` 147 | 148 | Setup the spritz hash state. 149 | 150 | ```c 151 | void spritz_hash_update(spritz_ctx *hash_ctx, 152 | const uint8_t *data, uint16_t dataLen) 153 | ``` 154 | 155 | Add a message/data chunk `data` to hash. 156 | 157 | ```c 158 | void spritz_hash_final(spritz_ctx *hash_ctx, 159 | uint8_t *digest, uint8_t digestLen) 160 | ``` 161 | 162 | Output the hash digest. 163 | 164 | ```c 165 | void spritz_mac_setup(spritz_ctx *mac_ctx, 166 | const uint8_t *key, uint16_t keyLen) 167 | ``` 168 | 169 | Setup the spritz Message Authentication Code (MAC) state. 170 | 171 | ```c 172 | void spritz_mac_update(spritz_ctx *mac_ctx, 173 | const uint8_t *msg, uint16_t msgLen) 174 | ``` 175 | 176 | Add a message/data chunk to Message Authentication Code (MAC). 177 | 178 | ```c 179 | void spritz_mac_final(spritz_ctx *mac_ctx, 180 | uint8_t *digest, uint8_t digestLen) 181 | ``` 182 | 183 | Output the Message Authentication Code (MAC) digest. 184 | 185 | #### Notes 186 | 187 | `spritz_random8()`, `spritz_random32()`, `spritz_random32_uniform()`, `spritz_add_entropy()`, `spritz_crypt()`. 188 | Are usable only after calling `spritz_setup()` or `spritz_setup_withIV()`. 189 | 190 | Functions `spritz_random*()` requires `spritz_setup()` or `spritz_setup_withIV()` initialized with an entropy (random data), 128-bit of entropy at least. 191 | Arduino Uno's ATmega328P and many microcontrollers and microprocessors does NOT have a real/official way to get entropy, 192 | 193 | **you will/may need getting entropy** by using hardware (recommended), or at least a pre-stored random data updated with `spritz_random*()` output (NOT recommended). 194 | 195 | To generate a random number in a range [k, m) use `k + spritz_random32_uniform(ctx, m)`, 196 | Not `k + (spritz_random8(ctx) % m)` or `k + (spritz_random32(ctx) % m)`. 197 | 198 | Use `spritz_state_memzero()` after `spritz_hash_final()` or `spritz_mac_final()` 199 | if you need to wipe the used `spritz_ctx`'s data. 200 | 201 | ### Constants 202 | 203 | Configure library settings in the file `SpritzCipher.h`. 204 | 205 | - **SPRITZ_USE_LIBC** 206 | 207 | Use C standard library functions such as `memset()` to zero buffers. 208 | It can be useful for performnce if the lib-C functions are optimized in low-level. 209 | If the compiler is not GCC or Clang, you will see a security warning about code optimization 210 | is not off in some sensitive functions. 211 | 212 | `SPRITZ_USE_LIBC` is **NOT** defined by default. 213 | 214 | - **SPRITZ_TIMING_SAFE_CRUSH** 215 | 216 | If defined, The equal time `crush()` will be used. 217 | 218 | `SPRITZ_TIMING_SAFE_CRUSH` is defined by default. 219 | 220 | - **SPRITZ_WIPE_TRACES** 221 | 222 | If defined, Sensitive data like `spritz_ctx` will be wiped, when they are 223 | no longer needed, in the functions: `spritz_hash()`, `spritz_mac()`. 224 | 225 | `SPRITZ_WIPE_TRACES` is **NOT** defined by default. 226 | 227 | - **SPRITZ_WIPE_TRACES_PARANOID** 228 | 229 | If defined, The library functions internal variables will be wiped if they 230 | contain a bit or more of spritz state, such as temporary variables in a swap 231 | function or user data. Variables that contain data length will not be wiped. 232 | 233 | If `SPRITZ_WIPE_TRACES_PARANOID` defined, Then `SPRITZ_WIPE_TRACES` and `SPRITZ_TIMING_SAFE_CRUSH`, will be defined automatically. 234 | 235 | `SPRITZ_WIPE_TRACES_PARANOID` is **NOT** defined by default. 236 | 237 | - **SPRITZ_N** = `256` - Present the value of N in this spritz implementation, *Do NOT change `SPRITZ_N` value*. 238 | 239 | - **SPRITZ_LIBRARY_VERSION_STRING** = `"x.y.z"` - Present the version of this 240 | spritz library (MAJOR . MINOR . PATCH) using Semantic Versioning. 241 | 242 | - **SPRITZ_LIBRARY_VERSION_MAJOR** = `x` - The MAJOR version of the library. 243 | 244 | - **SPRITZ_LIBRARY_VERSION_MINOR** = `y` - The MINOR version of the library. 245 | 246 | - **SPRITZ_LIBRARY_VERSION_PATCH** = `z` - The PATCH version of the library. 247 | 248 | --- 249 | 250 | ## Examples 251 | 252 | - [SpritzBestPractice](examples/SpritzBestPractice/SpritzBestPractice.ino): 253 | Hash 32 KB of a Spritz stream (pseudo-random number generator output) then print the result. 254 | An embedded entropy/seed for the pseudo-random number generator is used. 255 | 256 | - [SpritzBestPracticePassword](examples/SpritzBestPracticePassword/SpritzBestPracticePassword.ino): 257 | Generate a strong Alphanumeric passwords, and then print it. 258 | An embedded entropy/seed for the pseudo-random number generator is used. 259 | 260 | - [SpritzBestPracticePasswordESP8266](examples/SpritzBestPracticePasswordESP8266/SpritzBestPracticePasswordESP8266.ino): 261 | Generate a strong Alphanumeric passwords, and then print it. 262 | This example is for ESP8266 SoC, it uses a hardware RNG in ESP8266 as an initialization entropy. 263 | 264 | - [SpritzCryptTest](examples/SpritzCryptTest/SpritzCryptTest.ino): 265 | Test the library encryption/decryption function. 266 | 267 | - [SpritzCryptInplaceTest](examples/SpritzCryptInplaceTest/SpritzCryptInplaceTest.ino): 268 | Test the library encryption/decryption function doing encrypt and decrypt 269 | in same buffer for less RAM usage. 270 | 271 | - [SpritzStreamTest](examples/SpritzStreamTest/SpritzStreamTest.ino): 272 | Generate random bytes (Spritz stream) test. 273 | 274 | - [SpritzHashTest](examples/SpritzHashTest/SpritzHashTest.ino): 275 | Hash function test. 276 | 277 | - [SpritzMACTest](examples/SpritzMACTest/SpritzMACTest.ino): 278 | Message authentication code (MAC) function test. 279 | 280 | --- 281 | 282 | ## Installation Guide 283 | 284 | [Arduino IDE](https://www.arduino.cc/en/Main/Software) - 285 | [Additional libraries installation guide](https://www.arduino.cc/en/Guide/Libraries). 286 | 287 | Compiling this library using *GCC* or *Clang* will give more security for functions that should be compiled with *zero optimization* (`-O0`) like `spritz_compare()`. 288 | 289 | --- 290 | 291 | ## Reporting bugs 292 | 293 | [Create an issue on GitHub](https://github.com/abderraouf-adjal/ArduinoSpritzCipher/issues). 294 | 295 | --- 296 | 297 | ## Copyright and License 298 | 299 | > Copyright (c) 2015-2020 Abderraouf Adjal 300 | 301 | - The source-code: ISC License. 302 | 303 | - Documentation (e.g. this file content): Public domain. 304 | 305 | - Examples: Public domain. 306 | -------------------------------------------------------------------------------- /examples/SpritzBestPractice/SpritzBestPractice.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Hash 32 KB of a Spritz stream (random bytes generator output) 3 | * then print the result. 4 | * 5 | * This code show what the library can do (show off the API). 6 | * An embedded entropy/seed for the RNG is used. 7 | * 8 | * The circuit: No external hardware needed. 9 | * 10 | * by Abderraouf Adjal. 11 | * 12 | * This example code is in the public domain. 13 | */ 14 | 15 | /* ArduinoSpritzCipher documentation: */ 16 | 17 | 18 | /* ArduinoSpritzCipher is configurable in with: 19 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 20 | * SPRITZ_USE_LIBC. 21 | * For detailed information, read the documentation. 22 | */ 23 | #include 24 | 25 | 26 | /* In a real case, get entropy by using hardware, NOT an embedded data like this example. 27 | * 28 | * Arduino Uno's ATmega328P and many microcontrollers and microprocessors 29 | * does NOT have a real/official way to get entropy, 30 | * you will/may need getting entropy by using hardware (recommended), 31 | * or at least a pre-stored random data updated with `spritz_random*()` output (NOT recommended). 32 | */ 33 | 34 | /* The RNG seed (64 digits of Pi) */ 35 | const uint8_t entropy_example[64] = 36 | { '3', '1', '4', '1', '5', '9', '2', '6', 37 | '5', '3', '5', '8', '9', '7', '9', '3', 38 | '2', '3', '8', '4', '6', '2', '6', '4', 39 | '3', '3', '8', '3', '2', '7', '9', '5', 40 | '0', '2', '8', '8', '4', '1', '9', '7', 41 | '1', '6', '9', '3', '9', '9', '3', '7', 42 | '5', '1', '0', '5', '8', '2', '0', '9', 43 | '7', '4', '9', '4', '4', '5', '9', '2' 44 | }; 45 | 46 | /* The expected result, Same as Github user @jedisct1 implementation */ 47 | const uint8_t ExpectedHash[32] = 48 | { 0x11, 0xfe, 0x5e, 0xf8, 0x91, 0xa3, 0xcf, 0xb9, 49 | 0x54, 0x07, 0x54, 0x8e, 0xa0, 0x5e, 0x0b, 0xeb, 50 | 0xaf, 0x94, 0xf2, 0x7a, 0x46, 0xfa, 0xbb, 0xad, 51 | 0x21, 0xf7, 0x57, 0x4e, 0xee, 0x66, 0xab, 0xd9 52 | }; 53 | 54 | void setup() { 55 | /* Initialize serial and wait for port to open */ 56 | Serial.begin(9600); 57 | while (!Serial) { 58 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 59 | } 60 | } 61 | 62 | void loop() { 63 | spritz_ctx hash_ctx; /* For the hash */ 64 | spritz_ctx rng_ctx; /* For the random bytes generator */ 65 | 66 | uint8_t digest[32]; /* Hash result, 256-bit */ 67 | uint8_t buf[32]; 68 | 69 | uint8_t i; 70 | uint16_t j; 71 | uint16_t LOOP_ROUNDS = 1024; /* 32 KB: (1024 * 32) / sizeof(buf) */ 72 | 73 | 74 | Serial.println("\n[Hash 32 KB of Spritz random bytes generator output]\n"); 75 | 76 | /* Make a 256-bit hash of the entropy in "buf" using one function */ 77 | spritz_hash(buf, (uint8_t)(sizeof(buf)), entropy_example, (uint8_t)(sizeof(entropy_example))); 78 | /* Initialize/Seed the RNG with the hash of entropy */ 79 | spritz_setup(&rng_ctx, buf, (uint8_t)(sizeof(buf))); 80 | 81 | /* The data will be generated in small chunks, 82 | * So we can not use "one function API" */ 83 | spritz_hash_setup(&hash_ctx); 84 | 85 | for (j = 0; j < LOOP_ROUNDS; j++) { 86 | /* Fill buf with Spritz random bytes generator output */ 87 | for (i = 0; i < (uint8_t)(sizeof(buf)); i++) { 88 | buf[i] = spritz_random8(&rng_ctx); 89 | } 90 | /* Add buf data to hash_ctx */ 91 | spritz_hash_update(&hash_ctx, buf, (uint16_t)(sizeof(buf))); 92 | } 93 | 94 | /* Output the final hash */ 95 | spritz_hash_final(&hash_ctx, digest, (uint8_t)(sizeof(digest))); 96 | 97 | /* Print the hash in HEX */ 98 | for (i = 0; i < (uint8_t)(sizeof(digest)); i++) { 99 | if (digest[i] < 0x10) { /* To print "0F", not "F" */ 100 | Serial.write('0'); 101 | } 102 | Serial.print(digest[i], HEX); 103 | } 104 | Serial.println(); 105 | 106 | /* Check the output */ 107 | if (spritz_compare(digest, ExpectedHash, (uint16_t)(sizeof(digest)))) { 108 | /* If the output is wrong "Alert" */ 109 | Serial.println("\n** WARNING: hash != expected hash **"); 110 | } 111 | 112 | /* wipe "hash_ctx" data by replacing it with zeros (0x00) */ 113 | spritz_state_memzero(&hash_ctx); 114 | 115 | /* wipe "digest" data by replacing it with zeros (0x00) */ 116 | spritz_memzero(digest, (uint16_t)(sizeof(digest))); 117 | 118 | /* Keys, RNG seed & buffer should be wiped in realworld. 119 | * In this example we should not wipe "entropy" 120 | * cause it is embedded in the code */ 121 | spritz_state_memzero(&rng_ctx); 122 | spritz_memzero(buf, (uint16_t)(sizeof(buf))); 123 | } 124 | -------------------------------------------------------------------------------- /examples/SpritzBestPracticePassword/SpritzBestPracticePassword.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate a strong Alphanumeric passwords, and then print it 3 | * 4 | * This code show what the library can do (show off the API). 5 | * An embedded entropy/seed for the RNG is used. 6 | * 7 | * The circuit: No external hardware needed. 8 | * 9 | * by Abderraouf Adjal. 10 | * 11 | * This example code is in the public domain. 12 | */ 13 | 14 | /* ArduinoSpritzCipher documentation: */ 15 | 16 | 17 | /* ArduinoSpritzCipher is configurable in with: 18 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 19 | * SPRITZ_USE_LIBC. 20 | * For detailed information, read the documentation. 21 | */ 22 | #include 23 | 24 | 25 | /* In a real case, get entropy by using hardware, NOT an embedded data like this example. 26 | * 27 | * Arduino Uno's ATmega328P and many microcontrollers and microprocessors 28 | * does NOT have a real/official way to get entropy, 29 | * you will/may need getting entropy by using hardware (recommended), 30 | * or at least a pre-stored random data updated with `spritz_random*()` output (NOT recommended). 31 | */ 32 | 33 | /* The RNG seed (64 digits of Pi) */ 34 | uint8_t entropy_example[64] = 35 | { '3', '1', '4', '1', '5', '9', '2', '6', 36 | '5', '3', '5', '8', '9', '7', '9', '3', 37 | '2', '3', '8', '4', '6', '2', '6', '4', 38 | '3', '3', '8', '3', '2', '7', '9', '5', 39 | '0', '2', '8', '8', '4', '1', '9', '7', 40 | '1', '6', '9', '3', '9', '9', '3', '7', 41 | '5', '1', '0', '5', '8', '2', '0', '9', 42 | '7', '4', '9', '4', '4', '5', '9', '2' 43 | }; 44 | 45 | /* Table of alphabetic (uppercase and lowercase) and numeric characters */ 46 | const uint8_t alphanumeric_table[62] = 47 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 48 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 49 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 50 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 51 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 52 | }; 53 | 54 | 55 | void setup() { 56 | /* Initialize serial and wait for port to open */ 57 | Serial.begin(9600); 58 | while (!Serial) { 59 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 60 | } 61 | } 62 | 63 | 64 | void loop() { 65 | uint8_t password_len = 28; /* ~160-bit of entropy password; ceil(160/log2(26*2+10)) */ 66 | uint8_t buf[32]; 67 | spritz_ctx the_ctx; 68 | /* One spritz_ctx, One buffer. 69 | * For both, hash function and the random numbers generator (Memory saving) 70 | */ 71 | 72 | /* We did NOT use spritz_hash() cause it will have its own spritz_ctx, 73 | * And we like to save memory 74 | */ 75 | /* Make a 256-bit hash of the entropy in "buf" using one function */ 76 | spritz_hash_setup(&the_ctx); /* Initialize */ 77 | spritz_hash_update(&the_ctx, entropy_example, (uint16_t)(sizeof(entropy_example))); /* Add data */ 78 | spritz_hash_final(&the_ctx, buf, (uint8_t)(sizeof(buf))); /* Output the final hash */ 79 | 80 | spritz_state_memzero(&the_ctx); /* wipe "the_ctx" data by replacing it with zeros (0x00) */ 81 | spritz_memzero(entropy_example, (uint16_t)(sizeof(entropy_example))); /* wipe "entropy" data by replacing it with zeros (0x00) */ 82 | 83 | /* Initialize/Seed the RNG with the hash of entropy */ 84 | spritz_setup(&the_ctx, buf, (uint8_t)(sizeof(buf))); 85 | 86 | spritz_memzero(buf, (uint16_t)(sizeof(buf))); /* wipe "buf" data by replacing it with zeros (0x00) */ 87 | 88 | 89 | Serial.println("\n[Make strong Alphanumeric passwords]\n"); 90 | 91 | while (1) 92 | { 93 | /* Fill the buffer with random uniformly distributed alphanumeric characters */ 94 | for (uint8_t i = 0; i < password_len; i++) { 95 | /* Like: buf[i] = charactersTable[random() % number_Of_elements_In_charactersTable] */ 96 | buf[i] = alphanumeric_table[spritz_random32_uniform(&the_ctx, (uint32_t)(sizeof(alphanumeric_table)))]; 97 | } 98 | 99 | /* Print the password */ 100 | Serial.write(buf, password_len); 101 | Serial.println(); 102 | 103 | delay(1000); /* Wait 1s */ 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /examples/SpritzBestPracticePasswordESP8266/SpritzBestPracticePasswordESP8266.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate a strong Alphanumeric passwords, and then print it. 3 | * The initial entropy source will be from hardware RNG in ESP8266 SoC. 4 | * 5 | * This code show what the library can do (show off the API). 6 | * An embedded entropy/seed for the RNG is used. 7 | * 8 | * The circuit: ESP8266 SoC. 9 | * 10 | * by Abderraouf Adjal. 11 | * 12 | * This example code is in the public domain. 13 | */ 14 | 15 | /* ArduinoSpritzCipher documentation: */ 16 | 17 | 18 | /* ArduinoSpritzCipher is configurable in with: 19 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 20 | * SPRITZ_USE_LIBC. 21 | * For detailed information, read the documentation. 22 | */ 23 | #include 24 | #include 25 | 26 | 27 | 28 | /* Table of alphabetic (uppercase and lowercase) and numeric characters */ 29 | const char alphanumeric_table[62] = 30 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 31 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 32 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 33 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 34 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 35 | }; 36 | 37 | #define PASSWORD_LEN 28 /* ~160-bit of entropy password; ceil(160/log2(26*2+10)) */ 38 | /* One spritz_ctx (One mem buffer) to save some memory. 39 | * For both, hash function and the random numbers generator. 40 | */ 41 | spritz_ctx the_ctx; 42 | 43 | void setup() { 44 | volatile uint32_t hw_rng; /* The RNG seed */ 45 | uint8_t buf[32]; 46 | 47 | /* Initialize serial and wait for port to open */ 48 | Serial.begin(115200); 49 | while (!Serial) { 50 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 51 | } 52 | 53 | /* We did NOT use spritz_hash() cause it will have its own spritz_ctx, 54 | * And we like to save memory 55 | */ 56 | /* To make a 256-bit hash of the entropy */ 57 | spritz_hash_setup(&the_ctx); /* Initialize */ 58 | 59 | /* Insert 64*4=256 bytes of entropy in hash function */ 60 | for (uint16_t i = 0; i < 64; i++) { 61 | delay(1); 62 | hw_rng = *(volatile uint32_t *)0x3FF20E44; 63 | spritz_hash_update(&the_ctx, (const uint8_t *)&hw_rng, (uint16_t)(sizeof(hw_rng))); /* Add 4 bytes of entropy */ 64 | } 65 | 66 | spritz_hash_final(&the_ctx, buf, (uint8_t)(sizeof(buf))); /* Output the final hash */ 67 | spritz_memzero((uint8_t *)&hw_rng, (uint16_t)(sizeof(hw_rng))); 68 | 69 | /* Initialize/Seed the RNG with the hash of entropy */ 70 | spritz_setup(&the_ctx, buf, (uint8_t)(sizeof(buf))); /* wipe "the_ctx" data by replacing it with zeros (0x00) */ 71 | spritz_memzero(buf, (uint16_t)(sizeof(buf))); /* wipe "buf" data by replacing it with zeros (0x00) */ 72 | 73 | Serial.println(F("\n\n[Make strong Alphanumeric passwords]\n\n")); 74 | } 75 | 76 | 77 | void loop() { 78 | /* Print random uniformly distributed alphanumeric characters. 79 | * Better than: rand_char = charactersTable[random() % number_Of_elements_In_charactersTable] 80 | */ 81 | for (uint8_t i = 0; i < PASSWORD_LEN; i++) { 82 | Serial.print((char)alphanumeric_table[spritz_random32_uniform(&the_ctx, (uint32_t)(sizeof(alphanumeric_table)))]); 83 | } 84 | Serial.println(); 85 | 86 | delay(1000); /* Wait 1s */ 87 | } 88 | -------------------------------------------------------------------------------- /examples/SpritzCryptInplaceTest/SpritzCryptInplaceTest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Spritz Cipher MAC Test 3 | * 4 | * This example code test SpritzCipher library encryption/decryption function. 5 | * Encrypt and decrypt in same buffer for less RAM usage. 6 | * 7 | * The circuit: No external hardware needed. 8 | * 9 | * by Abderraouf Adjal. 10 | * 11 | * This example code is in the public domain. 12 | */ 13 | 14 | /* ArduinoSpritzCipher documentation: */ 15 | 16 | 17 | /* ArduinoSpritzCipher is configurable in with: 18 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 19 | * SPRITZ_USE_LIBC. 20 | * For detailed information, read the documentation. 21 | */ 22 | #include 23 | 24 | 25 | /* Data to input */ 26 | byte testMsg[3] = { 'A', 'B', 'C' }; /* Encrypt and decrypt in same buffer. */ 27 | const byte testMsg_original[3] = { 'A', 'B', 'C' }; 28 | const byte testKey[3] = { 0x00, 0x01, 0x02 }; 29 | 30 | 31 | void testFunc(byte *msg, byte msgLen, const byte *key, byte keyLen) 32 | { 33 | spritz_ctx s_ctx; 34 | unsigned int i; 35 | 36 | /* Print MSG */ 37 | for (i = 0; i < msgLen; i++) { 38 | Serial.write(msg[i]); 39 | } 40 | Serial.println(); 41 | 42 | /* Print KEY */ 43 | for (i = 0; i < keyLen; i++) { 44 | if (key[i] < 0x10) { /* To print "0F" not "F" */ 45 | Serial.write('0'); 46 | } 47 | Serial.print(key[i], HEX); 48 | } 49 | Serial.println(); 50 | 51 | spritz_setup(&s_ctx, key, keyLen); 52 | spritz_crypt_inplace(&s_ctx, msg, msgLen); /* Encrypt in same buffer. */ 53 | /* You can also use: spritz_crypt(&s_ctx, msg, msgLen, msg); */ 54 | 55 | /* Print Ciphertext */ 56 | for (i = 0; i < msgLen; i++) { 57 | if (msg[i] < 0x10) { /* To print "0F" not "F" */ 58 | Serial.write('0'); 59 | } 60 | Serial.print(msg[i], HEX); 61 | } 62 | Serial.println(); 63 | 64 | spritz_setup(&s_ctx, key, keyLen); 65 | spritz_crypt_inplace(&s_ctx, msg, msgLen); /* Decrypt in same buffer. */ 66 | /* You can also use: spritz_crypt(&s_ctx, msg, msgLen, msg); */ 67 | 68 | /* Print MSG after decryption */ 69 | for (i = 0; i < msgLen; i++) { 70 | Serial.write(msg[i]); 71 | } 72 | Serial.println(); 73 | 74 | /* Check the output */ 75 | if (spritz_compare(msg, testMsg_original, msgLen)) { 76 | /* If the output is wrong "Alert" */ 77 | digitalWrite(LED_BUILTIN, HIGH); /* Turn pin LED_BUILTIN On (Most boards have this LED connected to digital pin 13) */ 78 | Serial.println("\n** WARNING: Output != Test_Vector **"); 79 | } 80 | Serial.println(); 81 | } 82 | 83 | void setup() { 84 | /* Initialize serial and wait for port to open */ 85 | Serial.begin(9600); 86 | while (!Serial) { 87 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 88 | } 89 | 90 | /* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */ 91 | pinMode(LED_BUILTIN, OUTPUT); 92 | digitalWrite(LED_BUILTIN, LOW); 93 | } 94 | 95 | void loop() { 96 | Serial.println("[Spritz library encryption/decryption function test]\n"); 97 | 98 | /* MSG='ABC' KEY=0x00,0x01,0x02 */ 99 | testFunc(testMsg, sizeof(testMsg), testKey, sizeof(testKey)); 100 | 101 | delay(5000); /* Wait 5s */ 102 | Serial.println(); 103 | } 104 | -------------------------------------------------------------------------------- /examples/SpritzCryptTest/SpritzCryptTest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Spritz Cipher MAC Test 3 | * 4 | * This example code test SpritzCipher library encryption/decryption function. 5 | * 6 | * The circuit: No external hardware needed. 7 | * 8 | * by Abderraouf Adjal. 9 | * 10 | * This example code is in the public domain. 11 | */ 12 | 13 | /* ArduinoSpritzCipher documentation: */ 14 | 15 | 16 | /* ArduinoSpritzCipher is configurable in with: 17 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 18 | * SPRITZ_USE_LIBC. 19 | * For detailed information, read the documentation. 20 | */ 21 | #include 22 | 23 | 24 | /* Data to input */ 25 | const byte testMsg[3] = { 'A', 'B', 'C' }; 26 | const byte testKey[3] = { 0x00, 0x01, 0x02 }; 27 | 28 | 29 | void testFunc(const byte *msg, byte msgLen, const byte *key, byte keyLen) 30 | { 31 | spritz_ctx s_ctx; 32 | byte buf[8]; /* Output buffer */ 33 | unsigned int i; 34 | 35 | /* Print MSG */ 36 | for (i = 0; i < msgLen; i++) { 37 | Serial.write(msg[i]); 38 | } 39 | Serial.println(); 40 | 41 | /* Print KEY */ 42 | for (i = 0; i < keyLen; i++) { 43 | if (key[i] < 0x10) { /* To print "0F" not "F" */ 44 | Serial.write('0'); 45 | } 46 | Serial.print(key[i], HEX); 47 | } 48 | Serial.println(); 49 | 50 | spritz_setup(&s_ctx, key, keyLen); 51 | spritz_crypt(&s_ctx, msg, msgLen, buf); 52 | 53 | /* Print Ciphertext */ 54 | for (i = 0; i < msgLen; i++) { 55 | if (buf[i] < 0x10) { /* To print "0F" not "F" */ 56 | Serial.write('0'); 57 | } 58 | Serial.print(buf[i], HEX); 59 | } 60 | Serial.println(); 61 | 62 | spritz_setup(&s_ctx, key, keyLen); 63 | spritz_crypt(&s_ctx, buf, msgLen, buf); 64 | 65 | /* Print MSG after decryption */ 66 | for (i = 0; i < msgLen; i++) { 67 | Serial.write(buf[i]); 68 | } 69 | Serial.println(); 70 | 71 | /* Check the output */ 72 | if (spritz_compare(buf, msg, msgLen)) { 73 | /* If the output is wrong "Alert" */ 74 | digitalWrite(LED_BUILTIN, HIGH); /* Turn pin LED_BUILTIN On (Most boards have this LED connected to digital pin 13) */ 75 | Serial.println("\n** WARNING: Output != Test_Vector **"); 76 | } 77 | Serial.println(); 78 | } 79 | 80 | void setup() { 81 | /* Initialize serial and wait for port to open */ 82 | Serial.begin(9600); 83 | while (!Serial) { 84 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 85 | } 86 | 87 | /* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */ 88 | pinMode(LED_BUILTIN, OUTPUT); 89 | digitalWrite(LED_BUILTIN, LOW); 90 | } 91 | 92 | void loop() { 93 | Serial.println("[Spritz library encryption/decryption function test]\n"); 94 | 95 | /* MSG='ABC' KEY=0x00,0x01,0x02 */ 96 | testFunc(testMsg, sizeof(testMsg), testKey, sizeof(testKey)); 97 | 98 | delay(5000); /* Wait 5s */ 99 | Serial.println(); 100 | } 101 | -------------------------------------------------------------------------------- /examples/SpritzHashTest/SpritzHashTest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Spritz Cipher Hash Test 3 | * 4 | * This example code test SpritzCipher library hash output 5 | * using test vectors from Spritz paper "RS14.pdf" Page 30: 6 | * 7 | * 8 | * The circuit: No external hardware needed. 9 | * 10 | * by Abderraouf Adjal. 11 | * 12 | * This example code is in the public domain. 13 | */ 14 | 15 | /* ArduinoSpritzCipher documentation: */ 16 | 17 | 18 | /* ArduinoSpritzCipher is configurable in with: 19 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 20 | * SPRITZ_USE_LIBC. 21 | * For detailed information, read the documentation. 22 | */ 23 | #include 24 | 25 | 26 | /* Data to input */ 27 | const byte testData1[3] = { 'A', 'B', 'C' }; 28 | const byte testData2[4] = { 's', 'p', 'a', 'm' }; 29 | const byte testData3[7] = { 'a', 'r', 'c', 'f', 'o', 'u', 'r' }; 30 | 31 | /* Test vectors */ 32 | /* Data 'ABC' hash test vectors */ 33 | const byte testVector1[32] = 34 | { 0x02, 0x8f, 0xa2, 0xb4, 0x8b, 0x93, 0x4a, 0x18, 35 | 0x62, 0xb8, 0x69, 0x10, 0x51, 0x3a, 0x47, 0x67, 36 | 0x7c, 0x1c, 0x2d, 0x95, 0xec, 0x3e, 0x75, 0x70, 37 | 0x78, 0x6f, 0x1c, 0x32, 0x8b, 0xbd, 0x4a, 0x47 38 | }; 39 | /* Data 'spam' hash test vectors */ 40 | const byte testVector2[32] = 41 | { 0xac, 0xbb, 0xa0, 0x81, 0x3f, 0x30, 0x0d, 0x3a, 42 | 0x30, 0x41, 0x0d, 0x14, 0x65, 0x74, 0x21, 0xc1, 43 | 0x5b, 0x55, 0xe3, 0xa1, 0x4e, 0x32, 0x36, 0xb0, 44 | 0x39, 0x89, 0xe7, 0x97, 0xc7, 0xaf, 0x47, 0x89 45 | }; 46 | /* Data 'arcfour' hash test vectors */ 47 | const byte testVector3[32] = 48 | { 0xff, 0x8c, 0xf2, 0x68, 0x09, 0x4c, 0x87, 0xb9, 49 | 0x5f, 0x74, 0xce, 0x6f, 0xee, 0x9d, 0x30, 0x03, 50 | 0xa5, 0xf9, 0xfe, 0x69, 0x44, 0x65, 0x3c, 0xd5, 51 | 0x0e, 0x66, 0xbf, 0x18, 0x9c, 0x63, 0xf6, 0x99 52 | }; 53 | 54 | 55 | void testFunc(const byte ExpectedOutput[32], const byte *data, byte dataLen) 56 | { 57 | byte hashLen = 32; /* 256-bit */ 58 | byte digest[hashLen]; /* Output buffer */ 59 | byte digest_2[hashLen]; /* Output buffer for chunk by chunk API */ 60 | spritz_ctx hash_ctx; /* the CTX for chunk by chunk API */ 61 | unsigned int i; 62 | 63 | /* Print input */ 64 | for (i = 0; i < dataLen; i++) { 65 | Serial.write(data[i]); 66 | } 67 | Serial.println(); 68 | 69 | spritz_hash_setup(&hash_ctx); 70 | /* For easy test: code add a byte each time */ 71 | for (i = 0; i < dataLen; i++) { 72 | spritz_hash_update(&hash_ctx, data + i, 1); 73 | } 74 | spritz_hash_final(&hash_ctx, digest_2, hashLen); 75 | 76 | spritz_hash(digest, hashLen, data, dataLen); 77 | 78 | for (i = 0; i < sizeof(digest); i++) { 79 | if (digest[i] < 0x10) { /* To print "0F" not "F" */ 80 | Serial.write('0'); 81 | } 82 | Serial.print(digest[i], HEX); 83 | } 84 | 85 | /* Check the output */ 86 | if (spritz_compare(digest, ExpectedOutput, sizeof(digest)) || spritz_compare(digest_2, ExpectedOutput, sizeof(digest_2))) { 87 | /* If the output is wrong "Alert" */ 88 | digitalWrite(LED_BUILTIN, HIGH); /* Turn pin LED_BUILTIN On (Most boards have this LED connected to digital pin 13) */ 89 | Serial.println("\n** WARNING: Output != Test_Vector **"); 90 | } 91 | Serial.println(); 92 | } 93 | 94 | void setup() { 95 | /* Initialize serial and wait for port to open */ 96 | Serial.begin(9600); 97 | while (!Serial) { 98 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 99 | } 100 | 101 | /* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */ 102 | pinMode(LED_BUILTIN, OUTPUT); 103 | digitalWrite(LED_BUILTIN, LOW); 104 | } 105 | 106 | void loop() { 107 | Serial.println("[Spritz spritz_hash*() test]\n"); 108 | 109 | /* Data: ABC */ 110 | testFunc(testVector1, testData1, sizeof(testData1)); 111 | /* Data: spam */ 112 | testFunc(testVector2, testData2, sizeof(testData2)); 113 | /* Data: arcfour */ 114 | testFunc(testVector3, testData3, sizeof(testData3)); 115 | 116 | delay(5000); /* Wait 5s */ 117 | Serial.println(); 118 | } 119 | -------------------------------------------------------------------------------- /examples/SpritzMACTest/SpritzMACTest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Spritz Cipher MAC Test 3 | * 4 | * This example code test SpritzCipher library MAC output. 5 | * 6 | * The circuit: No external hardware needed. 7 | * 8 | * by Abderraouf Adjal. 9 | * 10 | * This example code is in the public domain. 11 | */ 12 | 13 | /* ArduinoSpritzCipher documentation: */ 14 | 15 | 16 | /* ArduinoSpritzCipher is configurable in with: 17 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 18 | * SPRITZ_USE_LIBC. 19 | * For detailed information, read the documentation. 20 | */ 21 | #include 22 | 23 | 24 | /* Data to input */ 25 | const byte testMsg[3] = { 'A', 'B', 'C' }; 26 | const byte testKey[3] = { 0x00, 0x01, 0x02 }; 27 | 28 | /* Test vectors */ 29 | /* MSG='ABC' KEY=0x00,0x01,0x02 MAC test vectors */ 30 | const byte MACtestVector[32] = 31 | { 0xbe, 0x8e, 0xdc, 0xf2, 0x76, 0xcf, 0x57, 0xb4, 32 | 0x0e, 0xbc, 0x8e, 0x22, 0x43, 0x45, 0x7e, 0x3e, 33 | 0xb7, 0xc6, 0x4d, 0x4e, 0x99, 0x1e, 0x93, 0x58, 34 | 0xce, 0x81, 0xef, 0xb1, 0x6c, 0xce, 0xc7, 0xed 35 | }; 36 | 37 | 38 | void testFunc(const byte ExpectedOutput[32], const byte *msg, byte msgLen, const byte *key, byte keyLen) 39 | { 40 | byte macLen = 32; /* 256-bit */ 41 | byte digest[macLen]; /* Output buffer */ 42 | unsigned int i; 43 | 44 | spritz_mac(digest, macLen, msg, msgLen, key, keyLen); 45 | 46 | for (i = 0; i < sizeof(digest); i++) { 47 | if (digest[i] < 0x10) { /* To print "0F" not "F" */ 48 | Serial.write('0'); 49 | } 50 | Serial.print(digest[i], HEX); 51 | } 52 | 53 | /* Check the output */ 54 | if (spritz_compare(digest, ExpectedOutput, sizeof(digest))) { 55 | /* If the output is wrong "Alert" */ 56 | digitalWrite(LED_BUILTIN, HIGH); /* Turn pin LED_BUILTIN On (Most boards have this LED connected to digital pin 13) */ 57 | Serial.println("\n** WARNING: Output != Test_Vector **"); 58 | } 59 | Serial.println(); 60 | } 61 | 62 | void setup() { 63 | /* Initialize serial and wait for port to open */ 64 | Serial.begin(9600); 65 | while (!Serial) { 66 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 67 | } 68 | 69 | /* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */ 70 | pinMode(LED_BUILTIN, OUTPUT); 71 | digitalWrite(LED_BUILTIN, LOW); 72 | } 73 | 74 | void loop() { 75 | Serial.println("[Spritz spritz_mac(MSG='ABC' KEY=0x00,0x01,0x02) test]\n"); 76 | 77 | /* MSG='ABC' KEY=0x00,0x01,0x02 MAC test vectors */ 78 | testFunc(MACtestVector, testMsg, sizeof(testMsg), testKey, sizeof(testKey)); 79 | 80 | delay(5000); /* Wait 5s */ 81 | Serial.println(); 82 | } 83 | -------------------------------------------------------------------------------- /examples/SpritzStreamTest/SpritzStreamTest.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * Spritz Cipher Stream Test 3 | * 4 | * This example code test SpritzCipher library stream (PRNG) output 5 | * using test vectors from Spritz paper "RS14.pdf" Page 30: 6 | * 7 | * 8 | * The circuit: No external hardware needed. 9 | * 10 | * by Abderraouf Adjal. 11 | * 12 | * This example code is in the public domain. 13 | */ 14 | 15 | /* ArduinoSpritzCipher documentation: */ 16 | 17 | 18 | /* ArduinoSpritzCipher is configurable in with: 19 | * SPRITZ_TIMING_SAFE_CRUSH, SPRITZ_WIPE_TRACES, SPRITZ_WIPE_TRACES_PARANOID, 20 | * SPRITZ_USE_LIBC. 21 | * For detailed information, read the documentation. 22 | */ 23 | #include 24 | 25 | 26 | /* Keys to input */ 27 | const byte testKey1[3] = { 'A', 'B', 'C' }; 28 | const byte testKey2[4] = { 's', 'p', 'a', 'm' }; 29 | const byte testKey3[7] = { 'a', 'r', 'c', 'f', 'o', 'u', 'r' }; 30 | 31 | /* Test vectors */ 32 | /* Key 'ABC' stream test vectors */ 33 | const byte testVector1[32] = 34 | { 0x77, 0x9a, 0x8e, 0x01, 0xf9, 0xe9, 0xcb, 0xc0, 35 | 0x7f, 0xb9, 0x6b, 0x7e, 0xc1, 0x93, 0x6e, 0x24, 36 | 0x2e, 0x54, 0xf1, 0x8b, 0x6c, 0x3c, 0x76, 0xcf, 37 | 0x8f, 0xc8, 0x2f, 0x22, 0x2b, 0x20, 0xe4, 0xbb 38 | }; 39 | /* Key 'spam' stream test vectors */ 40 | const byte testVector2[32] = 41 | { 0xf0, 0x60, 0x9a, 0x1d, 0xf1, 0x43, 0xce, 0xbf, 42 | 0x58, 0xdc, 0xff, 0x3d, 0x30, 0xb7, 0xc2, 0x59, 43 | 0x9d, 0x2f, 0xb0, 0xdc, 0x2b, 0x7a, 0x12, 0xc4, 44 | 0xe8, 0x92, 0x16, 0xcc, 0x5d, 0xe9, 0x29, 0x67 45 | }; 46 | /* Key 'arcfour' stream test vectors */ 47 | const byte testVector3[32] = 48 | { 0x1a, 0xfa, 0x8b, 0x5e, 0xe3, 0x37, 0xdb, 0xc7, 49 | 0x22, 0x59, 0x7f, 0x0f, 0xdc, 0x3a, 0x42, 0xc7, 50 | 0x75, 0x4b, 0xf1, 0x03, 0x6f, 0x54, 0xfb, 0x4a, 51 | 0xeb, 0x03, 0x35, 0xd4, 0xa4, 0xe9, 0xa3, 0x6e 52 | }; 53 | 54 | 55 | void testFunc(const byte ExpectedOutput[32], const byte *data, byte dataLen) 56 | { 57 | byte buf[32]; /* Output buffer */ 58 | spritz_ctx s_ctx; 59 | unsigned int i; 60 | 61 | /* Print key */ 62 | for (i = 0; i < dataLen; i++) { 63 | Serial.write(data[i]); 64 | } 65 | Serial.println(); 66 | 67 | spritz_setup(&s_ctx, data, dataLen); 68 | 69 | for (i = 0; i < sizeof(buf); i++) { 70 | buf[i] = spritz_random8(&s_ctx); 71 | if (buf[i] < 0x10) { /* To print "0F" not "F" */ 72 | Serial.write('0'); 73 | } 74 | Serial.print(buf[i], HEX); 75 | } 76 | 77 | /* Check the output */ 78 | if (spritz_compare(buf, ExpectedOutput, sizeof(buf))) { 79 | /* If the output is wrong "Alert" */ 80 | digitalWrite(LED_BUILTIN, HIGH); /* Turn pin LED_BUILTIN On (Most boards have this LED connected to digital pin 13) */ 81 | Serial.println("\n** WARNING: Output != Test_Vector **"); 82 | } 83 | Serial.println(); 84 | } 85 | 86 | void setup() { 87 | /* Initialize serial and wait for port to open */ 88 | Serial.begin(9600); 89 | while (!Serial) { 90 | ; /* Wait for serial port to connect. Needed for Leonardo only */ 91 | } 92 | 93 | /* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */ 94 | pinMode(LED_BUILTIN, OUTPUT); 95 | digitalWrite(LED_BUILTIN, LOW); 96 | } 97 | 98 | void loop() { 99 | Serial.println("[Spritz spritz_random8() test]\n"); 100 | 101 | /* Key: ABC */ 102 | testFunc(testVector1, testKey1, sizeof(testKey1)); 103 | /* Key: spam */ 104 | testFunc(testVector2, testKey2, sizeof(testKey2)); 105 | /* Key: arcfour */ 106 | testFunc(testVector3, testKey3, sizeof(testKey3)); 107 | 108 | delay(5000); /* Wait 5s */ 109 | Serial.println(); 110 | } 111 | -------------------------------------------------------------------------------- /extras/Spritz cipher white paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abderraouf-adjal/ArduinoSpritzCipher/d089f3683b16d86d38086c6ca68ac20bef304fd3/extras/Spritz cipher white paper.pdf -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | # Arduino IDE syntax coloring map for SpritzCipher library 2 | 3 | # Datatypes: 4 | spritz_ctx KEYWORD1 5 | 6 | # Methods and Functions 7 | spritz_compare KEYWORD2 8 | spritz_memzero KEYWORD2 9 | spritz_state_memzero KEYWORD2 10 | spritz_setup KEYWORD2 11 | spritz_setup_withIV KEYWORD2 12 | spritz_random8 KEYWORD2 13 | spritz_random32 KEYWORD2 14 | spritz_random32_uniform KEYWORD2 15 | spritz_add_entropy KEYWORD2 16 | spritz_crypt KEYWORD2 17 | spritz_crypt_inplace KEYWORD2 18 | spritz_hash_setup KEYWORD2 19 | spritz_hash_update KEYWORD2 20 | spritz_hash_final KEYWORD2 21 | spritz_hash KEYWORD2 22 | spritz_mac_setup KEYWORD2 23 | spritz_mac_update KEYWORD2 24 | spritz_mac_final KEYWORD2 25 | spritz_mac KEYWORD2 26 | 27 | # Constants 28 | SPRITZ_N LITERAL1 29 | SPRITZ_LIBRARY_VERSION_STRING LITERAL1 30 | SPRITZ_LIBRARY_VERSION_MAJOR LITERAL1 31 | SPRITZ_LIBRARY_VERSION_MINOR LITERAL1 32 | SPRITZ_LIBRARY_VERSION_PATCH LITERAL1 33 | SPRITZ_USE_LIBC LITERAL1 34 | SPRITZ_WIPE_TRACES LITERAL1 35 | SPRITZ_WIPE_TRACES_PARANOID LITERAL1 36 | SPRITZ_TIMING_SAFE_CRUSH LITERAL1 37 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SpritzCipher", 3 | "version": "1.2.0", 4 | "description": "Spritz library for Arduino, CSPRNG, cryptographic hash and MAC functions, symmetric-key data encryption, and some general-purpose functions.", 5 | "keywords": "arduino, spritz, cipher, crypto, encryption, hash, mac, prng, rng, security", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/abderraouf-adjal/ArduinoSpritzCipher.git" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Abderraouf Adjal", 13 | "email": "abderraouf.adjal@gmail.com", 14 | "url": "https://github.com/abderraouf-adjal", 15 | "maintainer": true 16 | } 17 | ], 18 | "license": "ISC", 19 | "homepage": "https://github.com/abderraouf-adjal/ArduinoSpritzCipher", 20 | "frameworks": "*", 21 | "platforms": "*" 22 | } 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SpritzCipher 2 | version=1.2.0 3 | author=Abderraouf Adjal 4 | maintainer=Abderraouf Adjal 5 | sentence=Spritz library for Arduino, CSPRNG, cryptographic hash and MAC functions, symmetric-key data encryption, and some general-purpose functions. 6 | paragraph=Spritz is a spongy RC4-like stream cipher and hash function. This library contains a cryptographic pseudo-random number generator, cryptographic hash and message authentication code (MAC) functions, can perform symmetric-key authenticated data encryption, and general-purpose functions for timing-safe comparison and wiping data from memory. 7 | category=Data Processing 8 | url=https://github.com/abderraouf-adjal/ArduinoSpritzCipher 9 | includes=SpritzCipher.h 10 | architectures=* 11 | -------------------------------------------------------------------------------- /src/SpritzCipher.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /** 3 | * Copyright (c) 2015-2020 Abderraouf Adjal 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | 19 | #include "SpritzCipher.h" /* Data types and constants */ 20 | 21 | 22 | #define SPRITZ_N_MINUS_1 255U /* SPRITZ_N - 1 */ 23 | #define SPRITZ_N_HALF 128U /* SPRITZ_N / 2 */ 24 | 25 | 26 | static inline void 27 | spritz_state_s_swap(spritz_ctx *ctx, uint8_t index_a, uint8_t index_b) 28 | { 29 | #ifdef SPRITZ_WIPE_TRACES_PARANOID 30 | ctx->tmp1 = ctx->s[index_a]; 31 | ctx->s[index_a] = ctx->s[index_b]; 32 | ctx->s[index_b] = ctx->tmp1; 33 | #else 34 | uint8_t tmp = ctx->s[index_a]; 35 | ctx->s[index_a] = ctx->s[index_b]; 36 | ctx->s[index_b] = tmp; 37 | #endif /* SPRITZ_WIPE_TRACES_PARANOID */ 38 | } 39 | 40 | 41 | static inline void 42 | spritz_state_init(spritz_ctx *ctx) 43 | { 44 | uint8_t i = 0; 45 | 46 | /* Loop for SPRITZ_N=256 */ 47 | do { 48 | ctx->s[i] = i; 49 | } while (++i); 50 | 51 | ctx->i = 0; 52 | ctx->j = 0; 53 | ctx->k = 0; 54 | ctx->z = 0; 55 | ctx->a = 0; 56 | ctx->w = 1U; 57 | } 58 | 59 | static inline void 60 | update(spritz_ctx *ctx) 61 | { 62 | ctx->i = (uint8_t)(ctx->i + ctx->w); 63 | ctx->j = (uint8_t)(ctx->s[(uint8_t)(ctx->s[ctx->i] + ctx->j)] + ctx->k); 64 | ctx->k = (uint8_t)(ctx->s[ctx->j] + ctx->k + ctx->i); 65 | spritz_state_s_swap(ctx, ctx->i, ctx->j); 66 | } 67 | 68 | static inline void 69 | whip(spritz_ctx *ctx) 70 | { 71 | uint8_t i; 72 | 73 | for (i = 0; i < SPRITZ_N_HALF; i++) { 74 | update(ctx); 75 | update(ctx); 76 | update(ctx); 77 | update(ctx); 78 | } 79 | 80 | ctx->w = (uint8_t)(ctx->w + 2U); 81 | } 82 | 83 | #ifdef SPRITZ_TIMING_SAFE_CRUSH 84 | static inline void 85 | /* SPRITZ_TIMING_SAFE_CRUSH and GCC, disable optimization for this function */ 86 | # if defined(__GNUC__) && !defined(__clang__) 87 | __attribute__ ((optimize("O0"))) 88 | /* SPRITZ_TIMING_SAFE_CRUSH and Clang, disable optimization for this function */ 89 | # elif defined(__clang__) 90 | __attribute__ ((optnone)) 91 | # endif 92 | crush(spritz_ctx *ctx) 93 | { 94 | uint8_t i = 0, j = SPRITZ_N_MINUS_1; 95 | # ifdef SPRITZ_WIPE_TRACES_PARANOID 96 | for (; i < SPRITZ_N_HALF; i++, j--) { 97 | ctx->tmp1 = ctx->s[i]; /* s_i=ctx->s[i] */ 98 | ctx->tmp2 = ctx->s[j]; /* s_j=ctx->s[j] */ 99 | if (ctx->tmp1 > ctx->tmp2) { /* if(s_i>s_j) */ 100 | ctx->s[i] = ctx->tmp2; /* ctx->s[i]=s_j */ 101 | ctx->s[j] = ctx->tmp1; /* ctx->s[j]=s_i */ 102 | } 103 | else { 104 | ctx->s[i] = ctx->tmp1; /* ctx->s[i]=s_i */ 105 | ctx->s[j] = ctx->tmp2; /* ctx->s[j]=s_j */ 106 | } 107 | } 108 | # else /* SPRITZ_WIPE_TRACES_PARANOID */ 109 | uint8_t s_i, s_j; 110 | for (; i < SPRITZ_N_HALF; i++, j--) { 111 | s_i = ctx->s[i]; 112 | s_j = ctx->s[j]; 113 | if (s_i > s_j) { 114 | ctx->s[i] = s_j; 115 | ctx->s[j] = s_i; 116 | } 117 | else { 118 | ctx->s[i] = s_i; 119 | ctx->s[j] = s_j; 120 | } 121 | } 122 | # endif /* SPRITZ_WIPE_TRACES_PARANOID */ 123 | } 124 | #else /* SPRITZ_TIMING_SAFE_CRUSH */ 125 | /* non equal/safe time crush() */ 126 | static void 127 | crush(spritz_ctx *ctx) 128 | { 129 | uint8_t i = 0, j = SPRITZ_N_MINUS_1; 130 | for (; i < SPRITZ_N_HALF; i++, j--) { 131 | if (ctx->s[i] > ctx->s[j]) { 132 | spritz_state_s_swap(ctx, i, j); 133 | } 134 | } 135 | } 136 | #endif /* SPRITZ_TIMING_SAFE_CRUSH */ 137 | 138 | static inline void 139 | shuffle(spritz_ctx *ctx) 140 | { 141 | whip(ctx); 142 | crush(ctx); 143 | whip(ctx); 144 | crush(ctx); 145 | whip(ctx); 146 | ctx->a = 0; 147 | } 148 | 149 | /* Note: Nibble=4-bit; Octet=2*Nibble=8-bit; Byte=Octet (in modern/most computers) */ 150 | static inline void 151 | absorbNibble(spritz_ctx *ctx, const uint8_t nibble) 152 | { 153 | if (ctx->a == SPRITZ_N_HALF) { 154 | shuffle(ctx); 155 | } 156 | spritz_state_s_swap(ctx, ctx->a, (uint8_t)(SPRITZ_N_HALF + nibble)); 157 | ctx->a++; 158 | } 159 | static inline void 160 | absorb(spritz_ctx *ctx, const uint8_t octet) 161 | { 162 | absorbNibble(ctx, octet % 16); /* With the Right/Low nibble */ 163 | absorbNibble(ctx, octet / 16); /* With the Left/High nibble */ 164 | } 165 | static inline void 166 | absorbBytes(spritz_ctx *ctx, const uint8_t *buf, uint16_t len) 167 | { 168 | uint16_t i; 169 | 170 | for (i = 0; i < len; i++) { 171 | absorb(ctx, buf[i]); 172 | } 173 | } 174 | 175 | static inline void 176 | absorbStop(spritz_ctx *ctx) 177 | { 178 | if (ctx->a == SPRITZ_N_HALF) { 179 | shuffle(ctx); 180 | } 181 | 182 | ctx->a++; 183 | } 184 | 185 | static inline uint8_t 186 | output(spritz_ctx *ctx) 187 | { 188 | ctx->z = ctx->s[(ctx->s[(ctx->s[(ctx->z + ctx->k) % SPRITZ_N] + ctx->i) % SPRITZ_N] + ctx->j) % SPRITZ_N]; 189 | return ctx->z; 190 | } 191 | 192 | static inline uint8_t 193 | drip(spritz_ctx *ctx) 194 | { 195 | if (ctx->a) { 196 | shuffle(ctx); 197 | } 198 | update(ctx); 199 | return output(ctx); 200 | } 201 | 202 | 203 | /* |====================|| User Functions ||====================| */ 204 | 205 | /** spritz_compare() 206 | * Timing-safe equality comparison for `data_a` and `data_b`. 207 | * This function can be used to compare the password's hash safely. 208 | * 209 | * Parameter data_a: Data a to be compare with b. 210 | * Parameter data_b: Data b to be compare with a. 211 | * Parameter len: Length of the array in bytes. 212 | * 213 | * Return: Equality result. 214 | * Zero (0x00) if `data_a` equals `data_b` OR if `len` is zero, 215 | * Non-zero value if they are NOT equal. 216 | */ 217 | uint8_t 218 | /* Disable optimization for this function if compiler is GCC */ 219 | #if defined(__GNUC__) && !defined(__clang__) 220 | __attribute__ ((optimize("O0"))) 221 | /* Disable optimization for this function if compiler is Clang */ 222 | #elif defined(__clang__) 223 | __attribute__ ((optnone)) 224 | #endif 225 | spritz_compare(const uint8_t *data_a, const uint8_t *data_b, uint16_t len) 226 | { 227 | uint8_t d = 0; 228 | uint16_t i; 229 | 230 | for (i = 0; i < len; i++) { 231 | d |= data_a[i] ^ data_b[i]; 232 | } 233 | 234 | #ifdef SPRITZ_WIPE_TRACES_PARANOID 235 | # if !defined(__GNUC__) && !defined(__clang__) 236 | /* Not GCC or Clang, Optimization isn't off. */ 237 | /* It may be possible to use `d=!!d;` for performnce, 238 | * But audit the assembly code first. 239 | */ 240 | d |= d >> 1; /* |_|_|_|_|_|_|S|D| `D |= S` */ 241 | d |= d >> 2; /* |_|_|_|_|_|S|_|D| */ 242 | d |= d >> 3; /* |_|_|_|_|S|_|_|D| */ 243 | d |= d >> 4; /* |_|_|_|S|_|_|_|D| */ 244 | d |= d >> 5; /* |_|_|S|_|_|_|_|D| */ 245 | d |= d >> 6; /* |_|S|_|_|_|_|_|D| */ 246 | d |= d >> 7; /* |S|_|_|_|_|_|_|D| */ 247 | d &= 1; /* |0|0|0|0|0|0|0|D| Zero all bits except LSB */ 248 | # else 249 | /* Else if GCC or Clang, no optimization */ 250 | /* Timing-safe non-zero value to `1`. */ 251 | if (d == 0U) { 252 | d = 0U; 253 | } 254 | else { 255 | d = 1U; 256 | } 257 | # endif /* !defined(__GNUC__) && !defined(__clang__) */ 258 | #endif /* SPRITZ_WIPE_TRACES_PARANOID */ 259 | 260 | return d; 261 | } 262 | 263 | /** spritz_memzero() 264 | * Wipe `buf` data by replacing it with zeros (0x00). 265 | * 266 | * Parameter buf: Data to replace it with zeros (0x00). 267 | * Parameter len: Length of array in bytes. 268 | */ 269 | void 270 | /* Disable optimization for this function if compiler is GCC */ 271 | #if defined(__GNUC__) && !defined(__clang__) 272 | __attribute__ ((optimize("O0"))) 273 | /* Disable optimization for this function if compiler is Clang */ 274 | #elif defined(__clang__) 275 | __attribute__ ((optnone)) 276 | #endif 277 | spritz_memzero(uint8_t *buf, uint16_t len) 278 | { 279 | #ifdef SPRITZ_USE_LIBC 280 | memset(buf, 0, len * sizeof(uint8_t)); 281 | #else 282 | uint16_t i; 283 | 284 | for (i = 0; i < len; i++) { 285 | buf[i] = 0; 286 | } 287 | #endif 288 | } 289 | 290 | /** spritz_state_memzero() 291 | * Wipe `spritz_ctx`'s data by replacing its data with zeros (0x00). 292 | * 293 | * Parameter ctx: The context. 294 | */ 295 | void 296 | /* Disable optimization for this function if compiler is GCC */ 297 | #if defined(__GNUC__) && !defined(__clang__) 298 | __attribute__ ((optimize("O0"))) 299 | /* Disable optimization for this function if compiler is Clang */ 300 | #elif defined(__clang__) 301 | __attribute__ ((optnone)) 302 | #endif 303 | spritz_state_memzero(spritz_ctx *ctx) 304 | { 305 | #ifdef SPRITZ_USE_LIBC 306 | memset(ctx->s, 0, SPRITZ_N); 307 | #else 308 | uint8_t i = 0; 309 | /* Loop for SPRITZ_N=256 */ 310 | do { 311 | ctx->s[i] = 0; 312 | } while (++i); 313 | #endif 314 | 315 | ctx->i = 0; 316 | ctx->j = 0; 317 | ctx->k = 0; 318 | ctx->z = 0; 319 | ctx->a = 0; 320 | ctx->w = 0; 321 | 322 | #ifdef SPRITZ_WIPE_TRACES_PARANOID 323 | ctx->tmp1 = 0; 324 | ctx->tmp2 = 0; 325 | #endif 326 | } 327 | 328 | 329 | /** spritz_setup() 330 | * Setup the spritz state `spritz_ctx` with a key. 331 | * 332 | * Parameter ctx: The context. 333 | * Parameter key: The key. 334 | * Parameter keylen: Length of the key in bytes. 335 | */ 336 | void 337 | spritz_setup(spritz_ctx *ctx, 338 | const uint8_t *key, uint8_t keyLen) 339 | { 340 | spritz_state_init(ctx); 341 | absorbBytes(ctx, key, keyLen); 342 | if (ctx->a) { 343 | shuffle(ctx); 344 | } 345 | } 346 | 347 | /** spritz_setup_withiv() 348 | * Setup the spritz state `spritz_ctx` with a key and nonce/salt/iv. 349 | * 350 | * Parameter ctx: The context. 351 | * Parameter key: The key. 352 | * Parameter keylen: Length of the key in bytes. 353 | * Parameter nonce: The nonce (salt). 354 | * Parameter noncelen: Length of the nonce in bytes. 355 | */ 356 | void 357 | spritz_setup_withIV(spritz_ctx *ctx, 358 | const uint8_t *key, uint8_t keyLen, 359 | const uint8_t *nonce, uint8_t nonceLen) 360 | { 361 | spritz_state_init(ctx); 362 | absorbBytes(ctx, key, keyLen); 363 | absorbStop(ctx); 364 | absorbBytes(ctx, nonce, nonceLen); 365 | if (ctx->a) { 366 | shuffle(ctx); 367 | } 368 | } 369 | 370 | /** spritz_random8() 371 | * Generates a random byte from the spritz state `spritz_ctx`. 372 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 373 | * 374 | * Parameter ctx: The context. 375 | * 376 | * Return: Byte of keystream. 377 | */ 378 | uint8_t 379 | spritz_random8(spritz_ctx *ctx) 380 | { 381 | return drip(ctx); 382 | } 383 | 384 | /** spritz_random32() 385 | * Generates a random 32-bit (4 bytes) from the spritz state `spritz_ctx`. 386 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 387 | * 388 | * Parameter ctx: The context. 389 | * 390 | * Return: 32-bit (4 bytes) of keystream. 391 | */ 392 | uint32_t 393 | spritz_random32(spritz_ctx *ctx) 394 | { 395 | return (uint32_t)( 396 | ((uint32_t)(drip(ctx)) << 0) 397 | | ((uint32_t)(drip(ctx)) << 8) 398 | | ((uint32_t)(drip(ctx)) << 16) 399 | | ((uint32_t)(drip(ctx)) << 24)); 400 | } 401 | 402 | /** spritz_random32_uniform() 403 | * Calculate an uniformly distributed random number less than `upper_bound` avoiding modulo bias. 404 | * 405 | * Uniformity is achieved by generating new random numbers until the one 406 | * returned is outside the range [0, 2**32 % upper_bound). 407 | * This guarantees the selected random number will be inside 408 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 409 | * after reduction modulo upper_bound. 410 | * spritz_random32_uniform() derives from OpenBSD's arc4random_uniform() 411 | * 412 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 413 | * 414 | * Parameter ctx: The context. 415 | * Parameter upper_bound: The roof, `upper_bound - 1` is the largest number that can be returned. 416 | * 417 | * Return: Random number less than upper_bound, 0 if upper_bound<2. 418 | */ 419 | uint32_t 420 | spritz_random32_uniform(spritz_ctx *ctx, uint32_t upper_bound) 421 | { 422 | uint32_t r, min; 423 | 424 | if (upper_bound < 2U) 425 | { 426 | return 0; 427 | } 428 | 429 | /* 2**32 % x == (2**32 - x) % x */ 430 | min = (uint32_t)(-upper_bound % upper_bound); 431 | 432 | /* This could theoretically loop forever but each retry has 433 | * p > 0.5 (worst case, usually far better) of selecting a 434 | * number inside the range we need, so it should rarely need 435 | * to re-roll. 436 | */ 437 | for (;;) { 438 | r = spritz_random32(ctx); 439 | if (r >= min) 440 | { 441 | return (uint32_t)(r % upper_bound); 442 | } 443 | } 444 | } 445 | 446 | /** spritz_add_entropy() 447 | * Add entropy to the spritz state `spritz_ctx` using absorb(). 448 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 449 | * 450 | * Parameter ctx: The context. 451 | * Parameter entropy: The entropy array. 452 | * Parameter len: Length of the entropy array in bytes. 453 | */ 454 | void 455 | spritz_add_entropy(spritz_ctx *ctx, 456 | const uint8_t *entropy, uint16_t len) 457 | { 458 | absorbBytes(ctx, entropy, len); 459 | } 460 | 461 | /** spritz_crypt() 462 | * Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream. 463 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 464 | * 465 | * Parameter ctx: The context. 466 | * Parameter data: The data to encrypt or decrypt. 467 | * Parameter datalen: Length of the data in bytes. 468 | * Parameter dataout: The output. 469 | */ 470 | void 471 | spritz_crypt(spritz_ctx *ctx, 472 | const uint8_t *data, uint16_t dataLen, 473 | uint8_t *dataOut) 474 | { 475 | uint16_t i; 476 | 477 | for (i = 0; i < dataLen; i++) { 478 | dataOut[i] = data[i] ^ drip(ctx); 479 | } 480 | } 481 | 482 | /** spritz_crypt_inplace() 483 | * Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream 484 | * and put the output in the same buffer `data`. 485 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 486 | * 487 | * Parameter ctx: The context. 488 | * Parameter data: The data to encrypt or decrypt, also the output. 489 | * Parameter datalen: Length of the data in bytes. 490 | */ 491 | void 492 | spritz_crypt_inplace(spritz_ctx *ctx, 493 | uint8_t *data, uint16_t dataLen) 494 | { 495 | uint16_t i; 496 | 497 | for (i = 0; i < dataLen; i++) { 498 | data[i] ^= drip(ctx); 499 | } 500 | } 501 | 502 | 503 | /** spritz_hash_setup() 504 | * Setup the spritz hash state `spritz_ctx`. 505 | * 506 | * Parameter hash_ctx: The hash context (ctx). 507 | */ 508 | void 509 | spritz_hash_setup(spritz_ctx *hash_ctx) 510 | { 511 | spritz_state_init(hash_ctx); 512 | } 513 | 514 | /** spritz_hash_update() 515 | * Add a message/data chunk `data` to hash. 516 | * 517 | * Parameter hash_ctx: The hash context (ctx). 518 | * Parameter data: The data chunk to hash. 519 | * Parameter datalen: Length of the data in bytes. 520 | */ 521 | void 522 | spritz_hash_update(spritz_ctx *hash_ctx, 523 | const uint8_t *data, uint16_t dataLen) 524 | { 525 | absorbBytes(hash_ctx, data, dataLen); 526 | } 527 | 528 | /** spritz_hash_final() 529 | * Output the hash digest. 530 | * 531 | * Parameter hash_ctx: The hash context (ctx). 532 | * Parameter digest: The digest (hash) output. 533 | * Parameter digestlen: Length of the digest in bytes. 534 | */ 535 | void 536 | spritz_hash_final(spritz_ctx *hash_ctx, 537 | uint8_t *digest, uint8_t digestLen) 538 | { 539 | uint8_t i; 540 | 541 | absorbStop(hash_ctx); 542 | absorb(hash_ctx, digestLen); 543 | /* squeeze() */ 544 | if (hash_ctx->a) { 545 | shuffle(hash_ctx); 546 | } 547 | for (i = 0; i < digestLen; i++) { 548 | digest[i] = drip(hash_ctx); 549 | } 550 | } 551 | 552 | /** spritz_hash() 553 | * Cryptographic hash function. 554 | * 555 | * Parameter digest: The digest (hash) output. 556 | * Parameter digestlen: Length of the digest in bytes. 557 | * Parameter data: The data to hash. 558 | * Parameter datalen: Length of the data in bytes. 559 | */ 560 | void 561 | spritz_hash(uint8_t *digest, uint8_t digestLen, 562 | const uint8_t *data, uint16_t dataLen) 563 | { 564 | uint8_t i; 565 | spritz_ctx hash_ctx; 566 | 567 | /* spritz_hash_setup() */ 568 | spritz_state_init(&hash_ctx); 569 | 570 | /* spritz_hash_update() */ 571 | absorbBytes(&hash_ctx, data, dataLen); 572 | 573 | /* Same as spritz_hash_final() */ 574 | absorbStop(&hash_ctx); 575 | absorb(&hash_ctx, digestLen); 576 | /* squeeze() */ 577 | if (hash_ctx.a) { 578 | shuffle(&hash_ctx); 579 | } 580 | for (i = 0; i < digestLen; i++) { 581 | digest[i] = drip(&hash_ctx); 582 | } 583 | 584 | /* `hash_ctx` data will be replaced with 0x00 if SPRITZ_WIPE_TRACES is defined */ 585 | #ifdef SPRITZ_WIPE_TRACES 586 | spritz_state_memzero(&hash_ctx); 587 | #endif 588 | } 589 | 590 | 591 | /** spritz_mac_setup() 592 | * Setup the spritz message authentication code (MAC) state `spritz_ctx`. 593 | * 594 | * Parameter mac_ctx: The message authentication code (MAC) context (ctx). 595 | * Parameter key: The secret key. 596 | * Parameter keylen: Length of the key in bytes. 597 | */ 598 | void 599 | spritz_mac_setup(spritz_ctx *mac_ctx, 600 | const uint8_t *key, uint16_t keyLen) 601 | { 602 | spritz_state_init(mac_ctx); /* spritz_hash_setup() */ 603 | absorbBytes(mac_ctx, key, keyLen); /* spritz_hash_update() */ 604 | absorbStop(mac_ctx); 605 | } 606 | 607 | /** spritz_mac_update() 608 | * Add a message/data chunk to message authentication code (MAC). 609 | * 610 | * Parameter hash_ctx: The hash context (ctx). 611 | * Parameter msg: The message chunk to be authenticated. 612 | * Parameter msglen: Length of the message in bytes. 613 | */ 614 | void 615 | spritz_mac_update(spritz_ctx *mac_ctx, 616 | const uint8_t *msg, uint16_t msgLen) 617 | { 618 | absorbBytes(mac_ctx, msg, msgLen); /* spritz_hash_update() */ 619 | } 620 | 621 | /** spritz_mac_final() 622 | * Output the message authentication code (MAC) digest. 623 | * 624 | * Parameter mac_ctx: The message authentication code (MAC) context (ctx). 625 | * Parameter digest: Message authentication code (MAC) digest output. 626 | * Parameter digestlen: Length of the digest in bytes. 627 | */ 628 | void 629 | spritz_mac_final(spritz_ctx *mac_ctx, 630 | uint8_t *digest, uint8_t digestLen) 631 | { 632 | /* Same as spritz_hash_final() */ 633 | uint8_t i; 634 | 635 | absorbStop(mac_ctx); 636 | absorb(mac_ctx, digestLen); 637 | /* squeeze() */ 638 | if (mac_ctx->a) { 639 | shuffle(mac_ctx); 640 | } 641 | for (i = 0; i < digestLen; i++) { 642 | digest[i] = drip(mac_ctx); 643 | } 644 | } 645 | 646 | /** spritz_mac() 647 | * Message Authentication Code (MAC) function. 648 | * 649 | * Parameter digest: Message authentication code (MAC) digest output. 650 | * Parameter digestlen: Length of the digest in bytes. 651 | * Parameter msg: The message to be authenticated. 652 | * Parameter msglen: Length of the message in bytes. 653 | * Parameter key: The secret key. 654 | * Parameter keylen: Length of the key in bytes. 655 | */ 656 | void 657 | spritz_mac(uint8_t *digest, uint8_t digestLen, 658 | const uint8_t *msg, uint16_t msgLen, 659 | const uint8_t *key, uint16_t keyLen) 660 | { 661 | uint8_t i; 662 | spritz_ctx mac_ctx; 663 | 664 | /* spritz_mac_setup() */ 665 | spritz_state_init(&mac_ctx); /* spritz_hash_setup() */ 666 | absorbBytes(&mac_ctx, key, keyLen); /* spritz_hash_update() */ 667 | absorbStop(&mac_ctx); 668 | 669 | /* spritz_mac_update() */ 670 | absorbBytes(&mac_ctx, msg, msgLen); /* spritz_hash_update() */ 671 | 672 | /* spritz_mac_final() */ 673 | /* Same as spritz_hash_final() */ 674 | absorbStop(&mac_ctx); 675 | absorb(&mac_ctx, digestLen); 676 | /* squeeze() */ 677 | if (mac_ctx.a) { 678 | shuffle(&mac_ctx); 679 | } 680 | for (i = 0; i < digestLen; i++) { 681 | digest[i] = drip(&mac_ctx); 682 | } 683 | 684 | /* `mac_ctx` data will be replaced with 0x00 if SPRITZ_WIPE_TRACES is defined */ 685 | #ifdef SPRITZ_WIPE_TRACES 686 | spritz_state_memzero(&mac_ctx); 687 | #endif 688 | } 689 | -------------------------------------------------------------------------------- /src/SpritzCipher.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: ISC */ 2 | /** 3 | * Copyright (c) 2015-2020 Abderraouf Adjal 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | */ 17 | 18 | 19 | #ifndef SPRITZCIPHER_H 20 | #define SPRITZCIPHER_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | 27 | #include /* uint8_t, uint16_t, uint32_t */ 28 | 29 | 30 | /** SPRITZ_USE_LIBC 31 | * Use C standard library functions such as `memset()` to zero buffers. 32 | * It can be useful for performnce if the lib-C functions are optimized in low-level. 33 | */ 34 | #if 0 35 | # define SPRITZ_USE_LIBC 36 | # include /* For `memset()` */ 37 | # if !defined(__GNUC__) && !defined(__clang__) /* Not GCC or Clang. */ 38 | # warning "SPRITZ_USE_LIBC warning: Code optimization isn't off in some security functions." 39 | # endif /* Not GCC or Clang. */ 40 | #endif 41 | 42 | /** SPRITZ_TIMING_SAFE_CRUSH 43 | * If defined, the equal time crush() will be used. 44 | * This may NOT be useful in some compilers with optimization (except GCC and Clang). 45 | */ 46 | #if 1 47 | # define SPRITZ_TIMING_SAFE_CRUSH 48 | #endif 49 | 50 | /** SPRITZ_WIPE_TRACES 51 | * If defined, sensitive data (like spritz_ctx) when they are 52 | * no longer needed in functions such as hash and mac will be wiped. 53 | * Functions that SPRITZ_WIPE_TRACES is involved with: spritz_hash(), spritz_mac(). 54 | */ 55 | #if 0 56 | # define SPRITZ_WIPE_TRACES 57 | #endif 58 | 59 | /** SPRITZ_WIPE_TRACES_PARANOID 60 | * If defined, the library functions internal variables will be wiped if it contains 61 | * a bit or more of spritz state such as temporary variables in a swap function 62 | * or an user data be wiped when they are no longer needed. 63 | * Variables that contain data length will not be wiped. 64 | * 65 | * If defined, Then SPRITZ_WIPE_TRACES and SPRITZ_TIMING_SAFE_CRUSH 66 | * will be defined automatically. 67 | */ 68 | #if 0 69 | # define SPRITZ_WIPE_TRACES_PARANOID 70 | #endif 71 | 72 | #ifdef SPRITZ_WIPE_TRACES_PARANOID 73 | # ifndef SPRITZ_TIMING_SAFE_CRUSH 74 | # define SPRITZ_TIMING_SAFE_CRUSH 75 | # endif 76 | # ifndef SPRITZ_WIPE_TRACES 77 | # define SPRITZ_WIPE_TRACES 78 | # endif 79 | #endif 80 | 81 | /** SPRITZ_N 82 | * Present the value of N in this spritz implementation, 83 | * DO NOT change SPRITZ_N value. 84 | */ 85 | #define SPRITZ_N 256U 86 | 87 | /* `Semantic Versioning` of this library */ 88 | #define SPRITZ_LIBRARY_VERSION_STRING "1.2.0" 89 | #define SPRITZ_LIBRARY_VERSION_MAJOR 1 90 | #define SPRITZ_LIBRARY_VERSION_MINOR 2 91 | #define SPRITZ_LIBRARY_VERSION_PATCH 0 92 | 93 | 94 | /** spritz_ctx 95 | * The context (contains the state), Holds indices and s-box. 96 | */ 97 | typedef struct 98 | { 99 | uint8_t s[SPRITZ_N]; 100 | uint8_t i, j, k, z, a, w; 101 | #ifdef SPRITZ_WIPE_TRACES_PARANOID 102 | /* `tmp1` for: spritz_state_s_swap(), safe timing crush(). 103 | * `tmp2` for: The safe timing crush(). 104 | */ 105 | uint8_t tmp1, tmp2; 106 | #endif 107 | } spritz_ctx; 108 | 109 | /** spritz_compare() 110 | * Timing-safe equality comparison for `data_a` and `data_b`. 111 | * This function can be used to compare the password's hash safely. 112 | * 113 | * Parameter data_a: Data a to be compare with b. 114 | * Parameter data_b: Data b to be compare with a. 115 | * Parameter len: Length of the array in bytes. 116 | * 117 | * Return: Equality result. 118 | * Zero (0x00) if `data_a` equals `data_b` OR if `len` is zero, 119 | * Non-zero value if they are NOT equal. 120 | */ 121 | uint8_t 122 | spritz_compare(const uint8_t *data_a, const uint8_t *data_b, uint16_t len); 123 | 124 | /** spritz_memzero() 125 | * Wipe `buf` data by replacing it with zeros (0x00). 126 | * 127 | * Parameter buf: Data to replace it with zeros (0x00). 128 | * Parameter len: Length of array in bytes. 129 | */ 130 | void 131 | spritz_memzero(uint8_t *buf, uint16_t len); 132 | 133 | /** spritz_state_memzero() 134 | * Wipe `spritz_ctx`'s data by replacing its data with zeros (0x00). 135 | * 136 | * Parameter ctx: The context. 137 | */ 138 | void 139 | spritz_state_memzero(spritz_ctx *ctx); 140 | 141 | 142 | /** spritz_setup() 143 | * Setup the spritz state `spritz_ctx` with a key. 144 | * 145 | * Parameter ctx: The context. 146 | * Parameter key: The key. 147 | * Parameter keylen: Length of the key in bytes. 148 | */ 149 | void 150 | spritz_setup(spritz_ctx *ctx, 151 | const uint8_t *key, uint8_t keyLen); 152 | 153 | /** spritz_setup_withiv() 154 | * Setup the spritz state `spritz_ctx` with a key and nonce/salt/iv. 155 | * 156 | * Parameter ctx: The context. 157 | * Parameter key: The key. 158 | * Parameter keylen: Length of the key in bytes. 159 | * Parameter nonce: The nonce (salt). 160 | * Parameter noncelen: Length of the nonce in bytes. 161 | */ 162 | void 163 | spritz_setup_withIV(spritz_ctx *ctx, 164 | const uint8_t *key, uint8_t keyLen, 165 | const uint8_t *nonce, uint8_t nonceLen); 166 | 167 | /** spritz_random8() 168 | * Generates a random byte from the spritz state `spritz_ctx`. 169 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 170 | * 171 | * Parameter ctx: The context. 172 | * 173 | * Return: Byte of keystream. 174 | */ 175 | uint8_t 176 | spritz_random8(spritz_ctx *ctx); 177 | 178 | /** spritz_random32() 179 | * Generates a random 32-bit (4 bytes) from the spritz state `spritz_ctx`. 180 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 181 | * 182 | * Parameter ctx: The context. 183 | * 184 | * Return: 32-bit (4 bytes) of keystream. 185 | */ 186 | uint32_t 187 | spritz_random32(spritz_ctx *ctx); 188 | 189 | /** spritz_random32_uniform() 190 | * Calculate an uniformly distributed random number less than `upper_bound` avoiding modulo bias. 191 | * 192 | * Uniformity is achieved by generating new random numbers until the one 193 | * returned is outside the range [0, 2**32 % upper_bound). 194 | * This guarantees the selected random number will be inside 195 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) 196 | * after reduction modulo upper_bound. 197 | * spritz_random32_uniform() derives from OpenBSD's arc4random_uniform() 198 | * 199 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 200 | * 201 | * Parameter ctx: The context. 202 | * Parameter upper_bound: The roof, `upper_bound - 1` is the largest number that can be returned. 203 | * 204 | * Return: Random number less than upper_bound, 0 if upper_bound<2. 205 | */ 206 | uint32_t 207 | spritz_random32_uniform(spritz_ctx *ctx, uint32_t upper_bound); 208 | 209 | /** spritz_add_entropy() 210 | * Add entropy to the spritz state `spritz_ctx` using absorb(). 211 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 212 | * 213 | * Parameter ctx: The context. 214 | * Parameter entropy: The entropy array. 215 | * Parameter len: Length of the entropy array in bytes. 216 | */ 217 | void 218 | spritz_add_entropy(spritz_ctx *ctx, 219 | const uint8_t *entropy, uint16_t len); 220 | 221 | /** spritz_crypt() 222 | * Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream. 223 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 224 | * 225 | * Parameter ctx: The context. 226 | * Parameter data: The data to encrypt or decrypt. 227 | * Parameter datalen: Length of the data in bytes. 228 | * Parameter dataout: The output. 229 | */ 230 | void 231 | spritz_crypt(spritz_ctx *ctx, 232 | const uint8_t *data, uint16_t dataLen, 233 | uint8_t *dataOut); 234 | 235 | /** spritz_crypt_inplace() 236 | * Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream 237 | * and put the output in the same buffer `data`. 238 | * Usable only after calling spritz_setup() or spritz_setup_withiv(). 239 | * 240 | * Parameter ctx: The context. 241 | * Parameter data: The data to encrypt or decrypt, also the output. 242 | * Parameter datalen: Length of the data in bytes. 243 | */ 244 | void 245 | spritz_crypt_inplace(spritz_ctx *ctx, 246 | uint8_t *data, uint16_t dataLen); 247 | 248 | 249 | /** spritz_hash_setup() 250 | * Setup the spritz hash state `spritz_ctx`. 251 | * 252 | * Parameter hash_ctx: The hash context (ctx). 253 | */ 254 | void 255 | spritz_hash_setup(spritz_ctx *hash_ctx); 256 | 257 | /** spritz_hash_update() 258 | * Add a message/data chunk `data` to hash. 259 | * 260 | * Parameter hash_ctx: The hash context (ctx). 261 | * Parameter data: The data chunk to hash. 262 | * Parameter datalen: Length of the data in bytes. 263 | */ 264 | void 265 | spritz_hash_update(spritz_ctx *hash_ctx, 266 | const uint8_t *data, uint16_t dataLen); 267 | 268 | /** spritz_hash_final() 269 | * Output the hash digest. 270 | * 271 | * Parameter hash_ctx: The hash context (ctx). 272 | * Parameter digest: The digest (hash) output. 273 | * Parameter digestlen: Length of the digest in bytes. 274 | */ 275 | void 276 | spritz_hash_final(spritz_ctx *hash_ctx, 277 | uint8_t *digest, uint8_t digestLen); 278 | 279 | /** spritz_hash() 280 | * Cryptographic hash function. 281 | * 282 | * Parameter digest: The digest (hash) output. 283 | * Parameter digestlen: Length of the digest in bytes. 284 | * Parameter data: The data to hash. 285 | * Parameter datalen: Length of the data in bytes. 286 | */ 287 | void 288 | spritz_hash(uint8_t *digest, uint8_t digestLen, 289 | const uint8_t *data, uint16_t dataLen); 290 | 291 | 292 | /** spritz_mac_setup() 293 | * Setup the spritz message authentication code (MAC) state `spritz_ctx`. 294 | * 295 | * Parameter mac_ctx: The message authentication code (MAC) context (ctx). 296 | * Parameter key: The secret key. 297 | * Parameter keylen: Length of the key in bytes. 298 | */ 299 | void 300 | spritz_mac_setup(spritz_ctx *mac_ctx, 301 | const uint8_t *key, uint16_t keyLen); 302 | 303 | /** spritz_mac_update() 304 | * Add a message/data chunk to message authentication code (MAC). 305 | * 306 | * Parameter hash_ctx: The hash context (ctx). 307 | * Parameter msg: The message chunk to be authenticated. 308 | * Parameter msglen: Length of the message in bytes. 309 | */ 310 | void 311 | spritz_mac_update(spritz_ctx *mac_ctx, 312 | const uint8_t *msg, uint16_t msgLen); 313 | 314 | /** spritz_mac_final() 315 | * Output the message authentication code (MAC) digest. 316 | * 317 | * Parameter mac_ctx: The message authentication code (MAC) context (ctx). 318 | * Parameter digest: Message authentication code (MAC) digest output. 319 | * Parameter digestlen: Length of the digest in bytes. 320 | */ 321 | void 322 | spritz_mac_final(spritz_ctx *mac_ctx, 323 | uint8_t *digest, uint8_t digestLen); 324 | 325 | /** spritz_mac() 326 | * Message Authentication Code (MAC) function. 327 | * 328 | * Parameter digest: Message authentication code (MAC) digest output. 329 | * Parameter digestlen: Length of the digest in bytes. 330 | * Parameter msg: The message to be authenticated. 331 | * Parameter msglen: Length of the message in bytes. 332 | * Parameter key: The secret key. 333 | * Parameter keylen: Length of the key in bytes. 334 | */ 335 | void 336 | spritz_mac(uint8_t *digest, uint8_t digestLen, 337 | const uint8_t *msg, uint16_t msgLen, 338 | const uint8_t *key, uint16_t keyLen); 339 | 340 | 341 | #ifdef __cplusplus 342 | } 343 | #endif 344 | 345 | #endif /* SpritzCipher.h */ 346 | --------------------------------------------------------------------------------