]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
Updated proxmark research with Holiman's loclass framework
authorAndrew Davies <apdavies03@Andrews-MacBook-Pro.local>
Fri, 2 May 2014 10:11:54 +0000 (11:11 +0100)
committerAndrew Davies <apdavies03@Andrews-MacBook-Pro.local>
Fri, 2 May 2014 10:11:54 +0000 (11:11 +0100)
client/Makefile
client/cmdhficlass.c
client/loclass/cipher.c [new file with mode: 0644]
client/loclass/cipher.h [new file with mode: 0644]
client/loclass/cipherutils.c [new file with mode: 0644]
client/loclass/cipherutils.h [new file with mode: 0644]
client/loclass/des.c [new file with mode: 0644]
client/loclass/des.h [new file with mode: 0644]
client/loclass/ikeys.c [new file with mode: 0644]
client/loclass/ikeys.h [new file with mode: 0644]

index 6d75b4bbb6c8957f0c41841dbb2c23b603575334..c47e8526e69c79d459c2bda02763d4bd80cfa913 100644 (file)
@@ -15,7 +15,7 @@ OBJDIR = obj
 
 LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
 LDFLAGS = $(COMMON_FLAGS)
-CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
+CFLAGS = -std=c99 -lcrypto -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 
 LUAPLATFORM = generic
 
 ifneq (,$(findstring MINGW,$(platform)))
@@ -24,9 +24,9 @@ QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
 MOC = $(QTDIR)/bin/moc
 LUAPLATFORM = mingw
 else ifeq ($(platform),Darwin)
-CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
-QTLDLIBS = -framework QtGui -framework QtCore
-MOC = moc 
+CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
+QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
+MOC = $(shell pkg-config --variable=moc_location QtCore)
 LUAPLATFORM = macosx
 else
 CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
@@ -56,6 +56,10 @@ CORESRCS =   uart.c \
 CMDSRCS =      nonce2key/crapto1.c\
                nonce2key/crypto1.c\
                nonce2key/nonce2key.c\
+               loclass/cipher.c \
+               loclass/cipherutils.c \
+               loclass/des.c \
+               loclass/ikeys.c \
                        mifarehost.c\
                        crc16.c \
                        iso14443crc.c \
@@ -74,8 +78,8 @@ CMDSRCS =     nonce2key/crapto1.c\
                        cmdhfmf.c \
                        cmdhw.c \
                        cmdlf.c \
-                       cmdlfhid.c \
                        cmdlfio.c \
+                       cmdlfhid.c \
                        cmdlfem4x.c \
                        cmdlfhitag.c \
                        cmdlfti.c \
index aa5a2145f8c04471639cd86e2f6987a3a0ad0b39..34e8f6d9f89c0540208b524ab3b8764491f890c0 100644 (file)
 #include "cmdhficlass.h"
 #include "common.h"
 #include "util.h"
+#include "loclass/des.h"
+#include "loclass/cipherutils.h"
+#include "loclass/cipher.h"
+#include "loclass/ikeys.h"
 
 static int CmdHelp(const char *Cmd);
 
@@ -247,6 +251,72 @@ int CmdHFiClassReader_Replay(const char *Cmd)
   return 0;
 }
 
+int CmdHFiClassReader_Dump(const char *Cmd)
+{
+  uint8_t readerType = 0;
+  uint8_t MAC[4]={0x00,0x00,0x00,0x00};
+  uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t result[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+  des_context ctx_enc;
+  uint64_t crypted_id=0;
+
+  if (strlen(Cmd)<3) {
+    PrintAndLog("Usage:  hf iclass dump <Key> <CSN> <CC>");
+    PrintAndLog("        sample: hf iclass dump 0011223344556677 aabbccddeeffgghh FFFFFFFFFFFFFFFF");
+    return 0;
+  }
+
+  if (param_gethex(Cmd, 0, KEY, 16)) {
+    PrintAndLog("KEY must include 16 HEX symbols");
+    return 1;
+  }
+  
+  if (param_gethex(Cmd, 1, CSN, 16)) {
+    PrintAndLog("CSN must include 16 HEX symbols");
+    return 1;
+  }
+  if (param_gethex(Cmd, 2, CC_temp, 16)) {
+    PrintAndLog("CC must include 16 HEX symbols");
+    return 1;
+  }
+  
+  memcpy(CCNR,CC_temp,8);
+  des_setkey_enc( &ctx_enc, KEY);
+  des_crypt_ecb(&ctx_enc,CSN,result);
+  PrintAndLog("DES Key: %s",sprint_hex(result,8));
+    uint64_t newz=0;
+       crypted_id = bytes_to_num(result,8);
+       uint64_t x = (crypted_id & 0xFFFF000000000000 );
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,0),7);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,1),6);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,2),5);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,3),4);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,4),3);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,5),2);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,6),1);
+       pushbackSixBitByte(&newz, getSixBitByte(crypted_id,7),0);
+       newz|= x;
+       crypted_id=newz;
+       num_to_bytes(crypted_id,8,result);
+  PrintAndLog("DESr Key: %s",sprint_hex(result,8));    
+  //crypted_id = bytes_to_num(result,8);
+  //memset(result,0,8);
+  hash0(crypted_id,div_key);
+  //memcpy(div_key,result,8);
+  PrintAndLog("Div Key: %s",sprint_hex(div_key,8));
+  calc_iclass_mac(CCNR,div_key,MAC);
+
+  UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
+  memcpy(c.d.asBytes, MAC, 4);
+  SendCommand(&c);
+
+  return 0;
+}
+
 
 static command_t CommandTable[] = 
 {
@@ -256,6 +326,7 @@ static command_t CommandTable[] =
   {"sim",     CmdHFiClassSim,    0, "Simulate iClass tag"},
   {"reader",  CmdHFiClassReader, 0, "Read an iClass tag"},
   {"replay",  CmdHFiClassReader_Replay, 0, "Read an iClass tag via Reply Attack"},
+  {"dump",       CmdHFiClassReader_Dump, 0, "Authenticate and Dump iClass tag"},
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c
new file mode 100644 (file)
index 0000000..d7c9abd
--- /dev/null
@@ -0,0 +1,260 @@
+/*****************************************************************************
+ * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This file 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "loclass/cipher.h"
+#include "loclass/cipherutils.h"
+#include "loclass/ikeys.h"
+
+uint8_t keytable[] = { 0,0,0,0,0,0,0,0};
+
+/**
+*      Definition 2. The feedback function for the top register T : F 16/2 → F 2
+*      is defined as
+*      T (x 0 x 1 . . . . . . x 15 ) = x 0 ⊕ x 1 ⊕ x 5 ⊕ x 7 ⊕ x 10 ⊕ x 11 ⊕ x 14 ⊕ x 15 .
+**/
+bool T(State state)
+{
+       bool x0 = state.t & 0x8000;
+       bool x1 = state.t & 0x4000;
+       bool x5 = state.t & 0x0400;
+       bool x7 = state.t & 0x0100;
+       bool x10 = state.t & 0x0020;
+       bool x11 = state.t & 0x0010;
+       bool x14 = state.t & 0x0002;
+       bool x15 = state.t & 0x0001;
+       return x0 ^ x1 ^ x5 ^ x7 ^ x10 ^ x11 ^ x14 ^ x15;
+}
+/**
+*      Similarly, the feedback function for the bottom register B : F 8/2 → F 2 is defined as
+*      B(x 0 x 1 . . . x 7 ) = x 1 ⊕ x 2 ⊕ x 3 ⊕ x 7 .
+**/
+bool B(State state)
+{
+       bool x1 = state.b & 0x40;
+       bool x2 = state.b & 0x20;
+       bool x3 = state.b & 0x10;
+       bool x7 = state.b & 0x01;
+
+       return x1 ^ x2 ^ x3 ^ x7;
+
+}
+
+
+/**
+*      Definition 3 (Selection function). The selection function select : F 2 × F 2 ×
+*      F 8/2 → F 3/2 is defined as select(x, y, r) = z 0 z 1 z 2 where
+*      z 0 = (r 0 ∧ r 2 ) ⊕ (r 1 ∧ r 3 ) ⊕ (r 2 ∨ r 4 )
+*      z 1 = (r 0 ∨ r 2 ) ⊕ (r 5 ∨ r 7 ) ⊕ r 1 ⊕ r 6 ⊕ x ⊕ y
+*      z 2 = (r 3 ∧ r 5 ) ⊕ (r 4 ∧ r 6 ) ⊕ r 7 ⊕ x
+**/
+uint8_t _select(bool x, bool y, uint8_t r)
+{
+       bool r0 = r >> 7 & 0x1;
+       bool r1 = r >> 6 & 0x1;
+       bool r2 = r >> 5 & 0x1;
+       bool r3 = r >> 4 & 0x1;
+       bool r4 = r >> 3 & 0x1;
+       bool r5 = r >> 2 & 0x1;
+       bool r6 = r >> 1 & 0x1;
+       bool r7 = r & 0x1;
+
+       bool z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4);
+       bool z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y;
+       bool z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x;
+
+       // The three bitz z0.. z1 are packed into a uint8_t:
+       // 00000ZZZ
+       //Return value is a uint8_t
+       uint8_t retval = 0;
+       retval |= (z0 << 2) & 4;
+       retval |= (z1 << 1) & 2;
+       retval |= z2 & 1;
+
+       // Return value 0 <= retval <= 7
+       return retval;
+}
+
+/**
+*      Definition 4 (Successor state). Let s = l, r, t, b be a cipher state, k ∈ (F 82 ) 8
+*      be a key and y ∈ F 2 be the input bit. Then, the successor cipher state s ′ =
+*      l ′ , r ′ , t ′ , b ′ is defined as
+*      t ′ := (T (t) ⊕ r 0 ⊕ r 4 )t 0 . . . t 14 l ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l ⊞ r
+*      b ′ := (B(b) ⊕ r 7 )b 0 . . . b 6 r ′ := (k [select(T (t),y,r)] ⊕ b ′ ) ⊞ l
+*
+* @param s - state
+* @param k - array containing 8 bytes
+**/
+State successor(uint8_t* k, State s, bool y)
+{
+       bool r0 = s.r >> 7 & 0x1;
+       bool r4 = s.r >> 3 & 0x1;
+       bool r7 = s.r & 0x1;
+
+       State successor = {0,0,0,0};
+
+       successor.t = s.t >> 1;
+       successor.t |= (T(s) ^ r0 ^ r4) << 15;
+
+       successor.b = s.b >> 1;
+       successor.b |= (B(s) ^ r7) << 7;
+
+       bool Tt = T(s);
+
+       successor.l = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l+s.r ) & 0xFF;
+       successor.r = ((k[_select(Tt,y,s.r)] ^ successor.b) + s.l ) & 0xFF;
+
+       return successor;
+}
+/**
+*      We define the successor function suc which takes a key k ∈ (F 82 ) 8 , a state s and
+*      an input y ∈ F 2 and outputs the successor state s ′ . We overload the function suc
+*      to multiple bit input x ∈ F n 2 which we define as
+* @param k - array containing 8 bytes
+**/
+State suc(uint8_t* k,State s, BitstreamIn *bitstream)
+{
+       if(bitsLeft(bitstream) == 0)
+       {
+               return s;
+       }
+       bool lastbit = tailBit(bitstream);
+       return successor(k,suc(k,s,bitstream), lastbit);
+}
+
+/**
+*      Definition 5 (Output). Define the function output which takes an internal
+*      state s =< l, r, t, b > and returns the bit r 5 . We also define the function output
+*      on multiple bits input which takes a key k, a state s and an input x ∈ F n 2 as
+*      output(k, s, ǫ) = ǫ
+*      output(k, s, x 0 . . . x n ) = output(s) · output(k, s ′ , x 1 . . . x n )
+*      where s ′ = suc(k, s, x 0 ).
+**/
+void output(uint8_t* k,State s, BitstreamIn* in,  BitstreamOut* out)
+{
+       if(bitsLeft(in) == 0)
+       {
+               return;
+       }
+       //printf("bitsleft %d" , bitsLeft(in));
+       //printf(" %0d", s.r >> 2 & 1);
+       pushBit(out,(s.r >> 2) & 1);
+       //Remove first bit
+       uint8_t x0 = headBit(in);
+       State ss = successor(k,s,x0);
+       output(k,ss,in, out);
+}
+
+/**
+* Definition 6 (Initial state). Define the function init which takes as input a
+* key k ∈ (F 82 ) 8 and outputs the initial cipher state s =< l, r, t, b >
+**/
+
+State init(uint8_t* k)
+{
+       State s = {
+       ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
+       ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
+       0x4c, // b
+       0xE012 // t
+       };
+       return s;
+}
+void MAC(uint8_t* k, BitstreamIn input, BitstreamOut out)
+{
+       uint8_t zeroes_32[] = {0,0,0,0};
+       BitstreamIn input_32_zeroes = {zeroes_32,sizeof(zeroes_32)*8,0};
+       State initState = suc(k,init(k),&input);
+       output(k,initState,&input_32_zeroes,&out);
+
+}
+
+
+void printarr(char * name, uint8_t* arr, int len)
+{
+       int i ;
+       printf("uint8_t %s[] = {", name);
+       for(i =0 ;  i< len ; i++)
+       {
+               printf("0x%02x,",*(arr+i));
+       }
+       printf("};\n");
+}
+
+int testMAC()
+{
+
+       //From the "dismantling.IClass" paper:
+       uint8_t cc_nr[] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0};
+       // But actually, that must be reversed, it's "on-the-wire" data
+       reverse_arraybytes(cc_nr,sizeof(cc_nr));
+
+       //From the paper
+       uint8_t div_key[] = {0xE0,0x33,0xCA,0x41,0x9A,0xEE,0x43,0xF9};
+       uint8_t correct_MAC[] = {0x1d,0x49,0xC9,0xDA};
+
+       BitstreamIn bitstream = {cc_nr,sizeof(cc_nr) * 8,0};
+       uint8_t dest []= {0,0,0,0,0,0,0,0};
+       BitstreamOut out = { dest, sizeof(dest)*8, 0 };
+       MAC(div_key,bitstream, out);
+       //The output MAC must also be reversed
+       reverse_arraybytes(dest, sizeof(dest));
+
+       if(false && memcmp(dest, correct_MAC,4) == 0)
+       {
+               printf("MAC calculation OK!\n");
+
+       }else
+       {
+               printf("MAC calculation failed\n");
+               printarr("Calculated_MAC", dest, 4);
+               printarr("Correct_MAC   ", correct_MAC, 4);
+               return 1;
+       }
+       return 0;
+}
+
+int calc_iclass_mac(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t *mac)
+{
+    uint8_t cc_nr[12];
+    uint8_t div_key[8];
+    memcpy(cc_nr,cc_nr_p,12);
+    memcpy(div_key,div_key_p,8);
+    
+       reverse_arraybytes(cc_nr,sizeof(cc_nr));
+       BitstreamIn bitstream = {cc_nr,sizeof(cc_nr) * 8,0};
+       uint8_t dest []= {0,0,0,0,0,0,0,0};
+       BitstreamOut out = { dest, sizeof(dest)*8, 0 };
+       MAC(div_key,bitstream, out);
+       //The output MAC must also be reversed
+       reverse_arraybytes(dest, sizeof(dest));
+       
+       printf("Calculated_MAC\t%02x%02x%02x%02x\n", dest[0],dest[1],dest[2],dest[3]);
+       memcpy(mac,dest,4);
+       
+       return 1;
+}
\ No newline at end of file
diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h
new file mode 100644 (file)
index 0000000..10ea805
--- /dev/null
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This file 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+ ****************************************************************************/
+
+#ifndef CIPHER_H
+#define CIPHER_H
+#include <stdint.h>
+
+/**
+* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
+* consisting of the following four components:
+*      1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ;
+*      2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ;
+*      3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 .
+*      4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 .
+**/
+typedef struct {
+       uint8_t l;
+       uint8_t r;
+       uint8_t b;
+       uint16_t t;
+} State;
+
+void printarr(char * name, uint8_t* arr, int len);
+int calc_iclass_mac(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t *mac);
+
+#endif // CIPHER_H
diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c
new file mode 100644 (file)
index 0000000..685a381
--- /dev/null
@@ -0,0 +1,195 @@
+/*****************************************************************************
+ * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This file 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+ ****************************************************************************/
+
+#include "cipherutils.h"
+#include "../util.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+/**
+ *
+ * @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
+ * @param stream
+ * @return
+ */
+bool headBit( BitstreamIn *stream)
+{
+       int bytepos = stream->position >> 3; // divide by 8
+       int bitpos = (stream->position++) & 7; // mask out 00000111
+       return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
+}
+/**
+ * @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
+ * @param stream
+ * @return
+ */
+bool tailBit( BitstreamIn *stream)
+{
+       int bitpos = stream->numbits -1 - (stream->position++);
+
+       int bytepos= bitpos >> 3;
+       bitpos &= 7;
+       return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1;
+}
+/**
+ * @brief Pushes bit onto the stream
+ * @param stream
+ * @param bit
+ */
+void pushBit( BitstreamOut* stream, bool bit)
+{
+       int bytepos = stream->position >> 3; // divide by 8
+       int bitpos = stream->position & 7;
+       *(stream->buffer+bytepos) |= (bit & 1) <<  (7 - bitpos);
+       stream->position++;
+       stream->numbits++;
+}
+
+/**
+ * @brief Pushes the lower six bits onto the stream
+ * as b0 b1 b2 b3 b4 b5 b6
+ * @param stream
+ * @param bits
+ */
+void push6bits( BitstreamOut* stream, uint8_t bits)
+{
+       pushBit(stream, bits & 0x20);
+       pushBit(stream, bits & 0x10);
+       pushBit(stream, bits & 0x08);
+       pushBit(stream, bits & 0x04);
+       pushBit(stream, bits & 0x02);
+       pushBit(stream, bits & 0x01);
+}
+
+/**
+ * @brief bitsLeft
+ * @param stream
+ * @return number of bits left in stream
+ */
+int bitsLeft( BitstreamIn *stream)
+{
+       return stream->numbits - stream->position;
+}
+/**
+ * @brief numBits
+ * @param stream
+ * @return Number of bits stored in stream
+ */
+int numBits(BitstreamOut *stream)
+{
+       return stream->numbits;
+}
+
+uint8_t reversebytes(uint8_t b) {
+       b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
+       b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
+       b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
+   return b;
+}
+void reverse_arraybytes(uint8_t* arr, size_t len)
+{
+       uint8_t i;
+       for( i =0; i< len ; i++)
+       {
+               arr[i] = reversebytes(arr[i]);
+       }
+}
+
+
+//-----------------------------
+// Code for testing below
+//-----------------------------
+
+
+int testBitStream()
+{
+       uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
+       uint8_t output [] = {0,0,0,0,0,0,0,0};
+       BitstreamIn in = { input, sizeof(input) * 8,0};
+       BitstreamOut out ={ output, 0,0}
+                                         ;
+       while(bitsLeft(&in) > 0)
+       {
+               pushBit(&out, headBit(&in));
+               //printf("Bits left: %d\n", bitsLeft(&in));
+               //printf("Bits out: %d\n", numBits(&out));
+       }
+       if(memcmp(input, output, sizeof(input)) == 0)
+       {
+               printf("Bitstream test 1 ok\n");
+       }else
+       {
+               printf("Bitstream test 1 failed\n");
+               uint8_t i;
+               for(i = 0 ; i < sizeof(input) ; i++)
+               {
+                       printf("IN %02x, OUT %02x\n", input[i], output[i]);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int testReversedBitstream()
+{
+       uint8_t input [] = {0xDE,0xAD,0xBE,0xEF,0xDE,0xAD,0xBE,0xEF};
+       uint8_t reverse [] = {0,0,0,0,0,0,0,0};
+       uint8_t output [] = {0,0,0,0,0,0,0,0};
+       BitstreamIn in = { input, sizeof(input) * 8,0};
+       BitstreamOut out ={ output, 0,0};
+       BitstreamIn reversed_in ={ reverse, sizeof(input)*8,0};
+       BitstreamOut reversed_out ={ reverse,0 ,0};
+
+       while(bitsLeft(&in) > 0)
+       {
+               pushBit(&reversed_out, tailBit(&in));
+       }
+       while(bitsLeft(&reversed_in) > 0)
+       {
+               pushBit(&out, tailBit(&reversed_in));
+       }
+       if(memcmp(input, output, sizeof(input)) == 0)
+       {
+               printf("Bitstream test 2 ok\n");
+       }else
+       {
+               printf("Bitstream test 2 failed\n");
+               uint8_t i;
+               for(i = 0 ; i < sizeof(input) ; i++)
+               {
+                       printf("IN %02x, MIDDLE: %02x, OUT %02x\n", input[i],reverse[i], output[i]);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+
+int testCipherUtils(void)
+{
+       int retval = 0;
+       retval |= testBitStream();
+       retval |= testReversedBitstream();
+       return retval;
+}
diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h
new file mode 100644 (file)
index 0000000..84435da
--- /dev/null
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This file 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+ ****************************************************************************/
+
+#ifndef CIPHERUTILS_H
+#define CIPHERUTILS_H
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+typedef struct {
+       uint8_t * buffer;
+       uint8_t numbits;
+       uint8_t position;
+} BitstreamIn;
+
+typedef struct {
+       uint8_t * buffer;
+       uint8_t numbits;
+       uint8_t position;
+}BitstreamOut;
+
+bool headBit( BitstreamIn *stream);
+bool tailBit( BitstreamIn *stream);
+void pushBit( BitstreamOut *stream, bool bit);
+int bitsLeft( BitstreamIn *stream);
+bool xorbits_8(uint8_t val);
+bool xorbits_16(uint16_t val);
+int testCipherUtils(void);
+int testMAC();
+void push6bits( BitstreamOut* stream, uint8_t bits);
+void EncryptDES(bool key[56], bool outBlk[64], bool inBlk[64], int verbose) ;
+uint8_t reversebytes(uint8_t b);
+void reverse_arraybytes(uint8_t* arr, size_t len);
+
+#endif // CIPHERUTILS_H
diff --git a/client/loclass/des.c b/client/loclass/des.c
new file mode 100644 (file)
index 0000000..746752d
--- /dev/null
@@ -0,0 +1,1014 @@
+/*
+ *  FIPS-46-3 compliant Triple-DES implementation
+ *
+ *  Copyright (C) 2006-2014, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  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 2 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, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ *  DES, on which TDES is based, was originally designed by Horst Feistel
+ *  at IBM in 1974, and was adopted as a standard by NIST (formerly NBS).
+ *
+ *  http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf
+ */
+
+//#include "polarssl/config.h"
+#define POLARSSL_DES_C
+
+#if defined(POLARSSL_DES_C)
+
+#include "des.h"
+
+#if defined(POLARSSL_PLATFORM_C)
+#include "polarssl/platform.h"
+#else
+#define polarssl_printf printf
+#endif
+
+#if !defined(POLARSSL_DES_ALT)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i)                            \
+{                                                       \
+       (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
+               | ( (uint32_t) (b)[(i) + 1] << 16 )             \
+               | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
+               | ( (uint32_t) (b)[(i) + 3]       );            \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i)                            \
+{                                                       \
+       (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
+       (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
+       (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
+       (b)[(i) + 3] = (unsigned char) ( (n)       );       \
+}
+#endif
+
+/*
+ * Expanded DES S-boxes
+ */
+static const uint32_t SB1[64] =
+{
+       0x01010400, 0x00000000, 0x00010000, 0x01010404,
+       0x01010004, 0x00010404, 0x00000004, 0x00010000,
+       0x00000400, 0x01010400, 0x01010404, 0x00000400,
+       0x01000404, 0x01010004, 0x01000000, 0x00000004,
+       0x00000404, 0x01000400, 0x01000400, 0x00010400,
+       0x00010400, 0x01010000, 0x01010000, 0x01000404,
+       0x00010004, 0x01000004, 0x01000004, 0x00010004,
+       0x00000000, 0x00000404, 0x00010404, 0x01000000,
+       0x00010000, 0x01010404, 0x00000004, 0x01010000,
+       0x01010400, 0x01000000, 0x01000000, 0x00000400,
+       0x01010004, 0x00010000, 0x00010400, 0x01000004,
+       0x00000400, 0x00000004, 0x01000404, 0x00010404,
+       0x01010404, 0x00010004, 0x01010000, 0x01000404,
+       0x01000004, 0x00000404, 0x00010404, 0x01010400,
+       0x00000404, 0x01000400, 0x01000400, 0x00000000,
+       0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
+
+static const uint32_t SB2[64] =
+{
+       0x80108020, 0x80008000, 0x00008000, 0x00108020,
+       0x00100000, 0x00000020, 0x80100020, 0x80008020,
+       0x80000020, 0x80108020, 0x80108000, 0x80000000,
+       0x80008000, 0x00100000, 0x00000020, 0x80100020,
+       0x00108000, 0x00100020, 0x80008020, 0x00000000,
+       0x80000000, 0x00008000, 0x00108020, 0x80100000,
+       0x00100020, 0x80000020, 0x00000000, 0x00108000,
+       0x00008020, 0x80108000, 0x80100000, 0x00008020,
+       0x00000000, 0x00108020, 0x80100020, 0x00100000,
+       0x80008020, 0x80100000, 0x80108000, 0x00008000,
+       0x80100000, 0x80008000, 0x00000020, 0x80108020,
+       0x00108020, 0x00000020, 0x00008000, 0x80000000,
+       0x00008020, 0x80108000, 0x00100000, 0x80000020,
+       0x00100020, 0x80008020, 0x80000020, 0x00100020,
+       0x00108000, 0x00000000, 0x80008000, 0x00008020,
+       0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
+
+static const uint32_t SB3[64] =
+{
+       0x00000208, 0x08020200, 0x00000000, 0x08020008,
+       0x08000200, 0x00000000, 0x00020208, 0x08000200,
+       0x00020008, 0x08000008, 0x08000008, 0x00020000,
+       0x08020208, 0x00020008, 0x08020000, 0x00000208,
+       0x08000000, 0x00000008, 0x08020200, 0x00000200,
+       0x00020200, 0x08020000, 0x08020008, 0x00020208,
+       0x08000208, 0x00020200, 0x00020000, 0x08000208,
+       0x00000008, 0x08020208, 0x00000200, 0x08000000,
+       0x08020200, 0x08000000, 0x00020008, 0x00000208,
+       0x00020000, 0x08020200, 0x08000200, 0x00000000,
+       0x00000200, 0x00020008, 0x08020208, 0x08000200,
+       0x08000008, 0x00000200, 0x00000000, 0x08020008,
+       0x08000208, 0x00020000, 0x08000000, 0x08020208,
+       0x00000008, 0x00020208, 0x00020200, 0x08000008,
+       0x08020000, 0x08000208, 0x00000208, 0x08020000,
+       0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const uint32_t SB4[64] =
+{
+       0x00802001, 0x00002081, 0x00002081, 0x00000080,
+       0x00802080, 0x00800081, 0x00800001, 0x00002001,
+       0x00000000, 0x00802000, 0x00802000, 0x00802081,
+       0x00000081, 0x00000000, 0x00800080, 0x00800001,
+       0x00000001, 0x00002000, 0x00800000, 0x00802001,
+       0x00000080, 0x00800000, 0x00002001, 0x00002080,
+       0x00800081, 0x00000001, 0x00002080, 0x00800080,
+       0x00002000, 0x00802080, 0x00802081, 0x00000081,
+       0x00800080, 0x00800001, 0x00802000, 0x00802081,
+       0x00000081, 0x00000000, 0x00000000, 0x00802000,
+       0x00002080, 0x00800080, 0x00800081, 0x00000001,
+       0x00802001, 0x00002081, 0x00002081, 0x00000080,
+       0x00802081, 0x00000081, 0x00000001, 0x00002000,
+       0x00800001, 0x00002001, 0x00802080, 0x00800081,
+       0x00002001, 0x00002080, 0x00800000, 0x00802001,
+       0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const uint32_t SB5[64] =
+{
+       0x00000100, 0x02080100, 0x02080000, 0x42000100,
+       0x00080000, 0x00000100, 0x40000000, 0x02080000,
+       0x40080100, 0x00080000, 0x02000100, 0x40080100,
+       0x42000100, 0x42080000, 0x00080100, 0x40000000,
+       0x02000000, 0x40080000, 0x40080000, 0x00000000,
+       0x40000100, 0x42080100, 0x42080100, 0x02000100,
+       0x42080000, 0x40000100, 0x00000000, 0x42000000,
+       0x02080100, 0x02000000, 0x42000000, 0x00080100,
+       0x00080000, 0x42000100, 0x00000100, 0x02000000,
+       0x40000000, 0x02080000, 0x42000100, 0x40080100,
+       0x02000100, 0x40000000, 0x42080000, 0x02080100,
+       0x40080100, 0x00000100, 0x02000000, 0x42080000,
+       0x42080100, 0x00080100, 0x42000000, 0x42080100,
+       0x02080000, 0x00000000, 0x40080000, 0x42000000,
+       0x00080100, 0x02000100, 0x40000100, 0x00080000,
+       0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const uint32_t SB6[64] =
+{
+       0x20000010, 0x20400000, 0x00004000, 0x20404010,
+       0x20400000, 0x00000010, 0x20404010, 0x00400000,
+       0x20004000, 0x00404010, 0x00400000, 0x20000010,
+       0x00400010, 0x20004000, 0x20000000, 0x00004010,
+       0x00000000, 0x00400010, 0x20004010, 0x00004000,
+       0x00404000, 0x20004010, 0x00000010, 0x20400010,
+       0x20400010, 0x00000000, 0x00404010, 0x20404000,
+       0x00004010, 0x00404000, 0x20404000, 0x20000000,
+       0x20004000, 0x00000010, 0x20400010, 0x00404000,
+       0x20404010, 0x00400000, 0x00004010, 0x20000010,
+       0x00400000, 0x20004000, 0x20000000, 0x00004010,
+       0x20000010, 0x20404010, 0x00404000, 0x20400000,
+       0x00404010, 0x20404000, 0x00000000, 0x20400010,
+       0x00000010, 0x00004000, 0x20400000, 0x00404010,
+       0x00004000, 0x00400010, 0x20004010, 0x00000000,
+       0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const uint32_t SB7[64] =
+{
+       0x00200000, 0x04200002, 0x04000802, 0x00000000,
+       0x00000800, 0x04000802, 0x00200802, 0x04200800,
+       0x04200802, 0x00200000, 0x00000000, 0x04000002,
+       0x00000002, 0x04000000, 0x04200002, 0x00000802,
+       0x04000800, 0x00200802, 0x00200002, 0x04000800,
+       0x04000002, 0x04200000, 0x04200800, 0x00200002,
+       0x04200000, 0x00000800, 0x00000802, 0x04200802,
+       0x00200800, 0x00000002, 0x04000000, 0x00200800,
+       0x04000000, 0x00200800, 0x00200000, 0x04000802,
+       0x04000802, 0x04200002, 0x04200002, 0x00000002,
+       0x00200002, 0x04000000, 0x04000800, 0x00200000,
+       0x04200800, 0x00000802, 0x00200802, 0x04200800,
+       0x00000802, 0x04000002, 0x04200802, 0x04200000,
+       0x00200800, 0x00000000, 0x00000002, 0x04200802,
+       0x00000000, 0x00200802, 0x04200000, 0x00000800,
+       0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const uint32_t SB8[64] =
+{
+       0x10001040, 0x00001000, 0x00040000, 0x10041040,
+       0x10000000, 0x10001040, 0x00000040, 0x10000000,
+       0x00040040, 0x10040000, 0x10041040, 0x00041000,
+       0x10041000, 0x00041040, 0x00001000, 0x00000040,
+       0x10040000, 0x10000040, 0x10001000, 0x00001040,
+       0x00041000, 0x00040040, 0x10040040, 0x10041000,
+       0x00001040, 0x00000000, 0x00000000, 0x10040040,
+       0x10000040, 0x10001000, 0x00041040, 0x00040000,
+       0x00041040, 0x00040000, 0x10041000, 0x00001000,
+       0x00000040, 0x10040040, 0x00001000, 0x00041040,
+       0x10001000, 0x00000040, 0x10000040, 0x10040000,
+       0x10040040, 0x10000000, 0x00040000, 0x10001040,
+       0x00000000, 0x10041040, 0x00040040, 0x10000040,
+       0x10040000, 0x10001000, 0x10001040, 0x00000000,
+       0x10041040, 0x00041000, 0x00041000, 0x00001040,
+       0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/*
+ * PC1: left and right halves bit-swap
+ */
+static const uint32_t LHs[16] =
+{
+       0x00000000, 0x00000001, 0x00000100, 0x00000101,
+       0x00010000, 0x00010001, 0x00010100, 0x00010101,
+       0x01000000, 0x01000001, 0x01000100, 0x01000101,
+       0x01010000, 0x01010001, 0x01010100, 0x01010101
+};
+
+static const uint32_t RHs[16] =
+{
+       0x00000000, 0x01000000, 0x00010000, 0x01010000,
+       0x00000100, 0x01000100, 0x00010100, 0x01010100,
+       0x00000001, 0x01000001, 0x00010001, 0x01010001,
+       0x00000101, 0x01000101, 0x00010101, 0x01010101,
+};
+
+/*
+ * Initial Permutation macro
+ */
+#define DES_IP(X,Y)                                             \
+{                                                               \
+       T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+       T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+       T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+       T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+       Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF;                    \
+       T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T;                   \
+       X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF;                    \
+}
+
+/*
+ * Final Permutation macro
+ */
+#define DES_FP(X,Y)                                             \
+{                                                               \
+       X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF;                    \
+       T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T;                   \
+       Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF;                    \
+       T = ((Y >>  8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T <<  8);   \
+       T = ((Y >>  2) ^ X) & 0x33333333; X ^= T; Y ^= (T <<  2);   \
+       T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16);   \
+       T = ((X >>  4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T <<  4);   \
+}
+
+/*
+ * DES round macro
+ */
+#define DES_ROUND(X,Y)                          \
+{                                               \
+       T = *SK++ ^ X;                              \
+       Y ^= SB8[ (T      ) & 0x3F ] ^              \
+                SB6[ (T >>  8) & 0x3F ] ^              \
+                SB4[ (T >> 16) & 0x3F ] ^              \
+                SB2[ (T >> 24) & 0x3F ];               \
+                                                                                               \
+       T = *SK++ ^ ((X << 28) | (X >> 4));         \
+       Y ^= SB7[ (T      ) & 0x3F ] ^              \
+                SB5[ (T >>  8) & 0x3F ] ^              \
+                SB3[ (T >> 16) & 0x3F ] ^              \
+                SB1[ (T >> 24) & 0x3F ];               \
+}
+
+#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; }
+
+static const unsigned char odd_parity_table[128] = { 1,  2,  4,  7,  8,
+               11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44,
+               47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81,
+               82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112,
+               115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140,
+               143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168,
+               171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196,
+               199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224,
+               227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253,
+               254 };
+
+void des_key_set_parity( unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < DES_KEY_SIZE; i++ )
+               key[i] = odd_parity_table[key[i] / 2];
+}
+
+/*
+ * Check the given key's parity, returns 1 on failure, 0 on SUCCESS
+ */
+int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < DES_KEY_SIZE; i++ )
+               if ( key[i] != odd_parity_table[key[i] / 2] )
+                       return( 1 );
+
+       return( 0 );
+}
+
+/*
+ * Table of weak and semi-weak keys
+ *
+ * Source: http://en.wikipedia.org/wiki/Weak_key
+ *
+ * Weak:
+ * Alternating ones + zeros (0x0101010101010101)
+ * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE)
+ * '0xE0E0E0E0F1F1F1F1'
+ * '0x1F1F1F1F0E0E0E0E'
+ *
+ * Semi-weak:
+ * 0x011F011F010E010E and 0x1F011F010E010E01
+ * 0x01E001E001F101F1 and 0xE001E001F101F101
+ * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01
+ * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E
+ * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E
+ * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1
+ *
+ */
+
+#define WEAK_KEY_COUNT 16
+
+static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] =
+{
+       { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+       { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+       { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E },
+       { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 },
+
+       { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E },
+       { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 },
+       { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 },
+       { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 },
+       { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE },
+       { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 },
+       { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 },
+       { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E },
+       { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE },
+       { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E },
+       { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE },
+       { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 }
+};
+
+int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       for( i = 0; i < WEAK_KEY_COUNT; i++ )
+               if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0)
+                       return( 1 );
+
+       return( 0 );
+}
+
+static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+       uint32_t X, Y, T;
+
+       GET_UINT32_BE( X, key, 0 );
+       GET_UINT32_BE( Y, key, 4 );
+
+       /*
+        * Permuted Choice 1
+        */
+       T =  ((Y >>  4) ^ X) & 0x0F0F0F0F;  X ^= T; Y ^= (T <<  4);
+       T =  ((Y      ) ^ X) & 0x10101010;  X ^= T; Y ^= (T      );
+
+       X =   (LHs[ (X      ) & 0xF] << 3) | (LHs[ (X >>  8) & 0xF ] << 2)
+               | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ]     )
+               | (LHs[ (X >>  5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6)
+               | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4);
+
+       Y =   (RHs[ (Y >>  1) & 0xF] << 3) | (RHs[ (Y >>  9) & 0xF ] << 2)
+               | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ]     )
+               | (RHs[ (Y >>  4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6)
+               | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4);
+
+       X &= 0x0FFFFFFF;
+       Y &= 0x0FFFFFFF;
+
+       /*
+        * calculate subkeys
+        */
+       for( i = 0; i < 16; i++ )
+       {
+               if( i < 2 || i == 8 || i == 15 )
+               {
+                       X = ((X <<  1) | (X >> 27)) & 0x0FFFFFFF;
+                       Y = ((Y <<  1) | (Y >> 27)) & 0x0FFFFFFF;
+               }
+               else
+               {
+                       X = ((X <<  2) | (X >> 26)) & 0x0FFFFFFF;
+                       Y = ((Y <<  2) | (Y >> 26)) & 0x0FFFFFFF;
+               }
+
+               *SK++ =   ((X <<  4) & 0x24000000) | ((X << 28) & 0x10000000)
+                               | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000)
+                               | ((X <<  6) & 0x01000000) | ((X <<  9) & 0x00200000)
+                               | ((X >>  1) & 0x00100000) | ((X << 10) & 0x00040000)
+                               | ((X <<  2) & 0x00020000) | ((X >> 10) & 0x00010000)
+                               | ((Y >> 13) & 0x00002000) | ((Y >>  4) & 0x00001000)
+                               | ((Y <<  6) & 0x00000800) | ((Y >>  1) & 0x00000400)
+                               | ((Y >> 14) & 0x00000200) | ((Y      ) & 0x00000100)
+                               | ((Y >>  5) & 0x00000020) | ((Y >> 10) & 0x00000010)
+                               | ((Y >>  3) & 0x00000008) | ((Y >> 18) & 0x00000004)
+                               | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001);
+
+               *SK++ =   ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000)
+                               | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000)
+                               | ((X >>  2) & 0x02000000) | ((X <<  1) & 0x01000000)
+                               | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000)
+                               | ((X <<  3) & 0x00080000) | ((X >>  6) & 0x00040000)
+                               | ((X << 15) & 0x00020000) | ((X >>  4) & 0x00010000)
+                               | ((Y >>  2) & 0x00002000) | ((Y <<  8) & 0x00001000)
+                               | ((Y >> 14) & 0x00000808) | ((Y >>  9) & 0x00000400)
+                               | ((Y      ) & 0x00000200) | ((Y <<  7) & 0x00000100)
+                               | ((Y >>  7) & 0x00000020) | ((Y >>  3) & 0x00000011)
+                               | ((Y <<  2) & 0x00000004) | ((Y >> 21) & 0x00000002);
+       }
+}
+
+/*
+ * DES key schedule (56-bit, encryption)
+ */
+int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] )
+{
+       des_setkey( ctx->sk, key );
+
+       return( 0 );
+}
+
+/*
+ * DES key schedule (56-bit, decryption)
+ */
+int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] )
+{
+       int i;
+
+       des_setkey( ctx->sk, key );
+
+       for( i = 0; i < 16; i += 2 )
+       {
+               SWAP( ctx->sk[i    ], ctx->sk[30 - i] );
+               SWAP( ctx->sk[i + 1], ctx->sk[31 - i] );
+       }
+
+       return( 0 );
+}
+
+static void des3_set2key( uint32_t esk[96],
+                                                 uint32_t dsk[96],
+                                                 const unsigned char key[DES_KEY_SIZE*2] )
+{
+       int i;
+
+       des_setkey( esk, key );
+       des_setkey( dsk + 32, key + 8 );
+
+       for( i = 0; i < 32; i += 2 )
+       {
+               dsk[i     ] = esk[30 - i];
+               dsk[i +  1] = esk[31 - i];
+
+               esk[i + 32] = dsk[62 - i];
+               esk[i + 33] = dsk[63 - i];
+
+               esk[i + 64] = esk[i    ];
+               esk[i + 65] = esk[i + 1];
+
+               dsk[i + 64] = dsk[i    ];
+               dsk[i + 65] = dsk[i + 1];
+       }
+}
+
+/*
+ * Triple-DES key schedule (112-bit, encryption)
+ */
+int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] )
+{
+       uint32_t sk[96];
+
+       des3_set2key( ctx->sk, sk, key );
+       memset( sk,  0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (112-bit, decryption)
+ */
+int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] )
+{
+       uint32_t sk[96];
+
+       des3_set2key( sk, ctx->sk, key );
+       memset( sk,  0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+static void des3_set3key( uint32_t esk[96],
+                                                 uint32_t dsk[96],
+                                                 const unsigned char key[24] )
+{
+       int i;
+
+       des_setkey( esk, key );
+       des_setkey( dsk + 32, key +  8 );
+       des_setkey( esk + 64, key + 16 );
+
+       for( i = 0; i < 32; i += 2 )
+       {
+               dsk[i     ] = esk[94 - i];
+               dsk[i +  1] = esk[95 - i];
+
+               esk[i + 32] = dsk[62 - i];
+               esk[i + 33] = dsk[63 - i];
+
+               dsk[i + 64] = esk[30 - i];
+               dsk[i + 65] = esk[31 - i];
+       }
+}
+
+/*
+ * Triple-DES key schedule (168-bit, encryption)
+ */
+int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] )
+{
+       uint32_t sk[96];
+
+       des3_set3key( ctx->sk, sk, key );
+       memset( sk, 0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * Triple-DES key schedule (168-bit, decryption)
+ */
+int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] )
+{
+       uint32_t sk[96];
+
+       des3_set3key( sk, ctx->sk, key );
+       memset( sk, 0, sizeof( sk ) );
+
+       return( 0 );
+}
+
+/*
+ * DES-ECB block encryption/decryption
+ */
+int des_crypt_ecb( des_context *ctx,
+                                       const unsigned char input[8],
+                                       unsigned char output[8] )
+{
+       int i;
+       uint32_t X, Y, T, *SK;
+
+       SK = ctx->sk;
+
+       GET_UINT32_BE( X, input, 0 );
+       GET_UINT32_BE( Y, input, 4 );
+
+       DES_IP( X, Y );
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       DES_FP( Y, X );
+
+       PUT_UINT32_BE( Y, output, 0 );
+       PUT_UINT32_BE( X, output, 4 );
+
+       return( 0 );
+}
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/*
+ * DES-CBC buffer encryption/decryption
+ */
+int des_crypt_cbc( des_context *ctx,
+                                       int mode,
+                                       size_t length,
+                                       unsigned char iv[8],
+                                       const unsigned char *input,
+                                       unsigned char *output )
+{
+       int i;
+       unsigned char temp[8];
+
+       if( length % 8 )
+               return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH );
+
+       if( mode == DES_ENCRYPT )
+       {
+               while( length > 0 )
+               {
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+                       des_crypt_ecb( ctx, output, output );
+                       memcpy( iv, output, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+       else /* DES_DECRYPT */
+       {
+               while( length > 0 )
+               {
+                       memcpy( temp, input, 8 );
+                       des_crypt_ecb( ctx, input, output );
+
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+                       memcpy( iv, temp, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+
+       return( 0 );
+}
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/*
+ * 3DES-ECB block encryption/decryption
+ */
+int des3_crypt_ecb( des3_context *ctx,
+                                        const unsigned char input[8],
+                                        unsigned char output[8] )
+{
+       int i;
+       uint32_t X, Y, T, *SK;
+
+       SK = ctx->sk;
+
+       GET_UINT32_BE( X, input, 0 );
+       GET_UINT32_BE( Y, input, 4 );
+
+       DES_IP( X, Y );
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( X, Y );
+               DES_ROUND( Y, X );
+       }
+
+       for( i = 0; i < 8; i++ )
+       {
+               DES_ROUND( Y, X );
+               DES_ROUND( X, Y );
+       }
+
+       DES_FP( Y, X );
+
+       PUT_UINT32_BE( Y, output, 0 );
+       PUT_UINT32_BE( X, output, 4 );
+
+       return( 0 );
+}
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/*
+ * 3DES-CBC buffer encryption/decryption
+ */
+int des3_crypt_cbc( des3_context *ctx,
+                                        int mode,
+                                        size_t length,
+                                        unsigned char iv[8],
+                                        const unsigned char *input,
+                                        unsigned char *output )
+{
+       int i;
+       unsigned char temp[8];
+
+       if( length % 8 )
+               return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH );
+
+       if( mode == DES_ENCRYPT )
+       {
+               while( length > 0 )
+               {
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( input[i] ^ iv[i] );
+
+                       des3_crypt_ecb( ctx, output, output );
+                       memcpy( iv, output, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+       else /* DES_DECRYPT */
+       {
+               while( length > 0 )
+               {
+                       memcpy( temp, input, 8 );
+                       des3_crypt_ecb( ctx, input, output );
+
+                       for( i = 0; i < 8; i++ )
+                               output[i] = (unsigned char)( output[i] ^ iv[i] );
+
+                       memcpy( iv, temp, 8 );
+
+                       input  += 8;
+                       output += 8;
+                       length -= 8;
+               }
+       }
+
+       return( 0 );
+}
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+#endif /* !POLARSSL_DES_ALT */
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include <stdio.h>
+
+/*
+ * DES and 3DES test vectors from:
+ *
+ * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip
+ */
+static const unsigned char des3_test_keys[24] =
+{
+       0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+       0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01,
+       0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23
+};
+
+static const unsigned char des3_test_buf[8] =
+{
+       0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74
+};
+
+static const unsigned char des3_test_ecb_dec[3][8] =
+{
+       { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D },
+       { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB },
+       { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A }
+};
+
+static const unsigned char des3_test_ecb_enc[3][8] =
+{
+       { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B },
+       { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 },
+       { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 }
+};
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+static const unsigned char des3_test_iv[8] =
+{
+       0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF,
+};
+
+static const unsigned char des3_test_cbc_dec[3][8] =
+{
+       { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 },
+       { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 },
+       { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C }
+};
+
+static const unsigned char des3_test_cbc_enc[3][8] =
+{
+       { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 },
+       { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D },
+       { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 }
+};
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/*
+ * Checkup routine
+ */
+int des_self_test( int verbose )
+{
+       int i, j, u, v;
+       des_context ctx;
+       des3_context ctx3;
+       unsigned char key[24];
+       unsigned char buf[8];
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+       unsigned char prv[8];
+       unsigned char iv[8];
+#endif
+
+       memset( key, 0, 24 );
+
+       /*
+        * ECB mode
+        */
+       for( i = 0; i < 6; i++ )
+       {
+               u = i >> 1;
+               v = i  & 1;
+
+               if( verbose != 0 )
+                       polarssl_printf( "  DES%c-ECB-%3d (%s): ",
+                                                        ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                                                        ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+               memcpy( buf, des3_test_buf, 8 );
+
+               switch( i )
+               {
+               case 0:
+                       des_setkey_dec( &ctx, des3_test_keys );
+                       break;
+
+               case 1:
+                       des_setkey_enc( &ctx, des3_test_keys );
+                       break;
+
+               case 2:
+                       des3_set2key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 3:
+                       des3_set2key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               case 4:
+                       des3_set3key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 5:
+                       des3_set3key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               default:
+                       return( 1 );
+               }
+
+               for( j = 0; j < 10000; j++ )
+               {
+                       if( u == 0 )
+                               des_crypt_ecb( &ctx, buf, buf );
+                       else
+                               des3_crypt_ecb( &ctx3, buf, buf );
+               }
+
+               if( ( v == DES_DECRYPT &&
+                               memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) ||
+                       ( v != DES_DECRYPT &&
+                               memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) )
+               {
+                       if( verbose != 0 )
+                               polarssl_printf( "failed\n" );
+
+                       return( 1 );
+               }
+
+               if( verbose != 0 )
+                       polarssl_printf( "passed\n" );
+       }
+
+       if( verbose != 0 )
+               polarssl_printf( "\n" );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+       /*
+        * CBC mode
+        */
+       for( i = 0; i < 6; i++ )
+       {
+               u = i >> 1;
+               v = i  & 1;
+
+               if( verbose != 0 )
+                       polarssl_printf( "  DES%c-CBC-%3d (%s): ",
+                                                        ( u == 0 ) ? ' ' : '3', 56 + u * 56,
+                                                        ( v == DES_DECRYPT ) ? "dec" : "enc" );
+
+               memcpy( iv,  des3_test_iv,  8 );
+               memcpy( prv, des3_test_iv,  8 );
+               memcpy( buf, des3_test_buf, 8 );
+
+               switch( i )
+               {
+               case 0:
+                       des_setkey_dec( &ctx, des3_test_keys );
+                       break;
+
+               case 1:
+                       des_setkey_enc( &ctx, des3_test_keys );
+                       break;
+
+               case 2:
+                       des3_set2key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 3:
+                       des3_set2key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               case 4:
+                       des3_set3key_dec( &ctx3, des3_test_keys );
+                       break;
+
+               case 5:
+                       des3_set3key_enc( &ctx3, des3_test_keys );
+                       break;
+
+               default:
+                       return( 1 );
+               }
+
+               if( v == DES_DECRYPT )
+               {
+                       for( j = 0; j < 10000; j++ )
+                       {
+                               if( u == 0 )
+                                       des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                               else
+                                       des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+                       }
+               }
+               else
+               {
+                       for( j = 0; j < 10000; j++ )
+                       {
+                               unsigned char tmp[8];
+
+                               if( u == 0 )
+                                       des_crypt_cbc( &ctx, v, 8, iv, buf, buf );
+                               else
+                                       des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf );
+
+                               memcpy( tmp, prv, 8 );
+                               memcpy( prv, buf, 8 );
+                               memcpy( buf, tmp, 8 );
+                       }
+
+                       memcpy( buf, prv, 8 );
+               }
+
+               if( ( v == DES_DECRYPT &&
+                               memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) ||
+                       ( v != DES_DECRYPT &&
+                               memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) )
+               {
+                       if( verbose != 0 )
+                               polarssl_printf( "failed\n" );
+
+                       return( 1 );
+               }
+
+               if( verbose != 0 )
+                       polarssl_printf( "passed\n" );
+       }
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+       if( verbose != 0 )
+               polarssl_printf( "\n" );
+
+       return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/client/loclass/des.h b/client/loclass/des.h
new file mode 100644 (file)
index 0000000..907d56b
--- /dev/null
@@ -0,0 +1,256 @@
+/**
+ * \file des.h
+ *
+ * \brief DES block cipher
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  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 2 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, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_DES_H
+#define POLARSSL_DES_H
+
+//#include "config.h"
+
+#include <string.h>
+
+#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32)
+#include <basetsd.h>
+typedef UINT32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#define DES_ENCRYPT     1
+#define DES_DECRYPT     0
+
+#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH              -0x0032  /**< The data input has an invalid length. */
+
+#define DES_KEY_SIZE    8
+
+#if !defined(POLARSSL_DES_ALT)
+// Regular implementation
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          DES context structure
+ */
+typedef struct
+{
+       int mode;                   /*!<  encrypt/decrypt   */
+       uint32_t sk[32];            /*!<  DES subkeys       */
+}
+des_context;
+
+/**
+ * \brief          Triple-DES context structure
+ */
+typedef struct
+{
+       int mode;                   /*!<  encrypt/decrypt   */
+       uint32_t sk[96];            /*!<  3DES subkeys      */
+}
+des3_context;
+
+/**
+ * \brief          Set key parity on the given key to odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ */
+void des_key_set_parity( unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key parity on the given key is odd.
+ *
+ *                 DES keys are 56 bits long, but each byte is padded with
+ *                 a parity bit to allow verification.
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 is parity was ok, 1 if parity was not correct.
+ */
+int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Check that key is not a weak or semi-weak DES key
+ *
+ * \param key      8-byte secret key
+ *
+ * \return         0 if no weak key was found, 1 if a weak key was identified.
+ */
+int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, encryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          DES key schedule (56-bit, decryption)
+ *
+ * \param ctx      DES context to be initialized
+ * \param key      8-byte secret key
+ *
+ * \return         0
+ */
+int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (112-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      16-byte secret key
+ *
+ * \return         0
+ */
+int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, encryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          Triple-DES key schedule (168-bit, decryption)
+ *
+ * \param ctx      3DES context to be initialized
+ * \param key      24-byte secret key
+ *
+ * \return         0
+ */
+int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] );
+
+/**
+ * \brief          DES-ECB block encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int des_crypt_ecb( des_context *ctx,
+                                       const unsigned char input[8],
+                                       unsigned char output[8] );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/**
+ * \brief          DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ */
+int des_crypt_cbc( des_context *ctx,
+                                       int mode,
+                                       size_t length,
+                                       unsigned char iv[8],
+                                       const unsigned char *input,
+                                       unsigned char *output );
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+/**
+ * \brief          3DES-ECB block encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param input    64-bit input block
+ * \param output   64-bit output block
+ *
+ * \return         0 if successful
+ */
+int des3_crypt_ecb( des3_context *ctx,
+                                        const unsigned char input[8],
+                                        unsigned char output[8] );
+
+#if defined(POLARSSL_CIPHER_MODE_CBC)
+/**
+ * \brief          3DES-CBC buffer encryption/decryption
+ *
+ * \param ctx      3DES context
+ * \param mode     DES_ENCRYPT or DES_DECRYPT
+ * \param length   length of the input data
+ * \param iv       initialization vector (updated after use)
+ * \param input    buffer holding the input data
+ * \param output   buffer holding the output data
+ *
+ * \return         0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH
+ */
+int des3_crypt_cbc( des3_context *ctx,
+                                        int mode,
+                                        size_t length,
+                                        unsigned char iv[8],
+                                        const unsigned char *input,
+                                        unsigned char *output );
+#endif /* POLARSSL_CIPHER_MODE_CBC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* POLARSSL_DES_ALT */
+#include "des_alt.h"
+#endif /* POLARSSL_DES_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief          Checkup routine
+ *
+ * \return         0 if successful, or 1 if the test failed
+ */
+int des_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* des.h */
diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c
new file mode 100644 (file)
index 0000000..18571b0
--- /dev/null
@@ -0,0 +1,469 @@
+/*****************************************************************************
+ * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This file 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 IClassCipher.  If not, see <http://www.gnu.org/licenses/>.
+ ****************************************************************************/
+/**
+From "Dismantling iclass":
+       This section describes in detail the built-in key diversification algorithm of iClass.
+       Besides the obvious purpose of deriving a card key from a master key, this
+       algorithm intends to circumvent weaknesses in the cipher by preventing the
+       usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass
+       reader first encrypts the card identity id with the master key K, using single
+       DES. The resulting ciphertext is then input to a function called hash0 which
+       outputs the diversified key k.
+
+       k = hash0(DES enc (id, K))
+
+       Here the DES encryption of id with master key K outputs a cryptogram c
+       of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8
+       which is used as input to the hash0 function. This function introduces some
+       obfuscation by performing a number of permutations, complement and modulo
+       operations, see Figure 2.5. Besides that, it checks for and removes patterns like
+       similar key bytes, which could produce a strong bias in the cipher. Finally, the
+       output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 .
+
+
+**/
+
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "cipherutils.h"
+#include "cipher.h"
+#include "../util.h"
+#include <stdio.h>
+#include "des.h"
+#include <inttypes.h>
+
+uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78};
+
+static des_context ctx_enc = {DES_ENCRYPT,{0}};
+static des_context ctx_dec = {DES_DECRYPT,{0}};
+
+static bool debug_print = false;
+
+/**
+ * @brief The key diversification algorithm uses 6-bit bytes.
+ * This implementation uses 64 bit uint to pack seven of them into one
+ * variable. When they are there, they are placed as follows:
+ * XXXX XXXX N0 .... N7, occupying the lsat 48 bits.
+ *
+ * This function picks out one from such a collection
+ * @param all
+ * @param n bitnumber
+ * @return
+ */
+uint8_t getSixBitByte(uint64_t c, int n)
+{
+       return (c >> (42-6*n)) & 0x3F;
+       //return (c >> n*6) & 0x3f;
+}
+
+/**
+ * @brief Puts back a six-bit 'byte' into a uint64_t.
+ * @param c buffer
+ * @param z the value to place there
+ * @param n bitnumber.
+ */
+void pushbackSixBitByte(uint64_t *c, uint8_t z, int n)
+{
+       //0x XXXX YYYY ZZZZ ZZZZ ZZZZ
+       //             ^z0         ^z7
+       //z0:  1111 1100 0000 0000
+
+       uint64_t masked = z & 0x3F;
+       uint64_t eraser = 0x3F;
+       masked <<= 42-6*n;
+       eraser <<= 42-6*n;
+
+       //masked <<= 6*n;
+       //eraser <<= 6*n;
+
+       eraser = ~eraser;
+       (*c) &= eraser;
+       (*c) |= masked;
+
+}
+
+uint64_t swapZvalues(uint64_t c)
+{
+       uint64_t newz = 0;
+       pushbackSixBitByte(&newz, getSixBitByte(c,0),7);
+       pushbackSixBitByte(&newz, getSixBitByte(c,1),6);
+       pushbackSixBitByte(&newz, getSixBitByte(c,2),5);
+       pushbackSixBitByte(&newz, getSixBitByte(c,3),4);
+       pushbackSixBitByte(&newz, getSixBitByte(c,4),3);
+       pushbackSixBitByte(&newz, getSixBitByte(c,5),2);
+       pushbackSixBitByte(&newz, getSixBitByte(c,6),1);
+       pushbackSixBitByte(&newz, getSixBitByte(c,7),0);
+       newz |= (c & 0xFFFF000000000000);
+       return newz;
+}
+
+/**
+* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
+*/
+uint64_t ck(int i, int j, uint64_t z)
+{
+
+//     printf("ck( i=%d, j=%d), zi=[%d],zj=[%d] \n",i,j,getSixBitByte(z,i),getSixBitByte(z,j) );
+
+       if(i == 1 && j == -1)
+       {
+               // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
+               return z;
+
+       }else if( j == -1)
+       {
+               // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
+               return ck(i-1,i-2, z);
+       }
+
+       if(getSixBitByte(z,i) == getSixBitByte(z,j))
+       {
+               // TODO, I dont know what they mean here in the paper
+               //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
+               uint64_t newz = 0;
+               int c;
+               //printf("z[i]=z[i] (0x%02x), i=%d, j=%d\n",getSixBitByte(z,i),i,j );
+               for(c = 0; c < 4 ;c++)
+               {
+                       uint8_t val = getSixBitByte(z,c);
+                       if(c == i)
+                       {
+                               //printf("oops\n");
+                               pushbackSixBitByte(&newz, j, c);
+                       }else
+                       {
+                               pushbackSixBitByte(&newz, val, c);
+                       }
+               }
+               return ck(i,j-1,newz);
+       }else
+       {
+               return ck(i,j-1,z);
+       }
+
+}
+/**
+
+       Definition 8.
+       Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as
+       check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
+
+       where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as
+
+               ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
+               ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
+               ck(i, j, z [0] . . . z [3] ) =
+               ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ),  if z [i] = z [j] ;
+               ck(i, j − 1, z [0] . . . z [3] ), otherwise
+
+       otherwise.
+**/
+
+uint64_t check(uint64_t z)
+{
+       //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
+
+       // ck(3, 2, z [0] . . . z [3] )
+       uint64_t ck1 = ck(3,2, z );
+
+       // ck(3, 2, z [4] . . . z [7] )
+       uint64_t ck2 = ck(3,2, z << 24);
+       ck1 &= 0x00000000FFFFFF000000;
+       ck2 &= 0x00000000FFFFFF000000;
+
+       return ck1 | ck2 >> 24;
+
+}
+
+void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
+{
+       if(bitsLeft(p_in) == 0)
+       {
+               return;
+       }
+       bool pn = tailBit(p_in);
+       if( pn ) // pn = 1
+       {
+               uint8_t zl = getSixBitByte(z,l);
+               //printf("permute pushing, zl=0x%02x, zl+1=0x%02x\n", zl, zl+1);
+               push6bits(out, zl+1);
+               permute(p_in, z, l+1,r, out);
+       }else // otherwise
+       {
+               uint8_t zr = getSixBitByte(z,r);
+               //printf("permute pushing, zr=0x%02x\n", zr);
+               push6bits(out, zr);
+               permute(p_in,z,l,r+1,out);
+       }
+}
+void testPermute()
+{
+
+       uint64_t x = 0;
+       pushbackSixBitByte(&x,0x00,0);
+       pushbackSixBitByte(&x,0x01,1);
+       pushbackSixBitByte(&x,0x02,2);
+       pushbackSixBitByte(&x,0x03,3);
+       pushbackSixBitByte(&x,0x04,4);
+       pushbackSixBitByte(&x,0x05,5);
+       pushbackSixBitByte(&x,0x06,6);
+       pushbackSixBitByte(&x,0x07,7);
+
+       uint8_t mres[8] = { getSixBitByte(x, 0),
+                                               getSixBitByte(x, 1),
+                                               getSixBitByte(x, 2),
+                                               getSixBitByte(x, 3),
+                                               getSixBitByte(x, 4),
+                                               getSixBitByte(x, 5),
+                                               getSixBitByte(x, 6),
+                                               getSixBitByte(x, 7)};
+       printarr("input_perm", mres,8);
+
+       uint8_t p = ~pi[0];
+       BitstreamIn p_in = { &p, 8,0 };
+       uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
+       BitstreamOut out = {outbuffer,0,0};
+
+       permute(&p_in, x,0,4, &out);
+
+       uint64_t permuted = bytes_to_num(outbuffer,8);
+       //printf("zTilde 0x%"PRIX64"\n", zTilde);
+       permuted >>= 16;
+
+       uint8_t res[8] = { getSixBitByte(permuted, 0),
+                                               getSixBitByte(permuted, 1),
+                                               getSixBitByte(permuted, 2),
+                                               getSixBitByte(permuted, 3),
+                                               getSixBitByte(permuted, 4),
+                                               getSixBitByte(permuted, 5),
+                                               getSixBitByte(permuted, 6),
+                                               getSixBitByte(permuted, 7)};
+       printarr("permuted", res, 8);
+}
+void printbegin()
+{
+       if(! debug_print)
+               return;
+
+       printf("          | x| y|z0|z1|z2|z3|z4|z5|z6|z7|\n");
+}
+
+void printState(char* desc, int x,int y, uint64_t c)
+{
+       if(! debug_print)
+               return;
+
+       printf("%s : ", desc);
+       //uint8_t x =   (c & 0xFF00000000000000 ) >> 56;
+       //uint8_t y =   (c & 0x00FF000000000000 ) >> 48;
+       printf("  %02x %02x", x,y);
+       int i ;
+       for(i =0 ; i < 8 ; i++)
+       {
+               printf(" %02x", getSixBitByte(c,i));
+       }
+       printf("\n");
+}
+
+/**
+ * @brief
+ *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
+ *     hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
+ * z'[i] = (z[i] mod (63-i)) + i       i =  0...3
+ * z'[i+4] = (z[i+4] mod (64-i)) + i   i =  0...3
+ * ẑ = check(z');
+ * @param c
+ * @param k this is where the diversified key is put (should be 8 bytes)
+ * @return
+ */
+void hash0(uint64_t c, uint8_t *k)
+{
+       printbegin();
+       //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
+       // x = 8 bits
+       // y = 8 bits
+       // z0-z7 6 bits each : 48 bits
+       uint8_t x =     (c & 0xFF00000000000000 ) >> 56;
+       uint8_t y =     (c & 0x00FF000000000000 ) >> 48;
+       printState("origin",x,y,c);
+       int n;
+       uint8_t zn, zn4, _zn, _zn4;
+       uint64_t zP = 0;
+
+       for(n = 0;  n < 4 ; n++)
+       {
+               zn = getSixBitByte(c,n);
+               zn4 = getSixBitByte(c,n+4);
+
+               _zn = (zn % (63-n)) + n;
+               _zn4 = (zn4 % (64-n)) + n;
+
+               pushbackSixBitByte(&zP, _zn,n);
+               pushbackSixBitByte(&zP, _zn4,n+4);
+
+       }
+       printState("x|y|z'",x,y,zP);
+
+       uint64_t zCaret = check(zP);
+       printState("x|y|z^",x,y,zP);
+
+
+       uint8_t p = pi[x % 35];
+
+       if(x & 1) //Check if x7 is 1
+       {
+               p = ~p;
+       }
+    printState("p|y|z^",p,y,zP);
+       //if(debug_print) printf("p:%02x\n", p);
+
+       BitstreamIn p_in = { &p, 8,0 };
+       uint8_t outbuffer[] = {0,0,0,0,0,0,0,0};
+       BitstreamOut out = {outbuffer,0,0};
+       permute(&p_in,zCaret,0,4,&out);//returns 48 bits? or 6 8-bytes
+
+       //Out is now a buffer containing six-bit bytes, should be 48 bits
+       // if all went well
+       //printf("Permute output is %d num bits (48?)\n", out.numbits);
+       //Shift z-values down onto the lower segment
+
+       uint64_t zTilde = bytes_to_num(outbuffer,8);
+
+       //printf("zTilde 0x%"PRIX64"\n", zTilde);
+       zTilde >>= 16;
+       //printf("z~ 0x%"PRIX64"\n", zTilde);
+       printState("p|y|z~", p,y,zTilde);
+
+       int i;
+       int zerocounter =0 ;
+       for(i =0 ; i < 8  ; i++)
+       {
+
+               // the key on index i is first a bit from y
+               // then six bits from z,
+               // then a bit from p
+
+               // Init with zeroes
+               k[i] = 0;
+               // First, place yi leftmost in k
+               //k[i] |= (y  << i) & 0x80 ;
+
+               // First, place y(7-i) leftmost in k
+               k[i] |= (y  << (7-i)) & 0x80 ;
+
+               //printf("y%d = %d\n",i,(y  << i) & 0x80);
+
+               uint8_t zTilde_i = getSixBitByte(zTilde, i);
+               //printf("zTilde_%d 0x%02x (should be <= 0x3F)\n",i, zTilde_i);
+               // zTildeI is now on the form 00XXXXXX
+               // with one leftshift, it'll be
+               // 0XXXXXX0
+               // So after leftshift, we can OR it into k
+               // However, when doing complement, we need to
+               // again MASK 0XXXXXX0 (0x7E)
+               zTilde_i <<= 1;
+
+               //Finally, add bit from p or p-mod
+               //Shift bit i into rightmost location (mask only after complement)
+               uint8_t p_i = p >> i & 0x1;
+
+               if( k[i] )// yi = 1
+               {
+                       //printf("k[%d] +1\n", i);
+                       k[i] |= ~zTilde_i & 0x7E;
+                       k[i] |= p_i & 1;
+                       k[i] += 1;
+
+               }else // otherwise
+               {
+                       k[i] |= zTilde_i & 0x7E;
+                       k[i] |= (~p_i) & 1;
+               }
+               if((k[i]  & 1 )== 0)
+               {
+                       zerocounter ++;
+               }
+       }
+       //printf("zerocounter=%d (should be 4)\n",zerocounter);
+       //printf("permute fin, y:0x%02x, x: 0x%02x\n", y, x);
+
+       //return k;
+}
+
+void reorder(uint8_t arr[8])
+{
+       uint8_t tmp[4] = {arr[3],arr[2],arr[1], arr[0]};
+       arr[0] = arr[7];
+       arr[1] = arr[6];
+       arr[2] = arr[5];
+       arr[3] = arr[4];
+       arr[4] = tmp[0];//arr[3];
+       arr[5] = tmp[1];//arr[2];
+       arr[6] = tmp[2];//arr[3];
+       arr[7] = tmp[3];//arr[1]
+}
+
+//extern void printarr(char * name, uint8_t* arr, int len);
+
+bool des_getParityBitFromKey(uint8_t key)
+{//The top 7 bits is used
+       bool parity = ((key & 0x80) >> 7)
+                       ^ ((key & 0x40) >> 6) ^ ((key & 0x20) >> 5)
+                       ^ ((key & 0x10) >> 4) ^ ((key & 0x08) >> 3)
+                       ^ ((key & 0x04) >> 2) ^ ((key & 0x02) >> 1);
+       return !parity;
+}
+void des_checkParity(uint8_t* key)
+{
+       int i;
+       int fails =0;
+       for(i =0 ; i < 8 ; i++)
+       {
+               bool parity = des_getParityBitFromKey(key[i]);
+               if(parity != (key[i] & 0x1))
+               {
+                       fails++;
+                       printf("parity1 fail, byte %d [%02x] was %d, should be %d\n",i,key[i],(key[i] & 0x1),parity);
+               }
+       }
+       if(fails)
+       {
+               printf("parity fails: %d\n", fails);
+       }else
+       {
+               printf("Key syntax is with parity bits inside each byte\n");
+       }
+}
+
+void printarr2(char * name, uint8_t* arr, int len)
+{
+       int i ;
+       printf("%s :", name);
+       for(i =0 ;  i< len ; i++)
+       {
+               printf("%02x",*(arr+i));
+       }
+       printf("\n");
+}
diff --git a/client/loclass/ikeys.h b/client/loclass/ikeys.h
new file mode 100644 (file)
index 0000000..0b943d6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef IKEYS_H
+#define IKEYS_H
+int testKeyDiversification();
+int doKeyTests();
+void hash0(uint64_t c, uint8_t *k);
+void pushbackSixBitByte(uint64_t *c, uint8_t z, int n);
+uint8_t getSixBitByte(uint64_t c, int n);
+#endif // IKEYS_H
Impressum, Datenschutz