int morus_tag_verification(uint64_t msglen, uint64_t adlen, const uint8_t *c, uint64_t state[][4]) { int i,j; uint8_t t[32]; int check = 0; memcpy(t, state[3], 32); ((uint64_t*)t)[0] ^= (adlen << 3); ((uint64_t*)t)[1] ^= (msglen << 3); state[4][0] ^= state[0][0]; state[4][1] ^= state[0][1]; state[4][2] ^= state[0][2]; state[4][3] ^= state[0][3]; for (i = 0; i < 8; i++) morus_stateupdate((uint64_t*)t, state); for (i = 2; i < 5; i++) { for (j = 0; j < 4; j++) { state[1][j] ^= state[i][j]; }} //in this program, the mac length is assumed to be a multiple of bytes //verification for (i = 0; i < 16; i++) check |= (c[msglen + i] ^ ((uint8_t *)state[1])[i]); if (0 == check) return 0; else return -1; }
void morus_enc_aut_partialblock(const uint8_t* plaintext, uint8_t* ciphertext, uint64_t len, uint64_t state[][4]) { uint8_t plaintextblock[32] __attribute__((aligned(256))); uint8_t ciphertextblock[32] __attribute__((aligned(256))); memset(plaintextblock, 0, 32); memcpy(plaintextblock, plaintext, len); ((uint64_t*)ciphertextblock)[0] = ((uint64_t*)plaintextblock)[0] ^ state[0][0] ^ state[1][1] ^ (state[2][0] & state[3][0]); ((uint64_t*)ciphertextblock)[1] = ((uint64_t*)plaintextblock)[1] ^ state[0][1] ^ state[1][2] ^ (state[2][1] & state[3][1]); ((uint64_t*)ciphertextblock)[2] = ((uint64_t*)plaintextblock)[2] ^ state[0][2] ^ state[1][3] ^ (state[2][2] & state[3][2]); ((uint64_t*)ciphertextblock)[3] = ((uint64_t*)plaintextblock)[3] ^ state[0][3] ^ state[1][0] ^ (state[2][3] & state[3][3]); memcpy(ciphertext, ciphertextblock, len); morus_stateupdate(((uint64_t*)plaintextblock), state); }
// encrypt a partial block void morus_enc_aut_partialblock(const uint8_t *plaintext, uint8_t *ciphertext, uint64_t len, uint64_t state[][4]) { uint8_t plaintextblock[32], ciphertextblock[32]; memset(plaintextblock, 0, 32); memcpy(plaintextblock, plaintext, len); //encryption ((uint64_t*)ciphertextblock)[0] = ((uint64_t*)plaintextblock)[0] ^ state[0][0] ^ state[1][1] ^ (state[2][0] & state[3][0]); ((uint64_t*)ciphertextblock)[1] = ((uint64_t*)plaintextblock)[1] ^ state[0][1] ^ state[1][2] ^ (state[2][1] & state[3][1]); ((uint64_t*)ciphertextblock)[2] = ((uint64_t*)plaintextblock)[2] ^ state[0][2] ^ state[1][3] ^ (state[2][2] & state[3][2]); ((uint64_t*)ciphertextblock)[3] = ((uint64_t*)plaintextblock)[3] ^ state[0][3] ^ state[1][0] ^ (state[2][3] & state[3][3]); memcpy(ciphertext, ciphertextblock, len); morus_stateupdate(((uint64_t*)plaintextblock), state); }
void morus_tag_generation(uint64_t msglen, uint64_t adlen, uint8_t* c, uint64_t state[][4]) { int i; uint8_t t[32] __attribute__((aligned(256))); ((uint64_t*)t)[0] = (adlen << 3); ((uint64_t*)t)[1] = (msglen << 3); ((uint64_t*)t)[2] = 0; ((uint64_t*)t)[3] = 0; state[4][0] ^= state[0][0]; state[4][1] ^= state[0][1]; state[4][2] ^= state[0][2]; state[4][3] ^= state[0][3]; for (i = 0; i < 10; i++) morus_stateupdate((uint64_t*)t, state); state[0][0] = state[0][0] ^ state[1][1] ^ (state[2][0] & state[3][0]); state[0][1] = state[0][1] ^ state[1][2] ^ (state[2][1] & state[3][1]); memcpy(c+msglen, state[0], 16); }
/*The input to the initialization is the 128/256-bit key; 128-bit IV;*/ void morus_initialization(const uint8_t *key, const uint8_t *iv, uint64_t state[][4]) { int i; uint64_t temp[4] = {0,0,0,0}; uint8_t con[32] = {0x0,0x1,0x01,0x02,0x03,0x05,0x08,0x0d,0x15,0x22,0x37,0x59,0x90,0xe9,0x79,0x62, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd}; uint64_t ekey[4]; memcpy(ekey, key, 16); ekey[3] = ekey[1]; ekey[2] = ekey[0]; memcpy(state[0], iv, 16); memset(state[0]+2, 0, 16); memcpy(state[1], ekey, 32); memset(state[2], 0xff, 32); memset(state[3], 0, 32); memcpy(state[4], con, 32); for (i = 0; i < 4; i++) temp[i] = 0; for (i = 0; i < 16; i++) morus_stateupdate(temp, state); for (i = 0; i < 4; i++) state[1][i] ^= ((uint64_t*)ekey)[i]; }
void morus_initialization(const uint8_t* key, const uint8_t* iv, uint64_t state[][4]) { int i; uint64_t temp[4] __attribute__((aligned(256))) = { 0, 0, 0, 0 }; uint8_t con[32] = { 0x0, 0x1, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }; // Concatenate the 16 byte key to itself since MORUS with a 1280 bit state always uses a 256 bit key uint64_t ekey[4] __attribute__((aligned(256))); memcpy(ekey, key, 16); ekey[3] = ekey[1]; ekey[2] = ekey[0]; memcpy(state[0], iv, 16); memset(state[0]+2, 0, 16); memcpy(state[1], ekey, 32); memset(state[2], 0xff, 32); memset(state[3], 0, 32); memcpy(state[4], con, 32); for (i = 0; i < 16; i++) morus_stateupdate(temp, state); for (i = 0; i < 4; i++) state[1][i] ^= ((uint64_t*)ekey)[i]; }
int morus_tag_verification(uint64_t msglen, uint64_t adlen, const uint8_t* c, uint64_t state[][4]) { int i; uint8_t t[32] __attribute__((aligned(256))); int check = 0; ((uint64_t*)t)[0] = (adlen << 3); ((uint64_t*)t)[1] = (msglen << 3); ((uint64_t*)t)[2] = 0; ((uint64_t*)t)[3] = 0; state[4][0] ^= state[0][0]; state[4][1] ^= state[0][1]; state[4][2] ^= state[0][2]; state[4][3] ^= state[0][3]; for (i = 0; i < 10; i++) morus_stateupdate((uint64_t*)t, state); state[0][0] = state[0][0] ^ state[1][1] ^ (state[2][0] & state[3][0]); state[0][1] = state[0][1] ^ state[1][2] ^ (state[2][1] & state[3][1]); for (i = 0; i < 16; i++) check |= (c[msglen + i] ^ ((uint8_t *)state[0])[i]); if (0 == check) return 0; else return -1; }
//the finalization state of MORUS void morus_tag_generation(uint64_t msglen, uint64_t adlen, uint8_t *c, uint64_t state[][4]) { int i,j; uint8_t t[32]; memcpy(t, state[3], 32); ((uint64_t*)t)[0] ^= (adlen << 3); ((uint64_t*)t)[1] ^= (msglen << 3); state[4][0] ^= state[0][0]; state[4][1] ^= state[0][1]; state[4][2] ^= state[0][2]; state[4][3] ^= state[0][3]; for (i = 0; i < 8; i++) morus_stateupdate((uint64_t*)t, state); for (i = 2; i < 5; i++) { for (j = 0; j < 4; j++) { state[1][j] ^= state[i][j]; }} //in this program, the mac length is assumed to be a multiple of bytes memcpy(c+msglen,state[1], 16); }