diff options
Diffstat (limited to 'src/cipher.c')
| -rw-r--r-- | src/cipher.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/cipher.c b/src/cipher.c new file mode 100644 index 0000000..7f1152a --- /dev/null +++ b/src/cipher.c @@ -0,0 +1,170 @@ +#include <stdint.h> +#include <string.h> + +#include "cipher.h" +#include "constants.h" +#include "parameters.h" +#include "tweakey.h" + + +enum permutation +{ + PERMUTATION_ENCRYPTION = 0, + PERMUTATION_DECRYPTION = 1, + PERMUTATION_NONE +}; + +typedef enum permutation permutation; + +const uint8_t PERMUTATIONS[2][BLOCK_BYTES] = { + /* PI(i) */ + [0] = { 13, 9, 14, 8, 10, 11, 12, 15, + 4, 5, 3, 1, 2, 6, 0, 7 }, + /* PI^-1(i) */ + [1] = { 14, 11, 12, 10, 8, 9, 13, 15, + 3, 1, 4, 5, 6, 0, 2, 7 } +}; + + +struct cipher_state +{ + uint8_t X[BLOCK_BYTES]; +}; + + +typedef struct cipher_state cipher_state; + + +static void _state_init(cipher_state *X, const uint8_t message[BLOCK_BYTES]) +{ + memcpy(X->X, message, sizeof(X->X)); +} + + +static void _compute_round_tweakeys( + const uint8_t key[KEY_BYTES], + const uint8_t tweak[TWEAK_BYTES], + uint8_t RTK[ROUNDS][ROUND_TWEAKEY_BYTES] +) +{ + tweakey_state TK; + tweakey_state_init(&TK, key, tweak); + tweakey_state_extract(&TK, RTK[0], 0); + + for (uint8_t i=1; i<ROUNDS; i++) + { + tweakey_state_update(&TK); + tweakey_state_extract(&TK, RTK[i], i); + } +} + + +static void _nonlinear_layer(cipher_state *X, const uint8_t RTK[ROUND_TWEAKEY_BYTES]) +{ + uint8_t F[ROUND_TWEAKEY_BYTES]; + for (size_t j=0; j<sizeof(F); j++) + { + F[j] = X->X[j] ^ RTK[j]; + } + + for (size_t j=0; j<sizeof(F); j++) + { + F[j] = S[F[j]]; + } + + for (size_t j=0; j<8; j++) + { + size_t dest_j = 15-j; + X->X[dest_j] ^= F[j]; + } +} + +static void _linear_layer(cipher_state *X) +{ + X->X[15] ^= X->X[1]; + X->X[15] ^= X->X[2]; + X->X[15] ^= X->X[3]; + X->X[15] ^= X->X[4]; + X->X[15] ^= X->X[5]; + X->X[15] ^= X->X[6]; + X->X[15] ^= X->X[7]; + + X->X[14] ^= X->X[7]; + X->X[13] ^= X->X[7]; + X->X[12] ^= X->X[7]; + X->X[11] ^= X->X[7]; + X->X[10] ^= X->X[7]; + X->X[9] ^= X->X[7]; +} + +static void _permutation_layer(cipher_state *X, permutation p) +{ + if (p == PERMUTATION_NONE) + { + return; + } + + uint8_t X_old[BLOCK_BYTES]; + memcpy(X_old, X, sizeof(X_old)); + + const uint8_t *pi = PERMUTATIONS[p]; + + for (size_t j=0; j<BLOCK_BYTES; j++) + { + X->X[pi[j]] = X_old[j]; + } +} + +static void _one_round_egfn(cipher_state *X, const uint8_t RTK[ROUND_TWEAKEY_BYTES], permutation p) +{ + _nonlinear_layer(X, RTK); + _linear_layer(X); + _permutation_layer(X, p); +} + + +void lilliput_tbc_encrypt( + const uint8_t key[KEY_BYTES], + const uint8_t tweak[TWEAK_BYTES], + const uint8_t message[BLOCK_BYTES], + uint8_t ciphertext[BLOCK_BYTES] +) +{ + cipher_state X; + _state_init(&X, message); + + uint8_t RTK[ROUNDS][ROUND_TWEAKEY_BYTES]; + _compute_round_tweakeys(key, tweak, RTK); + + for (uint8_t i=0; i<ROUNDS-1; i++) + { + _one_round_egfn(&X, RTK[i], PERMUTATION_ENCRYPTION); + } + + _one_round_egfn(&X, RTK[ROUNDS-1], PERMUTATION_NONE); + + memcpy(ciphertext, X.X, BLOCK_BYTES); +} + +void lilliput_tbc_decrypt( + const uint8_t key[KEY_BYTES], + const uint8_t tweak[TWEAK_BYTES], + const uint8_t ciphertext[BLOCK_BYTES], + uint8_t message[BLOCK_BYTES] +) +{ + cipher_state X; + _state_init(&X, ciphertext); + + uint8_t RTK[ROUNDS][ROUND_TWEAKEY_BYTES]; + _compute_round_tweakeys(key, tweak, RTK); + + for (uint8_t i=0; i<ROUNDS-1; i++) + { + _one_round_egfn(&X, RTK[ROUNDS-1-i], PERMUTATION_DECRYPTION); + } + + _one_round_egfn(&X, RTK[0], PERMUTATION_NONE); + + memcpy(message, X.X, BLOCK_BYTES); +} |
