malb / algebraic_attacks (http://informatik.uni-bremen.de/~malb/blog.php)

This repository mainly holds code snippets for experimentation with algebraic attacks (and some general crypto code). The quality of this code is not 'release ready' at all. Although the code should work in general there is a lot of scratch, wrong and pathetic code in this repository. Also, some of this code dates back to my Diplomarbeit (master's thesis) and should be considered broken and outdated. By default all code listed here is released under the GPLv2+. Don't hesitate to ping me if you need something under some more permissive license like BSD-style.

Clone this repository (size: 122.6 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/malb/algebraic_attacks/
commit 35: ce280e2b1a19
parent 34: 3dd50c6be752
branch: default
tags: tip
fixed a very stupid bug in PRESENT which made the polynomial system unecessarily hard
Martin Albrecht / malb
4 weeks ago
algebraic_attacks / present_bitslice.c
r35:ce280e2b1a19 223 loc 6.9 KB embed / history / annotate / raw /
/**
 * Bit-Slice Implementation of PRESENT in C99.
 * v1.0 09/03/2009
 *
 * This implementation is not particulary efficient, e.g. on my C2D it
 * runs with roughly 28 cycles per byte, which is much worse than any
 * efficient AES implementation. It could easily be optimised quite
 * a bit by using SSE2, pushing critical paths down to assembly and by
 * optimising the sbox() function.
 *
 * Martin Albrecht <M.R.Albrecht@rhul.ac.uk>
 *
 * To compile try:
 *   gcc -O2 -g -std=c99 -lgmp present_bitslice.c -o present_bitslice
 *
 * TODO:
 *  - improve performance
 *  - make it safer, right now we assume sizeof(word) == 8
 */

#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>

#define RADIX 64
typedef uint64_t word;

#define ONE 1ULL
#define ZERO 0ULL
#define FF (0xFFFFFFFFFFFFFFFFULL)

#define Bs 64
#define Ks 80

void transpose(word *out, word *inp, const size_t out_size, const size_t inp_size) {
  for(size_t j=0; j<out_size; j++) {
    out[j] = 0;
    for(size_t i=0; i<inp_size; i++) {
      out[j] |= ((inp[i]&(ONE<<(out_size-j-1)))>>(out_size-j-1))<<(inp_size-i-1);
    }
  }
}

/** Encryption **/

static inline void sbox(word *Y0, word *Y1, word *Y2, word *Y3, word X0, word X1, word X2, word X3) {
  /** TODO: This is the most straight-forward representation possible, optimise it! **/
  *Y1 = X0&(X1&X3 ^ X2&X3 ^ X2 ^ X3 ^ FF) ^ X1 ^ X2&X3 ^ FF;
  *Y0 = X0&(X1&X3 ^ X2&X3 ^ FF) ^ X1&X2&X3 ^ X1&X2 ^ X2 ^ X3 ^ FF;
  *Y2 = X0&(X1&X3 ^ X2&X3 ^ X2 ^ X1 ^ FF) ^ X1&X2&X3 ^ X2;
  *Y3 = X0 ^ X1&X2 ^ X1 ^ X3;
}

void sBoxLayer(word *Y, word *X) {
  sbox(Y+ 0,Y+ 1,Y+ 2,Y+ 3, X[ 0],X[ 1],X[ 2],X[ 3]);
  sbox(Y+ 4,Y+ 5,Y+ 6,Y+ 7, X[ 4],X[ 5],X[ 6],X[ 7]);
  sbox(Y+ 8,Y+ 9,Y+10,Y+11, X[ 8],X[ 9],X[10],X[11]);
  sbox(Y+12,Y+13,Y+14,Y+15, X[12],X[13],X[14],X[15]);
  sbox(Y+16,Y+17,Y+18,Y+19, X[16],X[17],X[18],X[19]);

  sbox(Y+20,Y+21,Y+22,Y+23, X[20],X[21],X[22],X[23]);
  sbox(Y+24,Y+25,Y+26,Y+27, X[24],X[25],X[26],X[27]);
  sbox(Y+28,Y+29,Y+30,Y+31, X[28],X[29],X[30],X[31]);
  sbox(Y+32,Y+33,Y+34,Y+35, X[32],X[33],X[34],X[35]);
  sbox(Y+36,Y+37,Y+38,Y+39, X[36],X[37],X[38],X[39]);

  sbox(Y+40,Y+41,Y+42,Y+43, X[40],X[41],X[42],X[43]);
  sbox(Y+44,Y+45,Y+46,Y+47, X[44],X[45],X[46],X[47]);
  sbox(Y+48,Y+49,Y+50,Y+51, X[48],X[49],X[50],X[51]);
  sbox(Y+52,Y+53,Y+54,Y+55, X[52],X[53],X[54],X[55]);
  sbox(Y+56,Y+57,Y+58,Y+59, X[56],X[57],X[58],X[59]);

  sbox(Y+60,Y+61,Y+62,Y+63, X[60],X[61],X[62],X[63]);
}

void addRoundKey(word *X, const word *K) {
  X[ 0] ^= K[ 0],  X[ 1] ^= K[ 1],  X[ 2] ^= K[ 2],  X[ 3] ^= K[ 3];
  X[ 4] ^= K[ 4],  X[ 5] ^= K[ 5],  X[ 6] ^= K[ 6],  X[ 7] ^= K[ 7];
  X[ 8] ^= K[ 8],  X[ 9] ^= K[ 9],  X[10] ^= K[10],  X[11] ^= K[11];
  X[12] ^= K[12],  X[13] ^= K[13],  X[14] ^= K[14],  X[15] ^= K[15];
  X[16] ^= K[16],  X[17] ^= K[17],  X[18] ^= K[18],  X[19] ^= K[19];
  X[20] ^= K[20],  X[21] ^= K[21],  X[22] ^= K[22],  X[23] ^= K[23];
  X[24] ^= K[24],  X[25] ^= K[25],  X[26] ^= K[26],  X[27] ^= K[27];
  X[28] ^= K[28],  X[29] ^= K[29],  X[30] ^= K[30],  X[31] ^= K[31];
  X[32] ^= K[32],  X[33] ^= K[33],  X[34] ^= K[34],  X[35] ^= K[35];
  X[36] ^= K[36],  X[37] ^= K[37],  X[38] ^= K[38],  X[39] ^= K[39];
  X[40] ^= K[40],  X[41] ^= K[41],  X[42] ^= K[42],  X[43] ^= K[43];
  X[44] ^= K[44],  X[45] ^= K[45],  X[46] ^= K[46],  X[47] ^= K[47];
  X[48] ^= K[48],  X[49] ^= K[49],  X[50] ^= K[50],  X[51] ^= K[51];
  X[52] ^= K[52],  X[53] ^= K[53],  X[54] ^= K[54],  X[55] ^= K[55];
  X[56] ^= K[56],  X[57] ^= K[57],  X[58] ^= K[58],  X[59] ^= K[59];
  X[60] ^= K[60],  X[61] ^= K[61],  X[62] ^= K[62],  X[63] ^= K[63];
}

void pLayer(word *X, word *Y) {
  X[ 0] = Y[ 0],  X[ 1] = Y[ 4],  X[ 2] = Y[ 8],  X[ 3] = Y[12];
  X[ 4] = Y[16],  X[ 5] = Y[20],  X[ 6] = Y[24],  X[ 7] = Y[28];
  X[ 8] = Y[32],  X[ 9] = Y[36],  X[10] = Y[40],  X[11] = Y[44];
  X[12] = Y[48],  X[13] = Y[52],  X[14] = Y[56],  X[15] = Y[60];
  X[16] = Y[ 1],  X[17] = Y[ 5],  X[18] = Y[ 9],  X[19] = Y[13];
  X[20] = Y[17],  X[21] = Y[21],  X[22] = Y[25],  X[23] = Y[29];
  X[24] = Y[33],  X[25] = Y[37],  X[26] = Y[41],  X[27] = Y[45];
  X[28] = Y[49],  X[29] = Y[53],  X[30] = Y[57],  X[31] = Y[61];
  X[32] = Y[ 2],  X[33] = Y[ 6],  X[34] = Y[10],  X[35] = Y[14];
  X[36] = Y[18],  X[37] = Y[22],  X[38] = Y[26],  X[39] = Y[30];
  X[40] = Y[34],  X[41] = Y[38],  X[42] = Y[42],  X[43] = Y[46];
  X[44] = Y[50],  X[45] = Y[54],  X[46] = Y[58],  X[47] = Y[62];
  X[48] = Y[ 3],  X[49] = Y[ 7],  X[50] = Y[11],  X[51] = Y[15];
  X[52] = Y[19],  X[53] = Y[23],  X[54] = Y[27],  X[55] = Y[31];
  X[56] = Y[35],  X[57] = Y[39],  X[58] = Y[43],  X[59] = Y[47];
  X[60] = Y[51],  X[61] = Y[55],  X[62] = Y[59],  X[63] = Y[63];
}

void encrypt(word *X, const word *subkeys, const size_t nr) {
  static word Y[Bs];
  for(size_t i=0; i<nr;i++) {
    addRoundKey(X, subkeys + (i*Bs));
    sBoxLayer(Y, X);
    pLayer(X, Y);
  }
  addRoundKey(X, subkeys + (nr*Bs));
}

/** Key Schedule **/

void rotate(word *k) {
  static word temp[Ks];
  memcpy(temp,k,Ks*sizeof(word));
  for(size_t i =0; i<Ks; i++) {
    k[i] = temp[(61+i)%Ks];
  }
}

static inline void round_constant(word *rc, size_t i) {
  static word lookup[2] = {ZERO,FF};
  rc[4] = lookup[(i&(1<<0))>>0];
  rc[3] = lookup[(i&(1<<1))>>1];
  rc[2] = lookup[(i&(1<<2))>>2];
  rc[1] = lookup[(i&(1<<3))>>3];
  rc[0] = lookup[(i&(1<<4))>>4];

}

void key_schedule(word *subkeys, word *key, const size_t nr) {
  /** TODO: The key schedule isn't optimised at all */
  word *ki = subkeys;
  word S[4];
  word rc[5];
  for(size_t i=0; i<=nr; i++) {
    for(size_t j=0; j<Bs; j++)
      ki[j] = key[j];
    ki+=Bs;

    rotate(key);

    sbox(&S[0],&S[1],&S[2],&S[3], key[0], key[1], key[2], key[3]);
    key[0] = S[0], key[1] = S[1], key[2] = S[2], key[3] = S[3];

    round_constant(rc, i+1);
    key[Ks-1-19] ^= rc[0], key[Ks-1-18] ^= rc[1], key[Ks-1-17] ^= rc[2];
    key[Ks-1-16] ^= rc[3], key[Ks-1-15] ^= rc[4];
  }
}

/** PRNG **/

static gmp_randstate_t r_state;

word random_word(void) {
  mpz_t rand_n;
  mpz_init(rand_n);

  mpz_urandomb(rand_n, r_state, 64);
  word ret = mpz_get_ui(rand_n);
  mpz_clear(rand_n);
  return ret;
};

void seed_prng(void) {
  struct timeval tp;
  (void) gettimeofday(&tp,NULL);
  unsigned long seed = tp.tv_sec ^ tp.tv_usec;
  gmp_randinit_default(r_state);
  gmp_randseed_ui(r_state, seed);
}

int main(int arc, char **argv) {
  const size_t ntrials = 1;
  seed_prng();

  uint64_t plaintexts[RADIX];
  uint64_t ciphertexts[RADIX];
  word tmp[Bs];
  word key[Ks];

  size_t nr = 31;

  for(size_t i=0;i<Ks;i++)
    key[i] = 0;//random_word();

  word *subkeys = calloc(Bs * sizeof(word),nr+1);
  key_schedule(subkeys, key, nr);

  for(size_t i=0; i<Bs; i++)
    plaintexts[i] = i;//random_word();
  transpose(tmp, plaintexts, Bs, RADIX);

  for(size_t i=0;i<ntrials;i++)
    encrypt(tmp, subkeys, nr);

  transpose(ciphertexts, tmp,  RADIX, Bs);
  for(size_t i=0; i<Bs; i++) {
    printf("%16llx %16llx\n",plaintexts[i],ciphertexts[i]);
  }
  free(subkeys);
}