[FL-2859,2838] fbt: improvements for FAPs (#1813)

* fbt: assets builder for apps WIP
* fbt: automatically building private fap assets
* docs: details on how to use image assets
* fbt: renamed fap_assets -> fap_icons
* fbt: support for fap_extbuild field
* docs: info on fap_extbuild
* fbt: added --proxy-env parame ter
* fbt: made firmware_cdb & updater_cdb targets always available
* fbt: renamed fap_icons -> fap_icon_assets
* fbt: deprecated firmware_* target names for faps; new alias is "fap_APPID"
* fbt: changed intermediate file locations for external apps
* fbt: support for fap_private_libs; docs: updates
* restored mbedtls as global lib
* scripts: lint.py: skip "lib" subfolder
* fbt: Sanity checks for building advanced faps as part of fw
* docs: info on fap_private_libs; fbt: optimized *.fam indexing
* fbt: cleanup; samples: added sample_icons app
* fbt: moved example app to applications/examples
* linter fix
* docs: readme fixes
* added applications/examples/application.fam stub
* docs: more info on private libs

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2022-10-06 17:55:57 +04:00
committed by GitHub
parent a69e150e2f
commit 9bf11d9fd2
27 changed files with 438 additions and 81 deletions

View File

@@ -0,0 +1,318 @@
//-----------------------------------------------------------------------------
// 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);
}
***********************************************************************************/
#define loclass_opt__select(x, y, r) \
(4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ((r | r << 2) >> 3))) | \
(2 & (((r | r << 2) >> 6) ^ ((r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x ^ y) << 1))) | \
(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x))
static 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 opt_select = loclass_opt_select_LUT[s->r] & 0x04;
opt_select |= (loclass_opt_select_LUT[s->r] ^ ((Tt ^ y) << 1)) & 0x02;
opt_select |= (loclass_opt_select_LUT[s->r] ^ Tt) & 0x01;
uint8_t r = s->r;
s->r = (k[opt_select] ^ s->b) + s->l;
s->l = s->r + r;
}
static 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;
head = in[i];
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
head >>= 1;
loclass_opt_successor(k, s, head);
}
//For tag MAC, an additional 32 zeroes
if(add32Zeroes) {
for(int i = 0; i < 16; i++) {
loclass_opt_successor(k, s, 0);
loclass_opt_successor(k, s, 0);
}
}
}
static void loclass_opt_output(const uint8_t* k, LoclassState_t* s, uint8_t* buffer) {
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);
}
void loclass_iclass_calc_div_key(uint8_t* csn, 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);
}
}

View File

@@ -0,0 +1,98 @@
//-----------------------------------------------------------------------------
// 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 <stdlib.h>
#include <string.h>
#include <stdbool.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;
} 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);
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(uint8_t* csn, uint8_t* key, uint8_t* div_key, bool elite);
#endif // OPTIMIZED_CIPHER_H

View File

@@ -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 <stdint.h>
/**
*
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
* @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: <x0 x1 x2 ... xn>
* @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]);
}
}

View File

@@ -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 <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
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

View File

@@ -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 <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <mbedtls/des.h>
#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(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(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 hash2(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);
}
}
}

View File

@@ -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 <stdint.h>
#include <stdlib.h>
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(uint8_t* key64, uint8_t* outp_keytable);
#endif

View File

@@ -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 <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <mbedtls/des.h>
#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(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);
}

View File

@@ -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 <inttypes.h>
/**
* @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(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