fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / loclass / cipherutils.c
blob58875216b1a0ba0ad1b8a7dcc2abc2461774832e
1 /*****************************************************************************
2 * WARNING
4 * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
6 * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
7 * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
8 * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
10 * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
12 *****************************************************************************
14 * This file is part of loclass. It is a reconstructon of the cipher engine
15 * used in iClass, and RFID techology.
17 * The implementation is based on the work performed by
18 * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
19 * Milosch Meriac in the paper "Dismantling IClass".
21 * Copyright (C) 2014 Martin Holst Swende
23 * This is free software: you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License version 2 as published
25 * by the Free Software Foundation, or, at your option, any later version.
27 * This file is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with loclass. If not, see <http://www.gnu.org/licenses/>.
36 ****************************************************************************/
37 #include "cipherutils.h"
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include "util.h" // sprint_hex
43 #include "commonutil.h" // ARRAYLEN
45 #include "fileutils.h"
46 /**
48 * @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
49 * @param stream
50 * @return
52 bool headBit(BitstreamIn *stream) {
53 int bytepos = stream->position >> 3; // divide by 8
54 int bitpos = (stream->position++) & 7; // mask out 00000111
55 return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1;
57 /**
58 * @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
59 * @param stream
60 * @return
62 bool tailBit(BitstreamIn *stream) {
63 int bitpos = stream->numbits - 1 - (stream->position++);
65 int bytepos = bitpos >> 3;
66 bitpos &= 7;
67 return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1;
69 /**
70 * @brief Pushes bit onto the stream
71 * @param stream
72 * @param bit
74 void pushBit(BitstreamOut *stream, bool bit) {
75 int bytepos = stream->position >> 3; // divide by 8
76 int bitpos = stream->position & 7;
77 *(stream->buffer + bytepos) |= (bit) << (7 - bitpos);
78 stream->position++;
79 stream->numbits++;
82 /**
83 * @brief Pushes the lower six bits onto the stream
84 * as b0 b1 b2 b3 b4 b5 b6
85 * @param stream
86 * @param bits
88 void push6bits(BitstreamOut *stream, uint8_t bits) {
89 pushBit(stream, bits & 0x20);
90 pushBit(stream, bits & 0x10);
91 pushBit(stream, bits & 0x08);
92 pushBit(stream, bits & 0x04);
93 pushBit(stream, bits & 0x02);
94 pushBit(stream, bits & 0x01);
97 /**
98 * @brief bitsLeft
99 * @param stream
100 * @return number of bits left in stream
102 int bitsLeft(BitstreamIn *stream) {
103 return stream->numbits - stream->position;
106 * @brief numBits
107 * @param stream
108 * @return Number of bits stored in stream
111 static int numBits(BitstreamOut *stream) {
112 return stream->numbits;
115 void x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest) {
116 while (len--) {
117 dest[len] = (uint8_t) n;
118 n >>= 8;
122 uint64_t x_bytes_to_num(uint8_t *src, size_t len) {
123 uint64_t num = 0;
124 while (len--) {
125 num = (num << 8) | (*src);
126 src++;
128 return num;
131 void reverse_arraybytes(uint8_t *arr, size_t len) {
132 uint8_t i;
133 for (i = 0; i < len ; i++) {
134 arr[i] = reflect8(arr[i]);
138 void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) {
139 uint8_t i;
140 for (i = 0; i < len ; i++) {
141 dest[i] = reflect8(arr[i]);
145 void printarr(const char *name, uint8_t *arr, int len) {
146 if (name == NULL || arr == NULL) return;
148 int cx, i;
149 size_t outsize = 40 + strlen(name) + len * 5;
150 char *output = calloc(outsize, sizeof(char));
151 cx = snprintf(output, outsize, "uint8_t %s[] = {", name);
152 for (i = 0; i < len; i++) {
153 cx += snprintf(output + cx, outsize - cx, "0x%02x,", *(arr + i)); //5 bytes per byte
155 snprintf(output + cx, outsize - cx, "};");
156 PrintAndLogEx(INFO, output);
157 free(output);
160 void printarr_human_readable(const char *title, uint8_t *arr, int len) {
162 if (arr == NULL) return;
164 int cx = 0, i;
165 size_t outsize = 100 + strlen(title) + (len * 4);
166 char *output = calloc(outsize, sizeof(char));
167 PrintAndLogEx(INFO, "%s", title);
168 for (i = 0; i < len; i++) {
169 if (i % 16 == 0) {
171 if (i == 0)
172 cx += snprintf(output + cx, outsize - cx, "%02x| ", i);
173 else
174 cx += snprintf(output + cx, outsize - cx, "\n%02x| ", i);
176 cx += snprintf(output + cx, outsize - cx, "%02x ", *(arr + i));
178 PrintAndLogEx(INFO, output);
179 free(output);
182 //-----------------------------
183 // Code for testing below
184 //-----------------------------
186 #ifndef ON_DEVICE
187 static int testBitStream(void) {
188 uint8_t input [] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
189 uint8_t output [] = {0, 0, 0, 0, 0, 0, 0, 0};
190 BitstreamIn in = { input, sizeof(input) * 8, 0};
191 BitstreamOut out = { output, 0, 0}
193 while (bitsLeft(&in) > 0) {
194 pushBit(&out, headBit(&in));
195 //printf("Bits left: %d\n", bitsLeft(&in));
196 //printf("Bits out: %d\n", numBits(&out));
199 if (memcmp(input, output, sizeof(input)) == 0) {
200 PrintAndLogEx(SUCCESS, " Bitstream test 1 (%s)", _GREEN_("ok"));
201 } else {
202 PrintAndLogEx(FAILED, " Bitstream test 1 (%s)", _RED_("failed"));
203 uint8_t i;
204 for (i = 0 ; i < ARRAYLEN(input) ; i++) {
205 PrintAndLogEx(NORMAL, " IN %02x, OUT %02x", input[i], output[i]);
207 return PM3_ESOFT;
209 return PM3_SUCCESS;
212 static int testReversedBitstream(void) {
213 uint8_t input [] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
214 uint8_t reverse [] = {0, 0, 0, 0, 0, 0, 0, 0};
215 uint8_t output [] = {0, 0, 0, 0, 0, 0, 0, 0};
216 BitstreamIn in = { input, sizeof(input) * 8, 0};
217 BitstreamOut out = { output, 0, 0};
218 BitstreamIn reversed_in = { reverse, sizeof(input) * 8, 0};
219 BitstreamOut reversed_out = { reverse, 0, 0};
221 while (bitsLeft(&in) > 0) {
222 pushBit(&reversed_out, tailBit(&in));
225 while (bitsLeft(&reversed_in) > 0) {
226 pushBit(&out, tailBit(&reversed_in));
229 if (memcmp(input, output, sizeof(input)) == 0) {
230 PrintAndLogEx(SUCCESS, " Bitstream test 2 (%s)", _GREEN_("ok"));
231 } else {
232 PrintAndLogEx(FAILED, " Bitstream test 2 (%s)", _RED_("failed"));
233 uint8_t i;
234 for (i = 0 ; i < ARRAYLEN(input) ; i++) {
235 PrintAndLogEx(NORMAL, " IN %02x, MIDDLE: %02x, OUT %02x", input[i], reverse[i], output[i]);
237 return PM3_ESOFT;
239 return PM3_SUCCESS;
242 int testCipherUtils(void) {
243 PrintAndLogEx(INFO, "Testing some internals...");
244 int retval = testBitStream();
245 if (retval == PM3_SUCCESS)
246 retval = testReversedBitstream();
248 return retval;
250 #endif