3 * Implementation of NSA Speck Block Cipher
4 * Copyright 2017 Michael Calvin McCoy
5 * calvin.mccoy@gmail.com
6 * # The MIT License (MIT) - see LICENSE.md see LICENSE.md
16 #define rotate_left(x,n) (((x) >> (word_size - (n))) | ((x) << (n)))
17 #define rotate_right(x,n) (((x) << (word_size - (n))) | ((x) >> (n)))
19 const uint8_t speck_rounds[] = {22, 22, 23, 26, 27, 28, 29, 32, 33, 34};
21 uint8_t Speck_Init(SimSpk_Cipher *cipher_object, enum cipher_config_t cipher_cfg, enum mode_t c_mode, void *key, uint8_t *iv, uint8_t *counter) {
23 if (cipher_cfg > cfg_256_128 || cipher_cfg < cfg_64_32) {
27 cipher_object->block_size = block_sizes[cipher_cfg];
28 cipher_object->key_size = key_sizes[cipher_cfg];
29 cipher_object->round_limit = speck_rounds[cipher_cfg];
30 cipher_object->cipher_cfg = cipher_cfg;
32 uint8_t word_size = block_sizes[cipher_cfg] >> 1;
33 uint8_t word_bytes = word_size >> 3;
34 uint16_t key_words = key_sizes[cipher_cfg] / word_size;
35 uint64_t sub_keys[4] = {};
36 uint64_t mod_mask = ULLONG_MAX >> (64 - word_size);
38 if (cipher_cfg == cfg_64_32) {
39 cipher_object->alpha = 7;
40 cipher_object->beta = 2;
43 cipher_object->alpha = 8;
44 cipher_object->beta = 3;
48 for(int i = 0; i < key_words; i++) {
49 memcpy(&sub_keys[i], key + (word_bytes * i), word_bytes);
52 // Store First Key Schedule Entry
53 memcpy(cipher_object->key_schedule, &sub_keys[0], word_bytes);
56 for (uint64_t i = 0; i < speck_rounds[cipher_cfg] - 1; i++) {
58 // Run Speck Cipher Round Function
59 tmp = (rotate_right(sub_keys[1],cipher_object->alpha)) & mod_mask;
60 tmp = (tmp + sub_keys[0]) & mod_mask;
62 tmp2 = (rotate_left(sub_keys[0],cipher_object->beta)) & mod_mask;
66 // Shift Key Schedule Subword
69 for(int j = 1; j < (key_words - 1); j++){
70 sub_keys[j] = sub_keys[j+1];
73 sub_keys[key_words - 1] = tmp;
75 // Append sub key to key schedule
76 memcpy(cipher_object->key_schedule + (word_bytes * (i+1)), &sub_keys[0], word_bytes);
79 if (cipher_cfg == cfg_64_32){
80 cipher_object->encryptPtr = &Speck_Encrypt_32;
81 cipher_object->decryptPtr = &Speck_Decrypt_32;
83 else if(cipher_cfg <= cfg_96_48){
84 cipher_object->encryptPtr = Speck_Encrypt_48;
85 cipher_object->decryptPtr = Speck_Decrypt_48;
87 else if(cipher_cfg <= cfg_128_64) {
88 cipher_object->encryptPtr = Speck_Encrypt_64;
89 cipher_object->decryptPtr = Speck_Decrypt_64;
93 else if(cipher_cfg <= cfg_144_96) {
94 cipher_object->encryptPtr = Speck_Encrypt_96;
95 cipher_object->decryptPtr = Speck_Decrypt_96;
98 else if(cipher_cfg <= cfg_256_128) {
99 cipher_object->encryptPtr = Speck_Encrypt_128;
100 cipher_object->decryptPtr = Speck_Decrypt_128;
109 uint8_t Speck_Encrypt(SimSpk_Cipher cipher_object, const void *plaintext, void *ciphertext) {
110 (*cipher_object.encryptPtr)(cipher_object.round_limit, cipher_object.key_schedule, plaintext, ciphertext);
114 void Speck_Encrypt_32(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext, uint8_t *ciphertext) {
116 const uint8_t word_size = 16;
117 uint16_t *y_word = (uint16_t *)ciphertext;
118 uint16_t *x_word = ((uint16_t *)ciphertext) + 1;
119 uint16_t *round_key_ptr = (uint16_t *)key_schedule;
121 *y_word = *(uint16_t *)plaintext;
122 *x_word = *(((uint16_t *)plaintext) + 1);
124 for(uint8_t i = 0; i < round_limit; i++) {
125 *x_word = ((rotate_right(*x_word, 7)) + *y_word) ^ *(round_key_ptr + i);
126 *y_word = (rotate_left(*y_word, 2)) ^ *x_word;
131 void Speck_Encrypt_48(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
132 uint8_t *ciphertext){
134 const uint8_t word_size = 24;
136 bytes3_t *threeBytePtr = (bytes3_t *)plaintext;
137 uint32_t y_word = (*(bitword24_t *)threeBytePtr).data;
138 uint32_t x_word = (*(bitword24_t *)(threeBytePtr + 1)).data;
139 threeBytePtr = (bytes3_t *)key_schedule;
142 for(uint8_t i = 0; i < round_limit; i++) {
143 round_key = (*(bitword24_t *)(threeBytePtr + i)).data;
144 x_word = (((rotate_right(x_word, 8)) + y_word) ^ round_key) & 0x00FFFFFF;
145 y_word = ((rotate_left(y_word, 3)) ^ x_word) & 0x00FFFFFF;
147 // Assemble Ciphertext Output Array
148 threeBytePtr = (bytes3_t *)ciphertext;
149 *threeBytePtr = *(bytes3_t *)&y_word;
151 *threeBytePtr = *(bytes3_t *)&x_word;
154 void Speck_Encrypt_64(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
155 uint8_t *ciphertext) {
157 const uint8_t word_size = 32;
158 uint32_t *y_word = (uint32_t *)ciphertext;
159 uint32_t *x_word = ((uint32_t *)ciphertext) + 1;
160 uint32_t *round_key_ptr = (uint32_t *)key_schedule;
162 *y_word = *(uint32_t *)plaintext;
163 *x_word = *(((uint32_t *)plaintext) + 1);
165 for(uint8_t i = 0; i < round_limit; i++) {
166 *x_word = ((rotate_right(*x_word, 8)) + *y_word) ^ *(round_key_ptr + i);
167 *y_word = (rotate_left(*y_word, 3)) ^ *x_word;
171 void Speck_Encrypt_96(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
172 uint8_t *ciphertext){
173 const uint8_t word_size = 48;
175 bytes6_t *threeBytePtr = (bytes6_t *)plaintext;
176 uint64_t y_word = (*(bitword48_t *)threeBytePtr).data;
177 uint64_t x_word = (*(bitword48_t *)(threeBytePtr + 1)).data;
178 threeBytePtr = (bytes6_t *)key_schedule;
181 for(uint8_t i = 0; i < round_limit; i++) {
182 round_key = (*(bitword48_t *)(threeBytePtr + i)).data;
183 x_word = (((rotate_right(x_word, 8)) + y_word) ^ round_key) & 0x00FFFFFFFFFFFF;
184 y_word = ((rotate_left(y_word, 3)) ^ x_word) & 0x00FFFFFFFFFFFF;
186 // Assemble Ciphertext Output Array
187 threeBytePtr = (bytes6_t *)ciphertext;
188 *threeBytePtr = *(bytes6_t *)&y_word;
190 *threeBytePtr = *(bytes6_t *)&x_word;
193 void Speck_Encrypt_128(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *plaintext,
194 uint8_t *ciphertext){
196 const uint8_t word_size = 64;
197 uint64_t *y_word = (uint64_t *)ciphertext;
198 uint64_t *x_word = ((uint64_t *)ciphertext) + 1;
199 uint64_t *round_key_ptr = (uint64_t *)key_schedule;
201 *y_word = *(uint64_t *)plaintext;
202 *x_word = *(((uint64_t *)plaintext) + 1);
204 for(uint8_t i = 0; i < round_limit; i++) {
205 *x_word = ((rotate_right(*x_word, 8)) + *y_word) ^ *(round_key_ptr + i);
206 *y_word = (rotate_left(*y_word, 3)) ^ *x_word;
210 uint8_t Speck_Decrypt(SimSpk_Cipher cipher_object, const void *ciphertext, void *plaintext) {
211 (*cipher_object.decryptPtr)(cipher_object.round_limit, cipher_object.key_schedule, ciphertext, plaintext);
215 void Speck_Decrypt_32(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext, uint8_t *plaintext) {
217 const uint8_t word_size = 16;
218 uint16_t *y_word = (uint16_t *)plaintext;
219 uint16_t *x_word = ((uint16_t *)plaintext) + 1;
220 uint16_t *round_key_ptr = (uint16_t *)key_schedule;
222 *y_word = *(uint16_t *)ciphertext;
223 *x_word = *(((uint16_t *)ciphertext) + 1);
225 for(int8_t i = round_limit - 1; i >=0; i--) {
226 *y_word = rotate_right((*y_word ^ *x_word), 2);
227 *x_word = rotate_left((uint16_t)((*x_word ^ *(round_key_ptr + i)) - *y_word), 7);
231 void Speck_Decrypt_48(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
232 uint8_t *plaintext) {
234 const uint8_t word_size = 24;
236 bytes3_t *threeBytePtr = (bytes3_t *)ciphertext;
237 uint32_t y_word = (*(bitword24_t *)threeBytePtr).data;
238 uint32_t x_word = (*(bitword24_t *)(threeBytePtr + 1)).data;
239 threeBytePtr = (bytes3_t *)key_schedule;
242 for(int8_t i = round_limit - 1; i >=0; i--) {
243 round_key = (*(bitword24_t *)(threeBytePtr + i)).data;
244 y_word = (rotate_right((y_word ^ x_word), 3)) & 0x00FFFFFF;
245 x_word = (rotate_left(((((x_word ^ round_key)) - y_word) & 0x00FFFFFF), 8)) & 0x00FFFFFF;
248 // Assemble Plaintext Output Array
249 threeBytePtr = (bytes3_t *)plaintext;
250 *threeBytePtr = *(bytes3_t *)&y_word;
252 *threeBytePtr = *(bytes3_t *)&x_word;
255 void Speck_Decrypt_64(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
256 uint8_t *plaintext) {
258 const uint8_t word_size = 32;
259 uint32_t *y_word = (uint32_t *)plaintext;
260 uint32_t *x_word = ((uint32_t *)plaintext) + 1;
261 uint32_t *round_key_ptr = (uint32_t *)key_schedule;
263 *y_word = *(uint32_t *)ciphertext;
264 *x_word = *(((uint32_t *)ciphertext) + 1);
266 for(int8_t i = round_limit - 1; i >=0; i--) {
267 *y_word = rotate_right((*y_word ^ *x_word), 3);
268 *x_word = rotate_left((uint32_t)((*x_word ^ *(round_key_ptr + i)) - *y_word), 8);
272 void Speck_Decrypt_96(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
273 uint8_t *plaintext) {
274 const uint8_t word_size = 48;
276 bytes6_t *sixBytePtr = (bytes6_t *)ciphertext;
277 uint64_t y_word = (*(bitword48_t *)sixBytePtr).data;
278 uint64_t x_word = (*(bitword48_t *)(sixBytePtr + 1)).data;
279 sixBytePtr = (bytes6_t *)key_schedule;
282 for(int8_t i = round_limit - 1; i >=0; i--) {
283 round_key = (*(bitword48_t *)(sixBytePtr + i)).data;
284 y_word = (rotate_right((y_word ^ x_word), 3)) & 0x00FFFFFFFFFFFF;
285 x_word = (rotate_left(((((x_word ^ round_key)) - y_word) & 0x00FFFFFFFFFFFF), 8)) & 0x00FFFFFFFFFFFF;
288 // Assemble Plaintext Output Array
289 sixBytePtr = (bytes6_t *)plaintext;
290 *sixBytePtr = *(bytes6_t *)&y_word;
292 *sixBytePtr = *(bytes6_t *)&x_word;
295 void Speck_Decrypt_128(const uint8_t round_limit, const uint8_t *key_schedule, const uint8_t *ciphertext,
296 uint8_t *plaintext) {
298 const uint8_t word_size = 64;
299 uint64_t *y_word = (uint64_t *)plaintext;
300 uint64_t *x_word = ((uint64_t *)plaintext) + 1;
301 uint64_t *round_key_ptr = (uint64_t *)key_schedule;
303 *y_word = *(uint64_t *)ciphertext;
304 *x_word = *(((uint64_t *)ciphertext) + 1);
306 for(int8_t i = round_limit - 1; i >=0; i--) {
307 *y_word = rotate_right((*y_word ^ *x_word), 3);
308 *x_word = rotate_left((uint64_t)((*x_word ^ *(round_key_ptr + i)) - *y_word), 8);