style
[RRG-proxmark3.git] / client / src / mifare / lrpcrypto.c
blob678bc871195651b2df6da4c350bf4fb202e4213a
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // description here: Leakage Resilient Primitive (LRP) Specification, https://www.nxp.com/docs/en/application-note/AN12304.pdf
17 //-----------------------------------------------------------------------------
19 #include "lrpcrypto.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <util.h>
24 #include "ui.h"
25 #include "aes.h"
26 #include "commonutil.h"
28 static uint8_t constAA[] = {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
29 static uint8_t const55[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
30 static uint8_t const00[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
32 void LRPClearContext(LRPContext_t *ctx) {
33 memset(ctx->key, 0, CRYPTO_AES128_KEY_SIZE);
35 ctx->useBitPadding = false;
36 ctx->plaintextsCount = 0;
37 memset(ctx->plaintexts, 0, LRP_MAX_PLAINTEXTS_SIZE * CRYPTO_AES128_KEY_SIZE);
38 ctx->updatedKeysCount = 0;
39 memset(ctx->updatedKeys, 0, LRP_MAX_UPDATED_KEYS_SIZE * CRYPTO_AES128_KEY_SIZE);
40 ctx->useUpdatedKeyNum = 0;
43 void LRPSetKey(LRPContext_t *ctx, uint8_t *key, size_t updatedKeyNum, bool useBitPadding) {
44 LRPClearContext(ctx);
46 memcpy(ctx->key, key, CRYPTO_AES128_KEY_SIZE);
48 LRPGeneratePlaintexts(ctx, 16);
49 LRPGenerateUpdatedKeys(ctx, 4);
51 ctx->useUpdatedKeyNum = updatedKeyNum;
52 ctx->useBitPadding = useBitPadding;
54 memcpy(ctx->counter, const00, CRYPTO_AES128_KEY_SIZE);
55 ctx->counterLenNibbles = CRYPTO_AES128_KEY_SIZE;
58 void LRPSetCounter(LRPContext_t *ctx, uint8_t *counter, size_t counterLenNibbles) {
59 memcpy(ctx->counter, counter, counterLenNibbles / 2);
60 ctx->counterLenNibbles = counterLenNibbles;
63 void LRPSetKeyEx(LRPContext_t *ctx, uint8_t *key, uint8_t *counter, size_t counterLenNibbles, size_t updatedKeyNum, bool useBitPadding) {
64 LRPSetKey(ctx, key, updatedKeyNum, useBitPadding);
65 LRPSetCounter(ctx, counter, counterLenNibbles);
69 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
70 // Algorithm 1
71 void LRPGeneratePlaintexts(LRPContext_t *ctx, size_t plaintextsCount) {
72 if (plaintextsCount > LRP_MAX_PLAINTEXTS_SIZE)
73 return;
75 uint8_t h[CRYPTO_AES128_KEY_SIZE] = {0};
76 memcpy(h, ctx->key, CRYPTO_AES128_KEY_SIZE);
78 for (int i = 0; i < plaintextsCount; i++) {
79 aes_encode(NULL, h, const55, h, CRYPTO_AES128_KEY_SIZE);
80 aes_encode(NULL, h, constAA, ctx->plaintexts[i], CRYPTO_AES128_KEY_SIZE);
83 ctx->plaintextsCount = plaintextsCount;
86 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
87 // Algorithm 2
88 void LRPGenerateUpdatedKeys(LRPContext_t *ctx, size_t updatedKeysCount) {
89 if (updatedKeysCount > LRP_MAX_UPDATED_KEYS_SIZE)
90 return;
92 uint8_t h[CRYPTO_AES128_KEY_SIZE] = {0};
93 aes_encode(NULL, ctx->key, constAA, h, CRYPTO_AES128_KEY_SIZE);
95 for (int i = 0; i < updatedKeysCount; i++) {
96 aes_encode(NULL, h, constAA, ctx->updatedKeys[i], CRYPTO_AES128_KEY_SIZE);
97 aes_encode(NULL, h, const55, h, CRYPTO_AES128_KEY_SIZE);
100 ctx->updatedKeysCount = updatedKeysCount;
103 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
104 // Algorithm 3
105 void LRPEvalLRP(LRPContext_t *ctx, const uint8_t *iv, size_t ivlen, bool final, uint8_t *y) {
106 uint8_t ry[CRYPTO_AES128_KEY_SIZE] = {0};
107 memcpy(ry, ctx->updatedKeys[ctx->useUpdatedKeyNum], CRYPTO_AES128_KEY_SIZE);
109 for (int i = 0; i < ivlen; i++) {
110 uint8_t nk = (i % 2) ? iv[i / 2] & 0x0f : (iv[i / 2] >> 4) & 0x0f;
111 aes_encode(NULL, ry, ctx->plaintexts[nk], ry, CRYPTO_AES128_KEY_SIZE);
114 if (final)
115 aes_encode(NULL, ry, const00, ry, CRYPTO_AES128_KEY_SIZE);
116 memcpy(y, ry, CRYPTO_AES128_KEY_SIZE);
119 void LRPIncCounter(uint8_t *ctr, size_t ctrlen) {
120 bool carry = true;
121 for (int i = ctrlen - 1; i >= 0; i--) {
122 uint8_t nk = (i % 2) ? ctr[i / 2] & 0x0f : (ctr[i / 2] >> 4) & 0x0f;
124 if (carry)
125 nk++;
127 carry = (nk > 0xf);
128 if (i % 2)
129 ctr[i / 2] = (ctr[i / 2] & 0xf0) | (nk & 0x0f);
130 else
131 ctr[i / 2] = (ctr[i / 2] & 0x0f) | ((nk << 4) & 0xf0);
133 if (!carry)
134 break;
138 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
139 // Algorithm 4
140 void LRPEncode(LRPContext_t *ctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
141 *resplen = 0;
143 if ((datalen > 0) && (data == NULL)) {
144 return;
146 uint8_t xdata[1024] = {0};
147 memcpy(xdata, data, datalen);
148 if (ctx->useBitPadding) {
149 xdata[datalen] = 0x80;
150 datalen++;
153 if (datalen % CRYPTO_AES128_KEY_SIZE)
154 datalen = datalen + CRYPTO_AES128_KEY_SIZE - (datalen % CRYPTO_AES128_KEY_SIZE);
156 if (datalen == 0)
157 return;
159 uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0};
160 for (int i = 0; i < datalen / CRYPTO_AES128_KEY_SIZE; i++) {
161 LRPEvalLRP(ctx, ctx->counter, ctx->counterLenNibbles, true, y);
162 aes_encode(NULL, y, &xdata[i * CRYPTO_AES128_KEY_SIZE], &resp[i * CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
163 *resplen += CRYPTO_AES128_KEY_SIZE;
164 LRPIncCounter(ctx->counter, ctx->counterLenNibbles);
168 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
169 // Algorithm 5
170 void LRPDecode(LRPContext_t *ctx, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
171 *resplen = 0;
172 if (datalen % CRYPTO_AES128_KEY_SIZE)
173 return;
175 uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0};
176 for (int i = 0; i < datalen / CRYPTO_AES128_KEY_SIZE; i++) {
177 LRPEvalLRP(ctx, ctx->counter, ctx->counterLenNibbles, true, y);
178 aes_decode(NULL, y, &data[i * CRYPTO_AES128_KEY_SIZE], &resp[i * CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
179 *resplen += CRYPTO_AES128_KEY_SIZE;
180 LRPIncCounter(ctx->counter, ctx->counterLenNibbles);
183 // search padding
184 if (ctx->useBitPadding) {
185 for (int i = *resplen - 1; i >= *resplen - CRYPTO_AES128_KEY_SIZE; i--) {
186 if (resp[i] == 0x80)
187 *resplen = i;
188 if (resp[i] != 0x00)
189 break;
194 void LRPEncDec(uint8_t *key, uint8_t *iv, bool encode, uint8_t *data, size_t datalen, uint8_t *resp, size_t *resplen) {
195 LRPContext_t ctx = {0};
197 LRPSetKeyEx(&ctx, key, iv, 4 * 2, 1, true);
198 if (encode)
199 LRPEncode(&ctx, data, datalen, resp, resplen);
200 else
201 LRPDecode(&ctx, data, datalen, resp, resplen);
204 static bool shiftLeftBe(uint8_t *data, size_t length) {
205 if (length == 0)
206 return false;
208 bool carry = false;
209 for (int i = length - 1; i >= 0; i--) {
210 uint8_t val = data[i];
211 val = (val << 1) | ((carry) ? 1 : 0);
212 carry = ((data[i] & 0x80) != 0);
213 data[i] = val;
215 return carry;
218 // GF(2 ^ 128)
219 // poly x^128 + x ^ 7 + x ^ 2 + x + 1
220 // bit: 1000..0010000111 == 0x1 00 00 .. 00 00 87
221 static void mulPolyX(uint8_t *data) {
222 if (shiftLeftBe(data, 16))
223 data[15] = data[15] ^ 0x87;
226 void LRPGenSubkeys(uint8_t *key, uint8_t *sk1, uint8_t *sk2) {
227 LRPContext_t ctx = {0};
228 LRPSetKey(&ctx, key, 0, true);
230 uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0};
231 LRPEvalLRP(&ctx, const00, CRYPTO_AES128_KEY_SIZE * 2, true, y);
233 mulPolyX(y);
234 memcpy(sk1, y, CRYPTO_AES128_KEY_SIZE);
236 mulPolyX(y);
237 memcpy(sk2, y, CRYPTO_AES128_KEY_SIZE);
240 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
241 // Algorithm 6
242 void LRPCMAC(LRPContext_t *ctx, uint8_t *data, size_t datalen, uint8_t *cmac) {
243 uint8_t sk1[CRYPTO_AES128_KEY_SIZE] = {0};
244 uint8_t sk2[CRYPTO_AES128_KEY_SIZE] = {0};
245 LRPGenSubkeys(ctx->key, sk1, sk2);
247 uint8_t y[CRYPTO_AES128_KEY_SIZE] = {0};
248 size_t clen = 0;
249 for (int i = 0; i < datalen / CRYPTO_AES128_KEY_SIZE; i++) {
250 if (datalen - clen <= CRYPTO_AES128_KEY_SIZE)
251 break;
253 bin_xor(y, &data[i * CRYPTO_AES128_KEY_SIZE], CRYPTO_AES128_KEY_SIZE);
254 LRPEvalLRP(ctx, y, CRYPTO_AES128_KEY_SIZE * 2, true, y);
255 clen += CRYPTO_AES128_KEY_SIZE;
258 size_t bllen = datalen - clen;
259 bllen = MIN(bllen, CRYPTO_AES128_KEY_SIZE); // coverity
260 uint8_t bl[CRYPTO_AES128_KEY_SIZE] = {0};
261 memcpy(bl, &data[clen], bllen);
263 // last block
264 if (bllen == 16) {
265 bin_xor(y, bl, CRYPTO_AES128_KEY_SIZE);
267 bin_xor(y, sk1, CRYPTO_AES128_KEY_SIZE);
268 } else {
269 // padding
270 bl[bllen] = 0x80;
271 bin_xor(y, bl, CRYPTO_AES128_KEY_SIZE);
273 bin_xor(y, sk2, CRYPTO_AES128_KEY_SIZE);
276 LRPEvalLRP(ctx, y, CRYPTO_AES128_KEY_SIZE * 2, true, cmac);
279 void LRPCMAC8(LRPContext_t *ctx, uint8_t *data, size_t datalen, uint8_t *cmac) {
280 uint8_t cmac_tmp[16] = {0};
281 memset(cmac, 0x00, 8);
283 LRPCMAC(ctx, data, datalen, cmac_tmp);
285 for (int i = 0; i < 8; i++)
286 cmac[i] = cmac_tmp[i * 2 + 1];