3 * Implementation of NSA Simon Block Cipher
4 * Copyright 2017 Michael Calvin McCoy
5 * calvin.mccoy@gmail.com
6 * # The MIT License (MIT) - see LICENSE.md
16 // Cipher Operation Macros
17 #define shift_one(x_word) (((x_word) << 1) | ((x_word) >> (word_size - 1)))
18 #define shift_eight(x_word) (((x_word) << 8) | ((x_word) >> (word_size - 8)))
19 #define shift_two(x_word) (((x_word) << 2) | ((x_word) >> (word_size - 2)))
21 #define rshift_three(x) (((x) >> 3) | (((x) & 0x7) << (word_size - 3)))
22 #define rshift_one(x) (((x) >> 1) | (((x) & 0x1) << (word_size - 1)))
24 uint64_t z_arrays[5] = {0b0001100111000011010100100010111110110011100001101010010001011111,
25 0b0001011010000110010011111011100010101101000011001001111101110001,
26 0b0011001101101001111110001000010100011001001011000000111011110101,
27 0b0011110000101100111001010001001000000111101001100011010111011011,
28 0b0011110111001001010011000011101000000100011011010110011110001011};
30 // Valid Cipher Parameters
31 const uint8_t simon_rounds[] = {32, 36, 36, 42, 44, 52, 54, 68, 69, 72};
32 const uint8_t z_assign[] = {0, 0, 1, 2, 3, 2, 3, 2, 3, 4};
34 uint8_t Simon_Init(SimSpk_Cipher *cipher_object, enum cipher_config_t cipher_cfg, enum mode_t c_mode, void *key, uint8_t *iv, uint8_t *counter) {
36 if (cipher_cfg > cfg_256_128 || cipher_cfg < cfg_64_32){
40 cipher_object->block_size = block_sizes[cipher_cfg];
41 cipher_object->key_size = key_sizes[cipher_cfg];
42 cipher_object->round_limit = simon_rounds[cipher_cfg];
43 cipher_object->cipher_cfg = cipher_cfg;
44 cipher_object->z_seq = z_assign[cipher_cfg];
45 uint8_t word_size = block_sizes[cipher_cfg] >> 1;
46 uint8_t word_bytes = word_size >> 3;
47 uint16_t key_words = key_sizes[cipher_cfg] / word_size;
48 uint64_t sub_keys[4] = {};
49 uint64_t mod_mask = ULLONG_MAX >> (64 - word_size);
52 for(int i = 0; i < key_words; i++) {
53 memcpy(&sub_keys[i], key + (word_bytes * i), word_bytes);
57 uint64_t c = 0xFFFFFFFFFFFFFFFC;
59 // Store First Key Schedule Entry
60 memcpy(cipher_object->key_schedule, &sub_keys[0], word_bytes);
62 for (int i = 0; i < simon_rounds[cipher_cfg] - 1; i++) {
63 tmp1 = rshift_three(sub_keys[key_words - 1]);
69 tmp2 = rshift_one(tmp1);
73 tmp2 = c ^ ((z_arrays[cipher_object->z_seq] >> (i % 62)) & 1);
78 for (int j = 0; j < (key_words - 1); j++) {
79 sub_keys[j] = sub_keys[j + 1];
81 sub_keys[key_words - 1] = tmp1 & mod_mask;
83 // Append sub key to key schedule
84 memcpy(cipher_object->key_schedule + (word_bytes * (i + 1)), &sub_keys[0], word_bytes);
88 if (cipher_cfg == cfg_64_32){
89 cipher_object->encryptPtr = &Simon_Encrypt_32;
90 cipher_object->decryptPtr = &Simon_Decrypt_32;
92 else if(cipher_cfg <= cfg_96_48){
93 cipher_object->encryptPtr = Simon_Encrypt_48;
94 cipher_object->decryptPtr = Simon_Decrypt_48;
96 else if(cipher_cfg <= cfg_128_64) {
97 cipher_object->encryptPtr = Simon_Encrypt_64;
98 cipher_object->decryptPtr = Simon_Decrypt_64;
102 else if(cipher_cfg <= cfg_144_96) {
103 cipher_object->encryptPtr = Simon_Encrypt_96;
104 cipher_object->decryptPtr = Simon_Decrypt_96;
107 else if(cipher_cfg <= cfg_256_128) {
108 cipher_object->encryptPtr = Simon_Encrypt_128;
109 cipher_object->decryptPtr = Simon_Decrypt_128;
118 uint8_t Simon_Encrypt(SimSpk_Cipher cipher_object, const void *plaintext, void *ciphertext) {
119 (*cipher_object.encryptPtr)(cipher_object.round_limit, cipher_object.key_schedule, plaintext, ciphertext);
123 void Simon_Encrypt_32(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext, uint8_t *ciphertext) {
125 const uint8_t word_size = 16;
126 uint16_t *y_word = (uint16_t *)ciphertext;
127 uint16_t *x_word = (((uint16_t *)ciphertext) + 1);
129 *y_word = *(uint16_t *)plaintext;
130 *x_word = *(((uint16_t *)plaintext) + 1);
132 uint16_t *round_key_ptr = (uint16_t *)key_schedule;
134 for(uint8_t i = 0; i < round_limit; i++) {
136 // Shift, AND , XOR ops
137 uint16_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
142 // XOR with Round Key
143 *x_word = temp ^ *(round_key_ptr + i);
147 void Simon_Encrypt_48(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
148 uint8_t *ciphertext) {
150 const uint8_t word_size = 24;
152 bword_24 intrd = *(bword_24 *)plaintext;
153 uint32_t y_word = intrd.data;
154 intrd = *((bword_24 *)(plaintext+3));
155 uint32_t x_word = intrd.data;
157 for(uint8_t i = 0; i < round_limit; i++) {
159 // Shift, AND , XOR ops
160 uint32_t temp = (shift_one(x_word) & shift_eight(x_word)) ^ y_word ^ shift_two(x_word);
165 // XOR with Round Key
166 x_word = (temp ^ (*((bword_24 *)(key_schedule + (i*3)))).data) & 0xFFFFFF;
168 // Assemble Ciphertext Output Array
170 bword_24 * intrd_ptr = (bword_24 *)ciphertext;
174 intrd_ptr = (bword_24 *)(ciphertext + 3);
178 void Simon_Encrypt_64(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
179 uint8_t *ciphertext) {
181 const uint8_t word_size = 32;
182 uint32_t *y_word = (uint32_t *)ciphertext;
183 uint32_t *x_word = (((uint32_t *)ciphertext) + 1);
184 *y_word = *(uint32_t *)plaintext;
185 *x_word = *(((uint32_t *)plaintext) + 1);
186 uint32_t *round_key_ptr = (uint32_t *)key_schedule;
188 for(uint8_t i = 0; i < round_limit; i++) {
190 // Shift, AND , XOR ops
191 uint32_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
196 // XOR with Round Key
197 *x_word = temp ^ *(round_key_ptr + i);
201 void Simon_Encrypt_96(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
202 uint8_t *ciphertext) {
204 const uint8_t word_size = 48;
206 bword_48 intrd = *(bword_48 *)plaintext;
207 uint64_t y_word = intrd.data;
208 intrd = *((bword_48 *)(plaintext+6));
209 uint64_t x_word = intrd.data;
211 for(uint8_t i = 0; i < round_limit; i++) {
213 // Shift, AND , XOR ops
214 uint64_t temp = (shift_one(x_word) & shift_eight(x_word)) ^ y_word ^ shift_two(x_word);
219 // XOR with Round Key
220 x_word = (temp ^ (*((bword_48 *)(key_schedule + (i*6)))).data) & 0xFFFFFFFFFFFF;
222 // Assemble Ciphertext Output Array
224 bword_48 * intrd_ptr = (bword_48 *)ciphertext;
228 intrd_ptr = (bword_48 *)(ciphertext + 6);
233 void Simon_Encrypt_128(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
234 uint8_t *ciphertext) {
236 const uint8_t word_size = 64;
237 uint64_t *y_word = (uint64_t *)ciphertext;
238 uint64_t *x_word = (((uint64_t *)ciphertext) + 1);
239 *y_word = *(uint64_t *)plaintext;
240 *x_word = *(((uint64_t *)plaintext) + 1);
241 uint64_t *round_key_ptr = (uint64_t *)key_schedule;
244 for(uint8_t i = 0; i < round_limit; i++) {
246 // Shift, AND , XOR ops
247 uint64_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
252 // XOR with Round Key
253 *x_word = temp ^ *(round_key_ptr + i);
257 uint8_t Simon_Decrypt(SimSpk_Cipher cipher_object, const void *ciphertext, void *plaintext) {
258 (*cipher_object.decryptPtr)(cipher_object.round_limit, cipher_object.key_schedule, ciphertext, plaintext);
262 void Simon_Decrypt_32(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
263 uint8_t *plaintext) {
265 const uint8_t word_size = 16;
266 uint16_t *x_word = (uint16_t *)plaintext;
267 uint16_t *y_word = ((uint16_t *)plaintext) + 1;
268 uint16_t *round_key_ptr = (uint16_t *)key_schedule;
270 *x_word = *(uint16_t *)ciphertext;
271 *y_word = *(((uint16_t *)ciphertext) + 1);
273 for(int8_t i = round_limit - 1; i >= 0; i--) {
275 // Shift, AND , XOR ops
276 uint16_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
281 // XOR with Round Key
282 *x_word = temp ^ *(round_key_ptr + i);
286 void Simon_Decrypt_48(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
288 const uint8_t word_size = 24;
290 bword_24 intrd = *(bword_24 *)ciphertext;
291 uint32_t x_word = intrd.data;
292 intrd = *((bword_24 *)(ciphertext+3));
293 uint32_t y_word = intrd.data;
295 for(int8_t i = round_limit - 1 ; i >= 0; i--) {
297 // Shift, AND , XOR ops
298 uint32_t temp = (shift_one(x_word) & shift_eight(x_word)) ^ y_word ^ shift_two(x_word);
303 // XOR with Round Key
304 x_word = (temp ^ (*((bword_24 *)(key_schedule + (i*3)))).data) & 0xFFFFFF;
306 // Assemble plaintext Output Array
308 bword_24 * intrd_ptr = (bword_24 *)plaintext;
312 intrd_ptr = (bword_24 *)(plaintext + 3);
316 void Simon_Decrypt_64(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
319 const uint8_t word_size = 32;
320 uint32_t *x_word = (uint32_t *)plaintext;
321 uint32_t *y_word = ((uint32_t *)plaintext) + 1;
322 uint32_t *round_key_ptr = (uint32_t *)key_schedule;
324 *x_word = *(uint32_t *)ciphertext;
325 *y_word = *(((uint32_t *)ciphertext) + 1);
327 for(int8_t i = round_limit -1 ; i >= 0; i--) {
329 // Shift, AND , XOR ops
330 uint32_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
335 // XOR with Round Key
336 *x_word = temp ^ *(round_key_ptr + i);
340 void Simon_Decrypt_96(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
342 const uint8_t word_size = 48;
343 bword_48 intrd = *(bword_48 *)ciphertext;
344 uint64_t x_word = intrd.data;
345 intrd = *((bword_48 *)(ciphertext+6));
346 uint64_t y_word = intrd.data;
348 for(int8_t i = round_limit - 1; i >= 0; i--) {
350 // Shift, AND , XOR ops
351 uint64_t temp = (shift_one(x_word) & shift_eight(x_word)) ^ y_word ^ shift_two(x_word);
356 // XOR with Round Key
357 x_word = (temp ^ (*((bword_48 *)(key_schedule + (i*6)))).data) & 0xFFFFFFFFFFFF;
359 // Assemble Plaintext Output Array
361 bword_48 * intrd_ptr = (bword_48 *)plaintext;
365 intrd_ptr = (bword_48 *)(plaintext + 6);
369 void Simon_Decrypt_128(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
372 const uint8_t word_size = 64;
373 uint64_t *x_word = (uint64_t *)plaintext;
374 uint64_t *y_word = ((uint64_t *)plaintext) + 1;
375 uint64_t *round_key_ptr = (uint64_t *)key_schedule;
377 *x_word = *(uint64_t *)ciphertext;
378 *y_word = *(((uint64_t *)ciphertext) + 1);
380 for(int8_t i = round_limit - 1; i >=0; i--) {
382 // Shift, AND , XOR ops
383 uint64_t temp = (shift_one(*x_word) & shift_eight(*x_word)) ^ *y_word ^ shift_two(*x_word);
388 // XOR with Round Key
389 *x_word = temp ^ *(round_key_ptr + i);