/*****************************************************************************
- * This file is part of iClassCipher. It is a reconstructon of the cipher engine
+ * WARNING
+ *
+ * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
+ *
+ * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
+ * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
+ * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
+ *
+ * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
+ *
+ *****************************************************************************
+ *
+ * This file is part of loclass. 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".
*
- * This is a reference implementation of iclass key diversification. I'm sure it can be
- * optimized heavily. It is written for ease of understanding and correctness, please take it
- * and tweak it and make a super fast version instead, using this for testing and verification.
-
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* 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/>.
+ * along with loclass. 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
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>
* @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.
+ * XXXX XXXX N0 .... N7, occupying the last 48 bits.
*
* This function picks out one from such a collection
* @param all
*/
uint64_t ck(int i, int j, uint64_t z)
{
-
- if(i == 1 && j == -1)
- {
+ if (i == 1 && j == -1) {
// ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
return z;
-
- }else if( j == -1)
- {
+ } 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))
+ if (getSixBitByte(z,i) == getSixBitByte(z,j))
{
-
//ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
uint64_t newz = 0;
int c;
- for(c = 0; c < 4 ;c++)
- {
+ for(c = 0; c < 4; c++) {
uint8_t val = getSixBitByte(z,c);
- if(c == i)
- {
+ if (c == i)
pushbackSixBitByte(&newz, j, c);
- }else
- {
+ else
pushbackSixBitByte(&newz, val, c);
- }
}
return ck(i,j-1,newz);
- }else
- {
+ } else {
return ck(i,j-1,z);
}
}
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
{
permute(p_in,z,l,r+1,out);
}
}
-void printbegin()
-{
- if(debug_print <2)
- return ;
+void printbegin() {
+ if (debug_print < 2)
+ return;
prnlog(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
}
void printState(char* desc, uint64_t c)
{
if(debug_print < 2)
- return ;
+ 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++)
- {
+ int i;
+ for(i = 0; i < 8; i++)
printf(" %02x", getSixBitByte(c,i));
- }
printf("\n");
}
_zn = (zn % (63-n)) + n;
_zn4 = (zn4 % (64-n)) + n;
-
pushbackSixBitByte(&zP, _zn,n);
pushbackSixBitByte(&zP, _zn4,n+4);
-
}
+
printState("0|0|z'",zP);
uint64_t zCaret = check(zP);
printState("0|0|z^",zP);
-
uint8_t p = pi[x % 35];
if(x & 1) //Check if x7 is 1
- {
p = ~p;
- }
if(debug_print >= 2) prnlog("p:%02x", p);
int i;
int zerocounter =0 ;
- for(i =0 ; i < 8 ; i++)
+ 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
k[i] |= zTilde_i & 0x7E;
k[i] |= (~p_i) & 1;
}
- if((k[i] & 1 )== 0)
+ if ((k[i] & 1 )== 0)
{
- zerocounter ++;
+ zerocounter++;
}
}
}
*/
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
{
-
// Prepare the DES key
des_setkey_enc( &ctx_enc, key);
//Calculate HASH0(DES))
uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8);
- //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
+ //uint64_t crypted_csn_swapped = swapZvalues(crypt_csn);
hash0(crypt_csn,div_key);
}
-
-
-
-
void testPermute()
{
-
uint64_t x = 0;
pushbackSixBitByte(&x,0x00,0);
pushbackSixBitByte(&x,0x01,1);
uint8_t div_key[8];
} Testcase;
-
int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
{
uint8_t des_encrypted_csn[8] = {0};
printarr("hash0 ", div_key, 8);
printarr("Expected", testcase.div_key, 8);
retval = 1;
-
}
return retval;
}
return !parity;
}
-
-void des_checkParity(uint8_t* key)
-{
+void des_checkParity(uint8_t* key) {
int i;
- int fails =0;
- for(i =0 ; i < 8 ; i++)
- {
+ int fails = 0;
+ for(i = 0; i < 8; i++) {
bool parity = des_getParityBitFromKey(key[i]);
- if(parity != (key[i] & 0x1))
- {
+ if (parity != (key[i] & 0x1)) {
fails++;
- prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d",i,key[i],(key[i] & 0x1),parity);
+ prnlog("[+] parity1 fail, byte %d [%02x] was %d, should be %d", i, key[i], (key[i] & 0x1), parity);
}
}
if(fails)
- {
prnlog("[+] parity fails: %d", fails);
- }else
- {
+ else
prnlog("[+] Key syntax is with parity bits inside each byte");
- }
}
Testcase testcases[] ={
{{0},{0},{0}}
};
-
-int testKeyDiversificationWithMasterkeyTestcases()
-{
-
+int testKeyDiversificationWithMasterkeyTestcases() {
int error = 0;
int i;
-
uint8_t empty[8]={0};
+
prnlog("[+} Testing encryption/decryption");
- for (i = 0; memcmp(testcases+i,empty,8) ; i++) {
- error += testDES(testcases[i],ctx_enc, ctx_dec);
- }
- if(error)
- {
+ for (i = 0; memcmp(testcases+i, empty, 8); i++)
+ error += testDES(testcases[i], ctx_enc, ctx_dec);
+
+ if (error)
prnlog("[+] %d errors occurred (%d testcases)", error, i);
- }else
- {
+ else
prnlog("[+] Hashing seems to work (%d testcases)", i);
- }
return error;
}
-
-void print64bits(char*name, uint64_t val)
-{
+void print64bits(char*name, uint64_t val) {
printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
}
uint64_t resultbyte = x_bytes_to_num(result,8 );
if(debug_print) print64bits(" hash0 " , resultbyte );
- if(resultbyte != expected )
- {
-
+ if(resultbyte != expected ) {
if(debug_print) {
prnlog("\n[+] FAIL!");
print64bits(" expected " , expected );
}
retval = 1;
-
- }else
- {
- if(debug_print) prnlog(" [OK]");
+ } else {
+ if (debug_print) prnlog(" [OK]");
}
return retval;
}
-int testDES2(uint64_t csn, uint64_t expected)
-{
+int testDES2(uint64_t csn, uint64_t expected) {
uint8_t result[8] = {0};
uint8_t input[8] = {0};
print64bits(" {csn} ", crypt_csn );
print64bits(" expected ", expected );
- if( expected == crypt_csn )
- {
+ if( expected == crypt_csn ) {
prnlog("[+] OK");
return 0;
- }else
- {
+ } else {
return 1;
}
}
* @brief doTestsWithKnownInputs
* @return
*/
-int doTestsWithKnownInputs()
-{
-
+int doTestsWithKnownInputs() {
// KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977
int errors = 0;
prnlog("[+] Testing DES encryption");
-// uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
- prnlog("[+] Testing foo");
uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
des_setkey_enc( &ctx_enc, key);
errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
- if(errors)
- {
+ if (errors)
prnlog("[+] %d errors occurred (9 testcases)", errors);
- }else
- {
+ else
prnlog("[+] Hashing seems to work (9 testcases)" );
- }
return errors;
}
-int readKeyFile(uint8_t key[8])
-{
-
- FILE *f;
+int readKeyFile(uint8_t key[8]) {
+ int retval = 1;
+ FILE *f = fopen("iclass_key.bin", "rb");
+ if (!f)
+ return 0;
+
+ size_t bytes_read = fread(key, sizeof(uint8_t), 8, f);
+ if ( bytes_read == 1)
+ retval = 0;
- f = fopen("iclass_key.bin", "rb");
if (f)
- {
- if(fread(key, sizeof(key), 1, f) == 1) return 0;
- }
- return 1;
-
+ fclose(f);
+ return retval;
}
prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
uint8_t key[8] = {0};
- if(readKeyFile(key))
- {
+ if (readKeyFile(key)) {
prnlog("[+] Master key not present, will not be able to do all testcases");
- }else
- {
+ } else {
//Test if it's the right key...
uint8_t i;
uint8_t j = 0;
- for(i =0 ; i < sizeof(key) ; i++)
+ for (i = 0; i < sizeof(key); i++)
j += key[i];
-
- if(j != 185)
- {
+
+ if (j != 185) {
prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
- }else
- {
+ } else {
prnlog("[+] Key present");
-
prnlog("[+] Checking key parity...");
des_checkParity(key);
des_setkey_enc( &ctx_enc, key);
BitstreamOut out = { output, 0,0};
BitstreamIn in = {key, 0,0};
unsigned int bbyte, bbit;
- for(bbit =0 ; bbit < 56 ; bbit++)
- {
-
- if( bbit > 0 && bbit % 7 == 0)
- {
+ for(bbit =0 ; bbit < 56 ; bbit++) {
+ if( bbit > 0 && bbit % 7 == 0) {
pushBit(&out,!parity);
parity = 0;
}
bool bit = headBit(&in);
pushBit(&out,bit );
parity ^= bit;
-
}
pushBit(&out, !parity);
-
if( des_key_check_key_parity(output))
- {
printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
- }
-
}
-
*/