Last active
November 4, 2018 10:21
-
-
Save Silur/40ecd1de7cc1a7f1d2596cf9af6d3d9a to your computer and use it in GitHub Desktop.
Even-Mansour block cipher using GIMLI in CTR mode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <math.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <assert.h> | |
#define MIN(x,y) y ^ ((x ^ y) & -(x < y)) | |
#define rateInBytes 16 | |
uint32_t | |
rotate(uint32_t x, int bits) | |
{ | |
if (bits == 0) return x; | |
return (x << bits) | (x >> (32 - bits)); | |
} | |
void | |
gimli(uint32_t *state) | |
{ | |
int round; | |
int column; | |
uint32_t x; | |
uint32_t y; | |
uint32_t z; | |
for (round = 24; round > 0; --round) | |
{ | |
for (column = 0; column < 4; ++column) | |
{ | |
x = rotate(state[ column], 24); | |
y = rotate(state[4 + column], 9); | |
z = state[8 + column]; | |
state[8 + column] = x ^ (z << 1) ^ ((y&z) << 2); | |
state[4 + column] = y ^ x ^ ((x|z) << 1); | |
state[column] = z ^ y ^ ((x&y) << 3); | |
} | |
if ((round & 3) == 0) { | |
x = state[0]; | |
state[0] = state[1]; | |
state[1] = x; | |
x = state[2]; | |
state[2] = state[3]; | |
state[3] = x; | |
} | |
if ((round & 3) == 2) { | |
x = state[0]; | |
state[0] = state[2]; | |
state[2] = x; | |
x = state[1]; | |
state[1] = state[3]; | |
state[3] = x; | |
} | |
if ((round & 3) == 0) { | |
state[0] ^= (0x9e377900 | round); | |
} | |
} | |
} | |
void | |
gimli_hash(const uint8_t *input, | |
uint64_t inputByteLen, | |
uint8_t *output, | |
uint64_t outputByteLen) | |
{ | |
uint32_t state[12]; | |
uint8_t* state_8 = (uint8_t*)state; | |
uint64_t blockSize = 0; | |
uint64_t i; | |
memset(state, 0, sizeof(state)); | |
while(inputByteLen > 0) { | |
blockSize = MIN(inputByteLen, rateInBytes); | |
for(i=0; i<blockSize; i++) | |
state_8[i] ^= input[i]; | |
input += blockSize; | |
inputByteLen -= blockSize; | |
if (blockSize == rateInBytes) { | |
gimli(state); | |
blockSize = 0; | |
} | |
} | |
state_8[blockSize] ^= 0x1F; | |
state_8[rateInBytes-1] ^= 0x80; | |
gimli(state); | |
while(outputByteLen > 0) { | |
blockSize = MIN(outputByteLen, rateInBytes); | |
memcpy(output, state, blockSize); | |
output += blockSize; | |
outputByteLen -= blockSize; | |
if (outputByteLen > 0) | |
gimli(state); | |
} | |
} | |
size_t | |
gimli_parse( | |
const unsigned char *input, | |
uint64_t inlen, | |
const unsigned char *key, | |
const unsigned char *iv, | |
unsigned char *output) | |
{ | |
unsigned char nonce[48]; | |
uint64_t ctr = 0; | |
unsigned char ctr_bytes[8] = {0}; | |
int i; | |
unsigned char block[48] = {0}; | |
memcpy(nonce, iv, 40); | |
while((ctr+1)*48 < inlen) | |
{ | |
memcpy(nonce+40, ctr_bytes, 8); | |
for(i=0; i<48; i++) | |
block[i] = nonce[i] ^ key[i]; | |
gimli((uint32_t*)block); | |
for(i=0; i<48; i++) | |
output[(ctr*48)+i] = input[(ctr*48)+i] ^ (block[i] ^ key[i]); | |
ctr++; | |
memcpy(&ctr_bytes, &ctr, 8); | |
} | |
unsigned char padval = (ctr+1)*48 - inlen; | |
assert(padval < 48); | |
unsigned char padded[48] = {0}; | |
for(i=48-padval; i<padval; i++) | |
padded[i] = padval; | |
memcpy(padded, input+(ctr*48), 48-padval); | |
for(i=0; i<48; i++) | |
block[i] = nonce[i] ^ key[i]; | |
gimli((uint32_t*)block); | |
for(i=0; i<48; i++) | |
output[ctr*48+i] = padded[i] ^ (block[i] ^ key[i]); | |
return ctr*48+i; | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
if(argc<3) return 1; | |
int plain_len = atoi(argv[2]); | |
unsigned char derived_key[48]; | |
gimli_hash((unsigned char*)argv[1], strlen(argv[1])+1, derived_key, 48); | |
size_t blen = (size_t)ceil(plain_len/48.0)*48; | |
unsigned char *ciphertext = malloc(blen); | |
unsigned char iv[40]; | |
FILE *fd = fopen("/dev/urandom", "rb"); | |
fread(iv, 1, 40, fd); | |
unsigned char *plain = malloc(plain_len); | |
fread(plain, 1, plain_len, fd); | |
fclose(fd); | |
gimli_parse(plain, plain_len, derived_key, iv, ciphertext); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment