]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - client/loclass/ikeys.c
CHG: the mifare Auth command can make use of a random nonce aswell.
[proxmark3-svn] / client / loclass / ikeys.c
index 5240cba1068f87d9b58f5a3171425da19f20bef2..a870f86d83b6f0256454c021d7f634e44e6cb23c 100644 (file)
@@ -1,15 +1,23 @@
 /*****************************************************************************
 /*****************************************************************************
- * 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".
  *
  * 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
  * 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
  * 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
 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
@@ -46,10 +56,7 @@ From "Dismantling iclass":
        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 .
 
        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 <stdint.h>
 #include <stdbool.h>
 #include <string.h>
@@ -70,7 +77,7 @@ static int debug_print = 0;
  * @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:
  * @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
  *
  * This function picks out one from such a collection
  * @param all
@@ -134,38 +141,28 @@ uint64_t swapZvalues(uint64_t c)
 */
 uint64_t ck(int i, int j, uint64_t z)
 {
 */
 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;
                // 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);
        }
 
                // 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;
                //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);
                        uint8_t val = getSixBitByte(z,c);
-                       if(c == i)
-                       {
+                       if (c == i)
                                pushbackSixBitByte(&newz, j, c);
                                pushbackSixBitByte(&newz, j, c);
-                       }else
-                       {
+                       else
                                pushbackSixBitByte(&newz, val, c);
                                pushbackSixBitByte(&newz, val, c);
-                       }
                }
                return ck(i,j-1,newz);
                }
                return ck(i,j-1,newz);
-       }else
-       {
+       } else {
                return ck(i,j-1,z);
        }
 }
                return ck(i,j-1,z);
        }
 }
@@ -208,9 +205,8 @@ uint64_t check(uint64_t z)
 void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
 {
        if(bitsLeft(p_in) == 0)
 void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
 {
        if(bitsLeft(p_in) == 0)
-       {
                return;
                return;
-       }
+       
        bool pn = tailBit(p_in);
        if( pn ) // pn = 1
        {
        bool pn = tailBit(p_in);
        if( pn ) // pn = 1
        {
@@ -226,10 +222,9 @@ void permute(BitstreamIn *p_in, uint64_t z,int l,int r, BitstreamOut* out)
                permute(p_in,z,l,r+1,out);
        }
 }
                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|");
 }
 
        prnlog("          | x| y|z0|z1|z2|z3|z4|z5|z6|z7|");
 }
@@ -237,17 +232,15 @@ void printbegin()
 void printState(char* desc, uint64_t c)
 {
        if(debug_print < 2)
 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);
 
        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(" %02x", getSixBitByte(c,i));
-       }
        printf("\n");
 }
 
        printf("\n");
 }
 
@@ -287,23 +280,19 @@ void hash0(uint64_t c, uint8_t k[8])
                _zn = (zn % (63-n)) + n;
                _zn4 = (zn4 % (64-n)) + n;
 
                _zn = (zn % (63-n)) + n;
                _zn4 = (zn4 % (64-n)) + n;
 
-
                pushbackSixBitByte(&zP, _zn,n);
                pushbackSixBitByte(&zP, _zn4,n+4);
                pushbackSixBitByte(&zP, _zn,n);
                pushbackSixBitByte(&zP, _zn4,n+4);
-
        }
        }
+
        printState("0|0|z'",zP);
 
        uint64_t zCaret = check(zP);
        printState("0|0|z^",zP);
 
        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
        uint8_t p = pi[x % 35];
 
        if(x & 1) //Check if x7 is 1
-       {
                p = ~p;
                p = ~p;
-       }
 
        if(debug_print >= 2) prnlog("p:%02x", p);
 
 
        if(debug_print >= 2) prnlog("p:%02x", p);
 
@@ -324,9 +313,8 @@ void hash0(uint64_t c, uint8_t k[8])
 
        int i;
        int zerocounter =0 ;
 
        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
                // the key on index i is first a bit from y
                // then six bits from z,
                // then a bit from p
@@ -366,9 +354,9 @@ void hash0(uint64_t c, uint8_t k[8])
                        k[i] |= zTilde_i & 0x7E;
                        k[i] |= (~p_i) & 1;
                }
                        k[i] |= zTilde_i & 0x7E;
                        k[i] |= (~p_i) & 1;
                }
-               if((k[i]  & 1 )== 0)
+               if ((k[i] & 1 )== 0)
                {
                {
-                       zerocounter ++;
+                       zerocounter++;
                }
        }
 }
                }
        }
 }
@@ -380,7 +368,6 @@ void hash0(uint64_t c, uint8_t k[8])
  */
 void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
 {
  */
 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);
 
        // Prepare the DES key
        des_setkey_enc( &ctx_enc, key);
 
@@ -391,18 +378,13 @@ void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8])
 
        //Calculate HASH0(DES))
     uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8);
 
        //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);
 }
 
 
        hash0(crypt_csn,div_key);
 }
 
-
-
-
-
 void testPermute()
 {
 void testPermute()
 {
-
        uint64_t x = 0;
        pushbackSixBitByte(&x,0x00,0);
        pushbackSixBitByte(&x,0x01,1);
        uint64_t x = 0;
        pushbackSixBitByte(&x,0x00,0);
        pushbackSixBitByte(&x,0x01,1);
@@ -454,7 +436,6 @@ typedef struct
        uint8_t div_key[8];
 } Testcase;
 
        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};
 int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
 {
        uint8_t des_encrypted_csn[8] = {0};
@@ -492,7 +473,6 @@ int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec)
                printarr("hash0   ", div_key, 8);
                printarr("Expected", testcase.div_key, 8);
                retval = 1;
                printarr("hash0   ", div_key, 8);
                printarr("Expected", testcase.div_key, 8);
                retval = 1;
-
        }
        return retval;
 }
        }
        return retval;
 }
@@ -505,27 +485,20 @@ bool des_getParityBitFromKey(uint8_t key)
        return !parity;
 }
 
        return !parity;
 }
 
-
-void des_checkParity(uint8_t* key)
-{
+void des_checkParity(uint8_t* key) {
        int i;
        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]);
                bool parity = des_getParityBitFromKey(key[i]);
-               if(parity != (key[i] & 0x1))
-               {
+               if (parity != (key[i] & 0x1)) {
                        fails++;
                        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)
                }
        }
        if(fails)
-       {
                prnlog("[+] parity fails: %d", fails);
                prnlog("[+] parity fails: %d", fails);
-       }else
-       {
+       else
                prnlog("[+] Key syntax is with parity bits inside each byte");
                prnlog("[+] Key syntax is with parity bits inside each byte");
-       }
 }
 
 Testcase testcases[] ={
 }
 
 Testcase testcases[] ={
@@ -599,32 +572,24 @@ Testcase testcases[] ={
        {{0},{0},{0}}
 };
 
        {{0},{0},{0}}
 };
 
-
-int testKeyDiversificationWithMasterkeyTestcases()
-{
-
+int testKeyDiversificationWithMasterkeyTestcases() {
        int error = 0;
        int i;
        int error = 0;
        int i;
-
        uint8_t empty[8]={0};
        uint8_t empty[8]={0};
+
        prnlog("[+} Testing encryption/decryption");
 
        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);
                prnlog("[+] %d errors occurred (%d testcases)", error, i);
-       }else
-       {
+       else
                prnlog("[+] Hashing seems to work (%d testcases)", i);
                prnlog("[+] Hashing seems to work (%d testcases)", i);
-       }
        return error;
 }
 
        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));
 }
 
        printf("%s%08x%08x\n",name,(uint32_t) (val >> 32) ,(uint32_t) (val & 0xFFFFFFFF));
 }
 
@@ -643,24 +608,19 @@ uint64_t testCryptedCSN(uint64_t crypted_csn, uint64_t expected)
     uint64_t resultbyte = x_bytes_to_num(result,8 );
        if(debug_print) print64bits("    hash0      " , resultbyte );
 
     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;
                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;
 }
 
        }
        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};
 
        uint8_t result[8] = {0};
        uint8_t input[8] = {0};
 
@@ -673,12 +633,10 @@ int testDES2(uint64_t csn, uint64_t expected)
        print64bits("   {csn}    ", crypt_csn );
        print64bits("   expected ", expected );
 
        print64bits("   {csn}    ", crypt_csn );
        print64bits("   expected ", expected );
 
-       if( expected == crypt_csn )
-       {
+       if( expected == crypt_csn ) {
                prnlog("[+] OK");
                return 0;
                prnlog("[+] OK");
                return 0;
-       }else
-       {
+       } else {
                return 1;
        }
 }
                return 1;
        }
 }
@@ -688,14 +646,10 @@ int testDES2(uint64_t csn, uint64_t expected)
  * @brief doTestsWithKnownInputs
  * @return
  */
  * @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");
        // 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);
        uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf};
 
        des_setkey_enc( &ctx_enc, key);
@@ -713,28 +667,26 @@ int doTestsWithKnownInputs()
        errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
        errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
 
        errors += testCryptedCSN(0x21ba6565071f9299,0x34e80f88d5cf39ea);
        errors += testCryptedCSN(0x14e2adfc5bb7e134,0x6ac90c6508bd9ea3);
 
-       if(errors)
-       {
+       if (errors)
                prnlog("[+] %d errors occurred (9 testcases)", errors);
                prnlog("[+] %d errors occurred (9 testcases)", errors);
-       }else
-       {
+       else
                prnlog("[+] Hashing seems to work (9 testcases)" );
                prnlog("[+] Hashing seems to work (9 testcases)" );
-       }
        return errors;
 }
 
        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 (f)
-       {
-               if(fread(key, sizeof(key), 1, f) == 1) return 0;
-       }
-       return 1;
-
+               fclose(f);
+       return retval;
 }
 
 
 }
 
 
@@ -744,25 +696,20 @@ int doKeyTests(uint8_t debuglevel)
 
        prnlog("[+] Checking if the master key is present (iclass_key.bin)...");
        uint8_t key[8] = {0};
 
        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");
                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;
 
                //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];
                        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");
                        prnlog("[+] A key was loaded, but it does not seem to be the correct one. Aborting these tests");
-               }else
-               {
+               } else {
                        prnlog("[+] Key present");
                        prnlog("[+] Key present");
-
                        prnlog("[+] Checking key parity...");
                        des_checkParity(key);
                        des_setkey_enc( &ctx_enc, key);
                        prnlog("[+] Checking key parity...");
                        des_checkParity(key);
                        des_setkey_enc( &ctx_enc, key);
@@ -850,29 +797,20 @@ void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output)
        BitstreamOut out = { output, 0,0};
        BitstreamIn in = {key, 0,0};
        unsigned int bbyte, bbit;
        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);
                        parity = 0;
                }
                bool bit = headBit(&in);
                pushBit(&out,bit );
                parity ^= bit;
-
        }
        pushBit(&out, !parity);
 
        }
        pushBit(&out, !parity);
 
-
        if(     des_key_check_key_parity(output))
        if(     des_key_check_key_parity(output))
-       {
                printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
                printf("modifyKey_put_parity_allover fail, DES key invalid parity!");
-       }
-
 }
 }
-
 */
 
 
 */
 
 
Impressum, Datenschutz