Reputation: 941
I'm trying to extend the following implementation of the Speck cipher (https://github.com/inmcm/Simon_Speck_Ciphers) by adding the decryption module. I implemented the decryption algorithm by following the instructions from the original paper from NSA about Speck and Simon (https://eprint.iacr.org/2013/404).
At the moment I'm kinda stuck because I can't decipher correctly the cipher text generated from the encryption routine. I already had a look at other similar questions posted here on SO to no avail.
By checking my code and the stdout, I've noticed that the value stored in x_word in the decryption phase is not correct, starting with the first iteration. Therefore, there is probably an issue with the following instruction:
x_word = rotate_left( (sub_mod((x_word ^ *(round_key_ptr + 21 - i)), y_word, 65535)), 7);
I'm posting the relevant part of my code here:
#define rotate_left(x,n) (x >> (word_size - n)) | (x << n)
#define rotate_right(x,n) (x << (word_size - n)) | (x >> n)
void Speck_Encrypt_32(uint8_t *key_schedule, uint8_t *plaintext, uint8_t *ciphertext) {
const uint8_t word_size = 16;
uint16_t y_word = *(uint16_t *)plaintext;
uint16_t x_word = *(((uint16_t *)plaintext) + 1);
uint16_t *round_key_ptr = (uint16_t *)key_schedule;
uint16_t * word_ptr = (uint16_t *)ciphertext;
for(uint8_t i = 0; i < 22; i++) { // Block size 32 has only one round number option
x_word = ((rotate_right(x_word, 7)) + y_word) ^ *(round_key_ptr + i);
y_word = (rotate_left(y_word, 2)) ^ x_word;
printf("y_word - (%d) - %u\n", i, (unsigned int)y_word);
printf("x_word - (%d) - %u\n", i, (unsigned int)x_word);
}
// Assemble Ciphertext Output Array
*word_ptr = y_word;
word_ptr += 1;
*word_ptr = x_word;
return;
}
static inline uint16_t sub_mod(uint16_t a, uint16_t b, uint16_t m)
{
if ( a>=b )
return a - b;
else
return m - b + a;
}
void Speck_Decrypt_32(uint8_t *key_schedule, uint8_t *plaintext, uint8_t *ciphertext) {
const uint8_t word_size = 16;
// Swapping cipher text words
uint16_t y_word = *(uint16_t *)ciphertext;
uint16_t x_word = *(((uint16_t *)ciphertext) + 1);
uint16_t *round_key_ptr = (uint16_t *)key_schedule;
uint16_t * word_ptr = (uint16_t *)plaintext;
for(int i=0; i < 4; i++) {
printf("Ciphertext Byte %02d: %02x \n",i,ciphertext[i]);
printf("Plaintext Byte %02d: %02x \n",i,plaintext[i]);
}
// Reading round keys in reverse order
for(uint8_t i = 0; i < 22; i++) { // Block size 32 has only one round number option
//printf("y_word - (%d) - %u\n", i, (unsigned int)y_word);
//printf("x_word - (%d) - %u\n", i, (unsigned int)x_word);
// Inverting rotations and using custom modular subtraction
y_word = rotate_right((x_word ^ y_word), 2);
x_word = rotate_left( (sub_mod((x_word ^ *(round_key_ptr + 21 - i)), y_word, 65535)), 7);
}
// Assemble Plaintext - Swapping plaintext words
*word_ptr = y_word;
word_ptr += 1;
*word_ptr = x_word;
return;
}
I haven't been coding in C in awhile, there might be a few mistakes.
Upvotes: 0
Views: 1019
Reputation: 941
Good old pen and paper checks helped me to find two mistakes:
a mod n-1
instead of a mod n
(I was passing as divisor the wrong value).After fixing the aforementioned bugs, I'm now able to correctly encrypt/decrypt with different block/bey sizes.
Thanks everyone for the help anyway.
Upvotes: 0
Reputation: 21
Just do the encryption in reverse. So if your expanded key is k_0,...,k_{21} then you would do the following in C.
#define ROTR(x,r) (((x > > r) | (x < < (16-r))) & 0xffff)
#define ROTL(x,r) (((x< < r) | (x > > (16-r))) & 0xffff)
#define invR(x,y,k) (y=y^x, y=ROTR(y,2), x=x^k, x=(x-y) & 0xffff, x=ROTL(x,7))
Then you do something like:
for(i=21;i>=0;i--) invR(x,y,k[i])
FYI: SIMON and SPECK are among the most highly analyzed block ciphers in recent years. There are more than 70 "peer reviewed" papers which analyze them (as you may check by doing a search on Google Scholar) and they have a security margin similar to AES-128. On an x86 processor, SPECK128/256 has speed nearly identical to ChaCha20 (a very fast stream cipher). A fast software implementation of SPECK128/256 on an x86 processor is about 50% slower than AES-256 using AES-NI (i.e., the hardware instruction). See https://github.com/iadgov/simon-speck-supercop for fast implementations of SIMON and SPECK compatible with the SUPERCOP benchmarking system.
Upvotes: 1
Reputation: 2647
Given that the repo's author didn't get around the writing the C decryption routine, I'd have some concerns as to the validity of the C setup or encryption routine first.
Rather than starting there, why not look over one of the working C implementations:
https://github.com/tomasaazevedo/Speck_8-bit_C
https://github.com/yuehann/Simon_Speck
https://github.com/mysummergit/myssl/blob/master/demos/mycipher/speck.c
Upvotes: 1