diff --git a/application.fam b/application.fam index d47dd9e..a78c28a 100644 --- a/application.fam +++ b/application.fam @@ -30,6 +30,10 @@ App( name="asn1", cflags=["-Wno-error"], ), + Lib( + name="loclass", + cflags=["-O3"], + ), ], fap_weburl="https://seader.ericbetts.dev", fap_icon_assets="icons", diff --git a/lib/loclass/optimized_cipher.c b/lib/loclass/optimized_cipher.c new file mode 100644 index 0000000..e42dc08 --- /dev/null +++ b/lib/loclass/optimized_cipher.c @@ -0,0 +1,319 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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 file contains an optimized version of the MAC-calculation algorithm. Some measurements on + a std laptop showed it runs in about 1/3 of the time: + + Std: 0.428962 + Opt: 0.151609 + + Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can + be easily dropped into a code base. + + The optimizations have been performed in the following steps: + * Parameters passed by reference instead of by value. + * Iteration instead of recursion, un-nesting recursive loops into for-loops. + * Handling of bytes instead of individual bits, for less shuffling and masking + * Less creation of "objects", structs, and instead reuse of alloc:ed memory + * Inlining some functions via #define:s + + As a consequence, this implementation is less generic. Also, I haven't bothered documenting this. + For a thorough documentation, check out the MAC-calculation within cipher.c instead. + + -- MHS 2015 +**/ + +/** + + The runtime of opt_doTagMAC_2() with the MHS optimized version was 403 microseconds on Proxmark3. + This was still to slow for some newer readers which didn't want to wait that long. + + Further optimizations to speedup the MAC calculations: + * Optimized opt_Tt logic + * Look up table for opt_select + * Removing many unnecessary bit maskings (& 0x1) + * updating state in place instead of alternating use of a second state structure + * remove the necessity to reverse bits of input and output bytes + + opt_doTagMAC_2() now completes in 270 microseconds. + + -- piwi 2019 +**/ + +/** + add the possibility to do iCLASS on device only + -- iceman 2020 +**/ + +#include "optimized_cipher.h" +#include "optimized_elite.h" +#include "optimized_ikeys.h" +#include "optimized_cipherutils.h" + +static const uint8_t loclass_opt_select_LUT[256] = { + 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, 01, 02, 03, 00, 02, 03, 00, 01, + 05, 06, 06, 05, 06, 07, 05, 04, 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06, + 07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, 06, 05, 04, 07, 04, 05, 06, 07, + 02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, + 00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, 05, 06, 07, 04, 06, 07, 04, 05, + 05, 06, 06, 05, 06, 07, 05, 04, 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06, + 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, 02, 01, 00, 03, 00, 01, 02, 03, + 02, 01, 01, 02, 00, 01, 03, 02, 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02, + 04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, 01, 02, 03, 00, 02, 03, 00, 01, + 05, 06, 06, 05, 06, 07, 05, 04, 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04, + 01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00}; + +/********************** the table above has been generated with this code: ******** +#include "util.h" +static void init_opt_select_LUT(void) { + for (int r = 0; r < 256; r++) { + uint8_t r_ls2 = r << 2; + uint8_t r_and_ls2 = r & r_ls2; + uint8_t r_or_ls2 = r | r_ls2; + uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); + uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r; + uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r; + loclass_opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1); + } + print_result("", loclass_opt_select_LUT, 256); +} +***********************************************************************************/ + +static inline void loclass_opt_successor(const uint8_t* k, LoclassState_t* s, uint8_t y) { + uint16_t Tt = s->t & 0xc533; + Tt = Tt ^ (Tt >> 1); + Tt = Tt ^ (Tt >> 4); + Tt = Tt ^ (Tt >> 10); + Tt = Tt ^ (Tt >> 8); + + s->t = (s->t >> 1); + s->t |= (Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15; + + uint8_t opt_B = s->b; + opt_B ^= s->b >> 6; + opt_B ^= s->b >> 5; + opt_B ^= s->b >> 4; + + s->b = s->b >> 1; + s->b |= (opt_B ^ s->r) << 7; + + uint8_t Tt1 = Tt & 0x01; + uint8_t opt_select = loclass_opt_select_LUT[s->r] ^ Tt1 ^ ((Tt1 ^ (y & 0x01)) << 1); + + uint8_t r = s->r; + s->r = (k[opt_select] ^ s->b) + s->l; + s->l = s->r + r; +} + +static inline void loclass_opt_suc( + const uint8_t* k, + LoclassState_t* s, + const uint8_t* in, + uint8_t length, + bool add32Zeroes) { + for(int i = 0; i < length; i++) { + uint8_t head = in[i]; +#pragma GCC unroll 8 + for(int j = 0; j < 8; j++) { + loclass_opt_successor(k, s, head); + head >>= 1; + } + } + // For tag MAC, an additional 32 zeroes + if(add32Zeroes) { + for(int i = 0; i < 32; i++) { + loclass_opt_successor(k, s, 0); + } + } +} + +static inline void loclass_opt_output(const uint8_t* k, LoclassState_t* s, uint8_t* buffer) { +#pragma GCC unroll 4 + for(uint8_t times = 0; times < 4; times++) { + uint8_t bout = 0; + bout |= (s->r & 0x4) >> 2; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) >> 1; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4); + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 1; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 2; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 3; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 4; + loclass_opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 5; + loclass_opt_successor(k, s, 0); + buffer[times] = bout; + } +} + +static void loclass_opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out) { + LoclassState_t _init = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((k[0] ^ 0x4c) + 0x21) & 0xFF, // r + 0x4c, // b + 0xE012 // t + }; + + loclass_opt_suc(k, &_init, input, 12, false); + loclass_opt_output(k, &_init, out); +} + +static void loclass_opt_MAC_N(uint8_t* k, uint8_t* input, uint8_t in_size, uint8_t* out) { + LoclassState_t _init = { + ((k[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((k[0] ^ 0x4c) + 0x21) & 0xFF, // r + 0x4c, // b + 0xE012 // t + }; + + loclass_opt_suc(k, &_init, input, in_size, false); + loclass_opt_output(k, &_init, out); +} + +void loclass_opt_doReaderMAC(uint8_t* cc_nr_p, uint8_t* div_key_p, uint8_t mac[4]) { + uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; + loclass_opt_MAC(div_key_p, cc_nr_p, dest); + memcpy(mac, dest, 4); +} + +void loclass_opt_doReaderMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p) { + loclass_opt_suc(div_key_p, &_init, nr, 4, false); + loclass_opt_output(div_key_p, &_init, mac); +} + +void loclass_doMAC_N(uint8_t* in_p, uint8_t in_size, uint8_t* div_key_p, uint8_t mac[4]) { + uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; + loclass_opt_MAC_N(div_key_p, in_p, in_size, dest); + memcpy(mac, dest, 4); +} + +void loclass_opt_doTagMAC(uint8_t* cc_p, const uint8_t* div_key_p, uint8_t mac[4]) { + LoclassState_t _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r + 0x4c, // b + 0xE012 // t + }; + loclass_opt_suc(div_key_p, &_init, cc_p, 12, true); + loclass_opt_output(div_key_p, &_init, mac); +} + +/** + * The tag MAC can be divided (both can, but no point in dividing the reader mac) into + * two functions, since the first 8 bytes are known, we can pre-calculate the state + * reached after feeding CC to the cipher. + * @param cc_p + * @param div_key_p + * @return the cipher state + */ +LoclassState_t loclass_opt_doTagMAC_1(uint8_t* cc_p, const uint8_t* div_key_p) { + LoclassState_t _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF, // l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF, // r + 0x4c, // b + 0xE012 // t + }; + loclass_opt_suc(div_key_p, &_init, cc_p, 8, false); + return _init; +} + +/** + * The second part of the tag MAC calculation, since the CC is already calculated into the state, + * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag + * MAC response. + * @param _init - precalculated cipher state + * @param nr - the reader challenge + * @param mac - where to store the MAC + * @param div_key_p - the key to use + */ +void loclass_opt_doTagMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p) { + loclass_opt_suc(div_key_p, &_init, nr, 4, true); + loclass_opt_output(div_key_p, &_init, mac); +} + +/** + * The second part of the tag MAC calculation, since the CC is already calculated into the state, + * this function is fed only the NR, and generates both the reader and tag MACs. + * @param _init - precalculated cipher state + * @param nr - the reader challenge + * @param rmac - where to store the reader MAC + * @param tmac - where to store the tag MAC + * @param div_key_p - the key to use + */ +void loclass_opt_doBothMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t rmac[4], + uint8_t tmac[4], + const uint8_t* div_key_p) { + LoclassState_t* s = &_init; + loclass_opt_suc(div_key_p, s, nr, 4, false); + loclass_opt_output(div_key_p, s, rmac); + loclass_opt_output(div_key_p, s, tmac); +} + +void loclass_iclass_calc_div_key( + const uint8_t* csn, + const uint8_t* key, + uint8_t* div_key, + bool elite) { + if(elite) { + uint8_t keytable[128] = {0}; + uint8_t key_index[8] = {0}; + uint8_t key_sel[8] = {0}; + uint8_t key_sel_p[8] = {0}; + loclass_hash2(key, keytable); + loclass_hash1(csn, key_index); + for(uint8_t i = 0; i < 8; i++) key_sel[i] = keytable[key_index[i]]; + + //Permute from iclass format to standard format + loclass_permutekey_rev(key_sel, key_sel_p); + loclass_diversifyKey(csn, key_sel_p, div_key); + } else { + loclass_diversifyKey(csn, key, div_key); + } +} diff --git a/lib/loclass/optimized_cipher.h b/lib/loclass/optimized_cipher.h new file mode 100644 index 0000000..5830bec --- /dev/null +++ b/lib/loclass/optimized_cipher.h @@ -0,0 +1,117 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// More recently from https://github.com/RfidResearchGroup/proxmark3 +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#ifndef OPTIMIZED_CIPHER_H +#define OPTIMIZED_CIPHER_H +#include +#include +#include +#include + +/** +* 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; +} LoclassState_t; + +/** The reader MAC is MAC(key, CC * NR ) + **/ +void loclass_opt_doReaderMAC(uint8_t* cc_nr_p, uint8_t* div_key_p, uint8_t mac[4]); + +void loclass_opt_doReaderMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p); + +/** + * The tag MAC is MAC(key, CC * NR * 32x0)) + */ +void loclass_opt_doTagMAC(uint8_t* cc_p, const uint8_t* div_key_p, uint8_t mac[4]); + +/** + * The tag MAC can be divided (both can, but no point in dividing the reader mac) into + * two functions, since the first 8 bytes are known, we can pre-calculate the state + * reached after feeding CC to the cipher. + * @param cc_p + * @param div_key_p + * @return the cipher state + */ +LoclassState_t loclass_opt_doTagMAC_1(uint8_t* cc_p, const uint8_t* div_key_p); +/** + * The second part of the tag MAC calculation, since the CC is already calculated into the state, + * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag + * MAC response. + * @param _init - precalculated cipher state + * @param nr - the reader challenge + * @param mac - where to store the MAC + * @param div_key_p - the key to use + */ +void loclass_opt_doTagMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t mac[4], + const uint8_t* div_key_p); + +/** + * The same as loclass_opt_doTagMAC_2, but calculates both the reader and tag MACs at the same time + * @param _init - precalculated cipher state + * @param nr - the reader challenge + * @param rmac - where to store the reader MAC + * @param tmac - where to store the tag MAC + * @param div_key_p - the key to use + */ +void loclass_opt_doBothMAC_2( + LoclassState_t _init, + uint8_t* nr, + uint8_t rmac[4], + uint8_t tmac[4], + const uint8_t* div_key_p); + +void loclass_doMAC_N(uint8_t* in_p, uint8_t in_size, uint8_t* div_key_p, uint8_t mac[4]); +void loclass_iclass_calc_div_key( + const uint8_t* csn, + const uint8_t* key, + uint8_t* div_key, + bool elite); +#endif // OPTIMIZED_CIPHER_H diff --git a/lib/loclass/optimized_cipherutils.c b/lib/loclass/optimized_cipherutils.c new file mode 100644 index 0000000..e6a87c4 --- /dev/null +++ b/lib/loclass/optimized_cipherutils.c @@ -0,0 +1,136 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#include "optimized_cipherutils.h" +#include + +/** + * + * @brief Return and remove the first bit (x0) in the stream : + * @param stream + * @return + */ +bool loclass_headBit(LoclassBitstreamIn_t* 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: + * @param stream + * @return + */ +bool loclass_tailBit(LoclassBitstreamIn_t* 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 loclass_pushBit(LoclassBitstreamOut_t* stream, bool bit) { + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = stream->position & 7; + *(stream->buffer + bytepos) |= (bit) << (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 loclass_push6bits(LoclassBitstreamOut_t* stream, uint8_t bits) { + loclass_pushBit(stream, bits & 0x20); + loclass_pushBit(stream, bits & 0x10); + loclass_pushBit(stream, bits & 0x08); + loclass_pushBit(stream, bits & 0x04); + loclass_pushBit(stream, bits & 0x02); + loclass_pushBit(stream, bits & 0x01); +} + +/** + * @brief loclass_bitsLeft + * @param stream + * @return number of bits left in stream + */ +int loclass_bitsLeft(LoclassBitstreamIn_t* stream) { + return stream->numbits - stream->position; +} +/** + * @brief numBits + * @param stream + * @return Number of bits stored in stream + */ +void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { + while(len--) { + dest[len] = (uint8_t)n; + n >>= 8; + } +} + +uint64_t loclass_x_bytes_to_num(uint8_t* src, size_t len) { + uint64_t num = 0; + while(len--) { + num = (num << 8) | (*src); + src++; + } + return num; +} + +uint8_t loclass_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 loclass_reverse_arraybytes(uint8_t* arr, size_t len) { + uint8_t i; + for(i = 0; i < len; i++) { + arr[i] = loclass_reversebytes(arr[i]); + } +} + +void loclass_reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len) { + uint8_t i; + for(i = 0; i < len; i++) { + dest[i] = loclass_reversebytes(arr[i]); + } +} diff --git a/lib/loclass/optimized_cipherutils.h b/lib/loclass/optimized_cipherutils.h new file mode 100644 index 0000000..05b6820 --- /dev/null +++ b/lib/loclass/optimized_cipherutils.h @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// More recently from https://github.com/RfidResearchGroup/proxmark3 +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#ifndef CIPHERUTILS_H +#define CIPHERUTILS_H +#include +#include +#include + +typedef struct { + uint8_t* buffer; + uint8_t numbits; + uint8_t position; +} LoclassBitstreamIn_t; + +typedef struct { + uint8_t* buffer; + uint8_t numbits; + uint8_t position; +} LoclassBitstreamOut_t; + +bool loclass_headBit(LoclassBitstreamIn_t* stream); +bool loclass_tailBit(LoclassBitstreamIn_t* stream); +void loclass_pushBit(LoclassBitstreamOut_t* stream, bool bit); +int loclass_bitsLeft(LoclassBitstreamIn_t* stream); + +void loclass_push6bits(LoclassBitstreamOut_t* stream, uint8_t bits); +void loclass_x_num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +uint64_t loclass_x_bytes_to_num(uint8_t* src, size_t len); +uint8_t loclass_reversebytes(uint8_t b); +void loclass_reverse_arraybytes(uint8_t* arr, size_t len); +void loclass_reverse_arraycopy(uint8_t* arr, uint8_t* dest, size_t len); +#endif // CIPHERUTILS_H diff --git a/lib/loclass/optimized_elite.c b/lib/loclass/optimized_elite.c new file mode 100644 index 0000000..e198a41 --- /dev/null +++ b/lib/loclass/optimized_elite.c @@ -0,0 +1,232 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#include "optimized_elite.h" + +#include +#include +#include +#include +#include "optimized_ikeys.h" + +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 + * + * If you loclass_permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. + * + * 1 0 1 1 1 1 1 1 bf + * 0 0 0 0 0 0 0 1 01 + * 0 0 1 0 1 1 0 1 2d + * 0 0 1 0 1 0 1 0 2a + * 1 1 1 1 1 0 0 1 f9 + * 0 1 0 0 0 1 0 0 44 + * 1 0 0 0 1 1 0 1 8d + * 0 1 1 0 1 1 0 0 6c + * + * 8 0 b 8 b a 9 e + * a d 9 8 b 7 0 a + * + * @param key + * @param dest + */ +void loclass_permutekey(const uint8_t key[8], uint8_t dest[8]) { + int i; + for(i = 0; i < 8; i++) { + dest[i] = (((key[7] & (0x80 >> i)) >> (7 - i)) << 7) | + (((key[6] & (0x80 >> i)) >> (7 - i)) << 6) | + (((key[5] & (0x80 >> i)) >> (7 - i)) << 5) | + (((key[4] & (0x80 >> i)) >> (7 - i)) << 4) | + (((key[3] & (0x80 >> i)) >> (7 - i)) << 3) | + (((key[2] & (0x80 >> i)) >> (7 - i)) << 2) | + (((key[1] & (0x80 >> i)) >> (7 - i)) << 1) | + (((key[0] & (0x80 >> i)) >> (7 - i)) << 0); + } +} +/** + * Permutes a key from iclass specific format to NIST format + * @brief loclass_permutekey_rev + * @param key + * @param dest + */ +void loclass_permutekey_rev(const uint8_t key[8], uint8_t dest[8]) { + int i; + for(i = 0; i < 8; i++) { + dest[7 - i] = (((key[0] & (0x80 >> i)) >> (7 - i)) << 7) | + (((key[1] & (0x80 >> i)) >> (7 - i)) << 6) | + (((key[2] & (0x80 >> i)) >> (7 - i)) << 5) | + (((key[3] & (0x80 >> i)) >> (7 - i)) << 4) | + (((key[4] & (0x80 >> i)) >> (7 - i)) << 3) | + (((key[5] & (0x80 >> i)) >> (7 - i)) << 2) | + (((key[6] & (0x80 >> i)) >> (7 - i)) << 1) | + (((key[7] & (0x80 >> i)) >> (7 - i)) << 0); + } +} + +/** + * Helper function for loclass_hash1 + * @brief loclass_rr + * @param val + * @return + */ +static uint8_t loclass_rr(uint8_t val) { + return val >> 1 | ((val & 1) << 7); +} + +/** + * Helper function for loclass_hash1 + * @brief rl + * @param val + * @return + */ +static uint8_t loclass_rl(uint8_t val) { + return val << 1 | ((val & 0x80) >> 7); +} + +/** + * Helper function for loclass_hash1 + * @brief loclass_swap + * @param val + * @return + */ +static uint8_t loclass_swap(uint8_t val) { + return ((val >> 4) & 0xFF) | ((val & 0xFF) << 4); +} + +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void loclass_hash1(const uint8_t csn[], uint8_t k[]) { + k[0] = csn[0] ^ csn[1] ^ csn[2] ^ csn[3] ^ csn[4] ^ csn[5] ^ csn[6] ^ csn[7]; + k[1] = csn[0] + csn[1] + csn[2] + csn[3] + csn[4] + csn[5] + csn[6] + csn[7]; + k[2] = loclass_rr(loclass_swap(csn[2] + k[1])); + k[3] = loclass_rl(loclass_swap(csn[3] + k[0])); + k[4] = ~loclass_rr(csn[4] + k[2]) + 1; + k[5] = ~loclass_rl(csn[5] + k[3]) + 1; + k[6] = loclass_rr(csn[6] + (k[4] ^ 0x3c)); + k[7] = loclass_rl(csn[7] + (k[5] ^ 0xc3)); + + k[7] &= 0x7F; + k[6] &= 0x7F; + k[5] &= 0x7F; + k[4] &= 0x7F; + k[3] &= 0x7F; + k[2] &= 0x7F; + k[1] &= 0x7F; + k[0] &= 0x7F; +} +/** +Definition 14. Define the rotate key function loclass_rk : (F 82 ) 8 × N → (F 82 ) 8 as +loclass_rk(x [0] . . . x [7] , 0) = x [0] . . . x [7] +loclass_rk(x [0] . . . x [7] , n + 1) = loclass_rk(loclass_rl(x [0] ) . . . loclass_rl(x [7] ), n) +**/ +static void loclass_rk(const uint8_t* key, uint8_t n, uint8_t* outp_key) { + memcpy(outp_key, key, 8); + uint8_t j; + while(n-- > 0) { + for(j = 0; j < 8; j++) outp_key[j] = loclass_rl(outp_key[j]); + } + return; +} + +static mbedtls_des_context loclass_ctx_enc; +static mbedtls_des_context loclass_ctx_dec; + +static void loclass_desdecrypt_iclass(uint8_t* iclass_key, uint8_t* input, uint8_t* output) { + uint8_t key_std_format[8] = {0}; + loclass_permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_dec(&loclass_ctx_dec, key_std_format); + mbedtls_des_crypt_ecb(&loclass_ctx_dec, input, output); +} + +static void loclass_desencrypt_iclass(const uint8_t* iclass_key, uint8_t* input, uint8_t* output) { + uint8_t key_std_format[8] = {0}; + loclass_permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_enc(&loclass_ctx_enc, key_std_format); + mbedtls_des_crypt_ecb(&loclass_ctx_enc, input, output); +} + +/** + * @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select. + * @param key unpermuted custom key + * @param loclass_hash1 loclass_hash1 + * @param key_sel output key_sel=h[loclass_hash1[i]] + */ +void loclass_hash2(const uint8_t* key64, uint8_t* outp_keytable) { + /** + *Expected: + * High Security Key Table + + 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 + 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 + 20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2 + 30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C + 40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6 + 50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42 + 60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95 + 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB + + **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/ + uint8_t key64_negated[8] = {0}; + uint8_t z[8][8] = {{0}, {0}}; + uint8_t temp_output[8] = {0}; + + //calculate complement of key + int i; + for(i = 0; i < 8; i++) key64_negated[i] = ~key64[i]; + + // Once again, key is on iclass-format + loclass_desencrypt_iclass(key64, key64_negated, z[0]); + + uint8_t y[8][8] = {{0}, {0}}; + + // y[0]=DES_dec(z[0],~key) + // Once again, key is on iclass-format + loclass_desdecrypt_iclass(z[0], key64_negated, y[0]); + + for(i = 1; i < 8; i++) { + loclass_rk(key64, i, temp_output); + loclass_desdecrypt_iclass(temp_output, z[i - 1], z[i]); + loclass_desencrypt_iclass(temp_output, y[i - 1], y[i]); + } + + if(outp_keytable != NULL) { + for(i = 0; i < 8; i++) { + memcpy(outp_keytable + i * 16, y[i], 8); + memcpy(outp_keytable + 8 + i * 16, z[i], 8); + } + } +} diff --git a/lib/loclass/optimized_elite.h b/lib/loclass/optimized_elite.h new file mode 100644 index 0000000..fba512a --- /dev/null +++ b/lib/loclass/optimized_elite.h @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// More recently from https://github.com/RfidResearchGroup/proxmark3 +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#ifndef ELITE_CRACK_H +#define ELITE_CRACK_H + +#include +#include + +void loclass_permutekey(const uint8_t key[8], uint8_t dest[8]); +/** + * Permutes a key from iclass specific format to NIST format + * @brief loclass_permutekey_rev + * @param key + * @param dest + */ +void loclass_permutekey_rev(const uint8_t key[8], uint8_t dest[8]); +/** + * Hash1 takes CSN as input, and determines what bytes in the keytable will be used + * when constructing the K_sel. + * @param csn the CSN used + * @param k output + */ +void loclass_hash1(const uint8_t* csn, uint8_t* k); +void loclass_hash2(const uint8_t* key64, uint8_t* outp_keytable); + +#endif diff --git a/lib/loclass/optimized_ikeys.c b/lib/loclass/optimized_ikeys.c new file mode 100644 index 0000000..d19f560 --- /dev/null +++ b/lib/loclass/optimized_ikeys.c @@ -0,0 +1,320 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- + +/** +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 loclass_hash0 which + outputs the diversified key k. + + k = loclass_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 loclass_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 loclass_hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 . + +**/ +#include "optimized_ikeys.h" + +#include +#include +#include +#include +#include "optimized_cipherutils.h" + +static const uint8_t loclass_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}; + +/** + * @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 last 48 bits. + * + * This function picks out one from such a collection + * @param all + * @param n bitnumber + * @return + */ +static uint8_t loclass_getSixBitByte(uint64_t c, int n) { + return (c >> (42 - 6 * n)) & 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. + */ +static void loclass_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; +} +/** + * @brief Swaps the z-values. + * If the input value has format XYZ0Z1...Z7, the output will have the format + * XYZ7Z6...Z0 instead + * @param c + * @return + */ +static uint64_t loclass_swapZvalues(uint64_t c) { + uint64_t newz = 0; + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 0), 7); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 1), 6); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 2), 5); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 3), 4); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 4), 3); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 5), 2); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 6), 1); + loclass_pushbackSixBitByte(&newz, loclass_getSixBitByte(c, 7), 0); + newz |= (c & 0xFFFF000000000000); + return newz; +} + +/** +* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3 +*/ +static uint64_t loclass_ck(int i, int j, uint64_t z) { + if(i == 1 && j == -1) { + // loclass_ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + return z; + } else if(j == -1) { + // loclass_ck(i, −1, z [0] . . . z [3] ) = loclass_ck(i − 1, i − 2, z [0] . . . z [3] ) + return loclass_ck(i - 1, i - 2, z); + } + + if(loclass_getSixBitByte(z, i) == loclass_getSixBitByte(z, j)) { + //loclass_ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ) + uint64_t newz = 0; + int c; + for(c = 0; c < 4; c++) { + uint8_t val = loclass_getSixBitByte(z, c); + if(c == i) + loclass_pushbackSixBitByte(&newz, j, c); + else + loclass_pushbackSixBitByte(&newz, val, c); + } + return loclass_ck(i, j - 1, newz); + } else { + return loclass_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] ) = loclass_ck(3, 2, z [0] . . . z [3] ) · loclass_ck(3, 2, z [4] . . . z [7] ) + + where loclass_ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as + + loclass_ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3] + loclass_ck(i, −1, z [0] . . . z [3] ) = loclass_ck(i − 1, i − 2, z [0] . . . z [3] ) + loclass_ck(i, j, z [0] . . . z [3] ) = + loclass_ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ; + loclass_ck(i, j − 1, z [0] . . . z [3] ), otherwise + + otherwise. +**/ + +static uint64_t loclass_check(uint64_t z) { + //These 64 bits are divided as c = x, y, z [0] , . . . , z [7] + + // loclass_ck(3, 2, z [0] . . . z [3] ) + uint64_t ck1 = loclass_ck(3, 2, z); + + // loclass_ck(3, 2, z [4] . . . z [7] ) + uint64_t ck2 = loclass_ck(3, 2, z << 24); + + //The loclass_ck function will place the values + // in the middle of z. + ck1 &= 0x00000000FFFFFF000000; + ck2 &= 0x00000000FFFFFF000000; + + return ck1 | ck2 >> 24; +} + +static void loclass_permute( + LoclassBitstreamIn_t* p_in, + uint64_t z, + int l, + int r, + LoclassBitstreamOut_t* out) { + if(loclass_bitsLeft(p_in) == 0) return; + + bool pn = loclass_tailBit(p_in); + if(pn) { // pn = 1 + uint8_t zl = loclass_getSixBitByte(z, l); + + loclass_push6bits(out, zl + 1); + loclass_permute(p_in, z, l + 1, r, out); + } else { // otherwise + uint8_t zr = loclass_getSixBitByte(z, r); + + loclass_push6bits(out, zr); + loclass_permute(p_in, z, l, r + 1, out); + } +} + +/** + * @brief + *Definition 11. Let the function loclass_hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * loclass_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 loclass_hash0(uint64_t c, uint8_t k[8]) { + c = loclass_swapZvalues(c); + + //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; + uint64_t zP = 0; + + for(int n = 0; n < 4; n++) { + uint8_t zn = loclass_getSixBitByte(c, n); + uint8_t zn4 = loclass_getSixBitByte(c, n + 4); + uint8_t _zn = (zn % (63 - n)) + n; + uint8_t _zn4 = (zn4 % (64 - n)) + n; + loclass_pushbackSixBitByte(&zP, _zn, n); + loclass_pushbackSixBitByte(&zP, _zn4, n + 4); + } + + uint64_t zCaret = loclass_check(zP); + uint8_t p = loclass_pi[x % 35]; + + if(x & 1) //Check if x7 is 1 + p = ~p; + + LoclassBitstreamIn_t p_in = {&p, 8, 0}; + uint8_t outbuffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; + LoclassBitstreamOut_t out = {outbuffer, 0, 0}; + loclass_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 + //Shift z-values down onto the lower segment + + uint64_t zTilde = loclass_x_bytes_to_num(outbuffer, sizeof(outbuffer)); + + zTilde >>= 16; + + for(int 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; + + uint8_t zTilde_i = loclass_getSixBitByte(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 + 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; + } + } +} +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ +void loclass_diversifyKey(const uint8_t* csn, const uint8_t* key, uint8_t* div_key) { + mbedtls_des_context loclass_ctx_enc; + + // Prepare the DES key + mbedtls_des_setkey_enc(&loclass_ctx_enc, key); + + uint8_t crypted_csn[8] = {0}; + + // Calculate DES(CSN, KEY) + mbedtls_des_crypt_ecb(&loclass_ctx_enc, csn, crypted_csn); + + //Calculate HASH0(DES)) + uint64_t c_csn = loclass_x_bytes_to_num(crypted_csn, sizeof(crypted_csn)); + + loclass_hash0(c_csn, div_key); +} diff --git a/lib/loclass/optimized_ikeys.h b/lib/loclass/optimized_ikeys.h new file mode 100644 index 0000000..f40e87b --- /dev/null +++ b/lib/loclass/optimized_ikeys.h @@ -0,0 +1,66 @@ +//----------------------------------------------------------------------------- +// Borrowed initially from https://github.com/holiman/loclass +// More recently from https://github.com/RfidResearchGroup/proxmark3 +// Copyright (C) 2014 Martin Holst Swende +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// 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 3 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. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// It is a reconstruction 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". +//----------------------------------------------------------------------------- +#ifndef IKEYS_H +#define IKEYS_H + +#include + +/** + * @brief + *Definition 11. Let the function loclass_hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as + * loclass_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 loclass_hash0(uint64_t c, uint8_t k[8]); +/** + * @brief Performs Elite-class key diversification + * @param csn + * @param key + * @param div_key + */ + +void loclass_diversifyKey(const uint8_t* csn, const uint8_t* key, uint8_t* div_key); +/** + * @brief Permutes a key from standard NIST format to Iclass specific format + * @param key + * @param dest + */ + +#endif // IKEYS_H