/* =============================================================================== Reference implementation of Pyjamask block ciphers in C Copyright (C) 2019 Dahmun Goudarzi, Jérémy Jean, Stefan Kölbl, Thomas Peyrin, Matthieu Rivain, Yu Sasaki, Siang Meng Sim This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . =============================================================================== */ #include //============================================================================== //=== Parameters //============================================================================== #define STATE_SIZE_96 3 #define STATE_SIZE_128 4 #define NB_ROUNDS_96 14 #define NB_ROUNDS_128 14 #define NB_ROUNDS_KS 14 //============================================================================== //=== Macros //============================================================================== #define right_rotate(row) \ row = (row >> 1) | (row << 31); #define left_rotate(row,n) \ row = (row >> n) | (row << (32-n)); //============================================================================== //=== Constants //============================================================================== #define COL_M0 0xa3861085 #define COL_M1 0x63417021 #define COL_M2 0x692cf280 #define COL_M3 0x48a54813 #define COL_MK 0xb881b9ca #define COL_INV_M0 0x2037a121 #define COL_INV_M1 0x108ff2a0 #define COL_INV_M2 0x9054d8c0 #define COL_INV_M3 0x3354b117 #define KS_CONSTANT_0 0x00000080 #define KS_CONSTANT_1 0x00006a00 #define KS_CONSTANT_2 0x003f0000 #define KS_CONSTANT_3 0x24000000 #define KS_ROT_GAP1 8 #define KS_ROT_GAP2 15 #define KS_ROT_GAP3 18 //============================================================================== //=== Common functions //============================================================================== void load_state(const uint8_t *plaintext, uint32_t *state, int state_size) { int i; for (i=0; i> 24); ciphertext [4*i+1] = (uint8_t) (state[i] >> 16); ciphertext [4*i+2] = (uint8_t) (state[i] >> 8); ciphertext [4*i+3] = (uint8_t) (state[i] >> 0); } } uint32_t mat_mult(uint32_t mat_col, uint32_t vec) { int i; uint32_t mask, res=0; for (i = 31; i>=0; i--) { mask = -((vec >> i) & 1); res ^= mask & mat_col; right_rotate(mat_col); } return res; } //============================================================================== //=== Key schedule //============================================================================== void ks_mix_comlumns(const uint32_t *ks_prev, uint32_t *ks_next) { uint32_t tmp; tmp = ks_prev[0] ^ ks_prev[1] ^ ks_prev[2] ^ ks_prev[3]; ks_next[0] = ks_prev[0] ^ tmp; ks_next[1] = ks_prev[1] ^ tmp; ks_next[2] = ks_prev[2] ^ tmp; ks_next[3] = ks_prev[3] ^ tmp; } void ks_mix_rotate_rows(uint32_t *ks_state) { ks_state[0] = mat_mult(COL_MK, ks_state[0]); left_rotate(ks_state[1],KS_ROT_GAP1) left_rotate(ks_state[2],KS_ROT_GAP2) left_rotate(ks_state[3],KS_ROT_GAP3) } void ks_add_constant(uint32_t *ks_state, const uint32_t ctr) { ks_state[0] ^= KS_CONSTANT_0 ^ ctr; ks_state[1] ^= KS_CONSTANT_1; ks_state[2] ^= KS_CONSTANT_2; ks_state[3] ^= KS_CONSTANT_3; } void key_schedule(const uint8_t *key, uint32_t* round_keys) { int r; uint32_t *ks_state = round_keys; load_state(key, ks_state, 4); for (r=0; r state[1] state[0] ^= state[1]; state[1] ^= state[0]; state[0] ^= state[1]; } void add_round_key_96(uint32_t *state, const uint32_t *round_key, int r) { state[0] ^= round_key[4*r+0]; state[1] ^= round_key[4*r+1]; state[2] ^= round_key[4*r+2]; } void pyjamask_96_enc(const uint8_t *plaintext, const uint8_t *key, uint8_t *ciphertext) { int r; uint32_t state[STATE_SIZE_96]; uint32_t round_keys[4*(NB_ROUNDS_KS+1)]; key_schedule(key, round_keys); load_state(plaintext, state, STATE_SIZE_96); for (r=0; r state[1] state[0] ^= state[1]; state[1] ^= state[0]; state[0] ^= state[1]; state[2] = ~state[2]; state[0] ^= state[1]; state[2] ^= state[0]; state[1] ^= state[2] & state[0]; state[0] ^= state[1] & state[2]; state[2] ^= state[0] & state[1]; state[1] ^= state[2]; state[0] ^= state[1]; } void pyjamask_96_dec(const uint8_t *ciphertext, const uint8_t *key, uint8_t *plaintext) { int r; uint32_t state[STATE_SIZE_96]; uint32_t round_keys[4*(NB_ROUNDS_KS+1)]; key_schedule(key, round_keys); load_state(ciphertext, state, STATE_SIZE_96); add_round_key_96(state, round_keys, NB_ROUNDS_96); for (r=NB_ROUNDS_96-1; r>=0; r--) { inv_mix_rows_96(state); inv_sub_bytes_96(state); add_round_key_96(state, round_keys, r); } unload_state(plaintext, state, STATE_SIZE_96); } //============================================================================== //=== Pyjamask-128 (encryption) //============================================================================== void mix_rows_128(uint32_t *state) { state[0] = mat_mult(COL_M0, state[0]); state[1] = mat_mult(COL_M1, state[1]); state[2] = mat_mult(COL_M2, state[2]); state[3] = mat_mult(COL_M3, state[3]); } void sub_bytes_128(uint32_t *state) { state[0] ^= state[3]; state[3] ^= state[0] & state[1]; state[0] ^= state[1] & state[2]; state[1] ^= state[2] & state[3]; state[2] ^= state[0] & state[3]; state[2] ^= state[1]; state[1] ^= state[0]; state[3] = ~state[3]; // swap state[2] <-> state[3] state[2] ^= state[3]; state[3] ^= state[2]; state[2] ^= state[3]; } void add_round_key_128(uint32_t *state, const uint32_t *round_key, int r) { state[0] ^= round_key[4*r+0]; state[1] ^= round_key[4*r+1]; state[2] ^= round_key[4*r+2]; state[3] ^= round_key[4*r+3]; } void pyjamask_128_enc(const uint8_t *plaintext, const uint8_t *key, uint8_t *ciphertext) { int r; uint32_t state[STATE_SIZE_128]; uint32_t round_keys[4*(NB_ROUNDS_KS+1)]; key_schedule(key, round_keys); load_state(plaintext, state, STATE_SIZE_128); for (r=0; r state[3] state[2] ^= state[3]; state[3] ^= state[2]; state[2] ^= state[3]; state[3] = ~state[3]; state[1] ^= state[0]; state[2] ^= state[1]; state[2] ^= state[3] & state[0]; state[1] ^= state[2] & state[3]; state[0] ^= state[1] & state[2]; state[3] ^= state[0] & state[1]; state[0] ^= state[3]; } void pyjamask_128_dec(const uint8_t *ciphertext, const uint8_t *key, uint8_t *plaintext) { int r; uint32_t state[STATE_SIZE_128]; uint32_t round_keys[4*(NB_ROUNDS_KS+1)]; key_schedule(key, round_keys); load_state(ciphertext, state, STATE_SIZE_128); add_round_key_128(state, round_keys, NB_ROUNDS_128); for (r=NB_ROUNDS_128-1; r>=0; r--) { inv_mix_rows_128(state); inv_sub_bytes_128(state); add_round_key_128(state, round_keys, r); } unload_state(plaintext, state, STATE_SIZE_128); }