1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/holiman/loclass
3 // Copyright (C) 2014 Martin Holst Swende
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
20 // THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
22 // USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
23 // PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
24 // AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
26 // THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
27 //-----------------------------------------------------------------------------
28 // It is a reconstruction of the cipher engine used in iClass, and RFID techology.
30 // The implementation is based on the work performed by
31 // Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
32 // Milosch Meriac in the paper "Dismantling IClass".
33 //-----------------------------------------------------------------------------
34 #include "cipherutils.h"
39 #include "util.h" // sprint_hex
40 #include "commonutil.h" // ARRAYLEN
42 #include "fileutils.h"
45 * @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
49 bool headBit(BitstreamIn_t
*stream
) {
50 int bytepos
= stream
->position
>> 3; // divide by 8
51 int bitpos
= (stream
->position
++) & 7; // mask out 00000111
52 return (*(stream
->buffer
+ bytepos
) >> (7 - bitpos
)) & 1;
55 * @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
59 bool tailBit(BitstreamIn_t
*stream
) {
60 int bitpos
= stream
->numbits
- 1 - (stream
->position
++);
62 int bytepos
= bitpos
>> 3;
64 return (*(stream
->buffer
+ bytepos
) >> (7 - bitpos
)) & 1;
67 * @brief Pushes bit onto the stream
71 void pushBit(BitstreamOut_t
*stream
, bool bit
) {
72 int bytepos
= stream
->position
>> 3; // divide by 8
73 int bitpos
= stream
->position
& 7;
74 *(stream
->buffer
+ bytepos
) |= (bit
) << (7 - bitpos
);
80 * @brief Pushes the lower six bits onto the stream
81 * as b0 b1 b2 b3 b4 b5 b6
85 void push6bits(BitstreamOut_t
*stream
, uint8_t bits
) {
86 pushBit(stream
, bits
& 0x20);
87 pushBit(stream
, bits
& 0x10);
88 pushBit(stream
, bits
& 0x08);
89 pushBit(stream
, bits
& 0x04);
90 pushBit(stream
, bits
& 0x02);
91 pushBit(stream
, bits
& 0x01);
97 * @return number of bits left in stream
99 int bitsLeft(BitstreamIn_t
*stream
) {
100 return stream
->numbits
- stream
->position
;
105 * @return Number of bits stored in stream
108 static int numBits(BitstreamOut_t *stream) {
109 return stream->numbits;
112 void x_num_to_bytes(uint64_t n
, size_t len
, uint8_t *dest
) {
114 dest
[len
] = (uint8_t) n
;
119 uint64_t x_bytes_to_num(uint8_t *src
, size_t len
) {
122 num
= (num
<< 8) | (*src
);
128 void printarr(const char *name
, uint8_t *arr
, int len
) {
129 if (name
== NULL
|| arr
== NULL
) return;
132 size_t outsize
= 40 + strlen(name
) + len
* 5;
133 char *output
= calloc(outsize
, sizeof(char));
134 cx
= snprintf(output
, outsize
, "uint8_t %s[] = {", name
);
135 for (i
= 0; i
< len
; i
++) {
137 cx
+= snprintf(output
+ cx
, outsize
- cx
, "0x%02x,", *(arr
+ i
)); //5 bytes per byte
140 snprintf(output
+ cx
, outsize
- cx
, "};");
141 PrintAndLogEx(INFO
, output
);
145 void printarr_human_readable(const char *title
, uint8_t *arr
, int len
) {
147 if (arr
== NULL
) return;
150 size_t outsize
= 100 + strlen(title
) + (len
* 4);
151 char *output
= calloc(outsize
, sizeof(char));
152 PrintAndLogEx(INFO
, "%s", title
);
153 for (i
= 0; i
< len
; i
++) {
158 cx
+= snprintf(output
+ cx
, outsize
- cx
, "%02x| ", i
);
161 cx
+= snprintf(output
+ cx
, outsize
- cx
, "\n%02x| ", i
);
165 cx
+= snprintf(output
+ cx
, outsize
- cx
, "%02x ", *(arr
+ i
));
167 PrintAndLogEx(INFO
, output
);
171 //-----------------------------
172 // Code for testing below
173 //-----------------------------
176 static int testBitStream(void) {
177 uint8_t input
[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
178 uint8_t output
[] = {0, 0, 0, 0, 0, 0, 0, 0};
179 BitstreamIn_t in
= { input
, sizeof(input
) * 8, 0};
180 BitstreamOut_t out
= { output
, 0, 0}
182 while (bitsLeft(&in
) > 0) {
183 pushBit(&out
, headBit(&in
));
184 //printf("Bits left: %d\n", bitsLeft(&in));
185 //printf("Bits out: %d\n", numBits(&out));
188 if (memcmp(input
, output
, sizeof(input
)) == 0) {
189 PrintAndLogEx(SUCCESS
, " Bitstream test 1 ( %s )", _GREEN_("ok"));
191 PrintAndLogEx(FAILED
, " Bitstream test 1 ( %s )", _RED_("fail"));
193 for (i
= 0 ; i
< ARRAYLEN(input
) ; i
++) {
194 PrintAndLogEx(NORMAL
, " IN %02x, OUT %02x", input
[i
], output
[i
]);
201 static int testReversedBitstream(void) {
202 uint8_t input
[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
203 uint8_t reverse
[] = {0, 0, 0, 0, 0, 0, 0, 0};
204 uint8_t output
[] = {0, 0, 0, 0, 0, 0, 0, 0};
205 BitstreamIn_t in
= { input
, sizeof(input
) * 8, 0};
206 BitstreamOut_t out
= { output
, 0, 0};
207 BitstreamIn_t reversed_in
= { reverse
, sizeof(input
) * 8, 0};
208 BitstreamOut_t reversed_out
= { reverse
, 0, 0};
210 while (bitsLeft(&in
) > 0) {
211 pushBit(&reversed_out
, tailBit(&in
));
214 while (bitsLeft(&reversed_in
) > 0) {
215 pushBit(&out
, tailBit(&reversed_in
));
218 if (memcmp(input
, output
, sizeof(input
)) == 0) {
219 PrintAndLogEx(SUCCESS
, " Bitstream test 2 ( %s )", _GREEN_("ok"));
221 PrintAndLogEx(FAILED
, " Bitstream test 2 ( %s )", _RED_("fail"));
223 for (i
= 0 ; i
< ARRAYLEN(input
) ; i
++) {
224 PrintAndLogEx(NORMAL
, " IN %02x, MIDDLE: %02x, OUT %02x", input
[i
], reverse
[i
], output
[i
]);
231 int testCipherUtils(void) {
232 PrintAndLogEx(INFO
, "Testing some internals...");
233 int retval
= testBitStream();
234 if (retval
== PM3_SUCCESS
)
235 retval
= testReversedBitstream();