1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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"
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
) {
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
71 void LRPGeneratePlaintexts(LRPContext_t
*ctx
, size_t plaintextsCount
) {
72 if (plaintextsCount
> LRP_MAX_PLAINTEXTS_SIZE
)
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
88 void LRPGenerateUpdatedKeys(LRPContext_t
*ctx
, size_t updatedKeysCount
) {
89 if (updatedKeysCount
> LRP_MAX_UPDATED_KEYS_SIZE
)
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
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
);
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
) {
121 for (int i
= ctrlen
- 1; i
>= 0; i
--) {
122 uint8_t nk
= (i
% 2) ? ctr
[i
/ 2] & 0x0f : (ctr
[i
/ 2] >> 4) & 0x0f;
129 ctr
[i
/ 2] = (ctr
[i
/ 2] & 0xf0) | (nk
& 0x0f);
131 ctr
[i
/ 2] = (ctr
[i
/ 2] & 0x0f) | ((nk
<< 4) & 0xf0);
138 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
140 void LRPEncode(LRPContext_t
*ctx
, uint8_t *data
, size_t datalen
, uint8_t *resp
, size_t *resplen
) {
143 if ((datalen
> 0) && (data
== NULL
)) {
146 uint8_t xdata
[1024] = {0};
147 memcpy(xdata
, data
, datalen
);
148 if (ctx
->useBitPadding
) {
149 xdata
[datalen
] = 0x80;
153 if (datalen
% CRYPTO_AES128_KEY_SIZE
)
154 datalen
= datalen
+ CRYPTO_AES128_KEY_SIZE
- (datalen
% CRYPTO_AES128_KEY_SIZE
);
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
170 void LRPDecode(LRPContext_t
*ctx
, uint8_t *data
, size_t datalen
, uint8_t *resp
, size_t *resplen
) {
172 if (datalen
% CRYPTO_AES128_KEY_SIZE
)
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
);
184 if (ctx
->useBitPadding
) {
185 for (int i
= *resplen
- 1; i
>= *resplen
- CRYPTO_AES128_KEY_SIZE
; i
--) {
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);
199 LRPEncode(&ctx
, data
, datalen
, resp
, resplen
);
201 LRPDecode(&ctx
, data
, datalen
, resp
, resplen
);
204 static bool shiftLeftBe(uint8_t *data
, size_t length
) {
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);
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
);
234 memcpy(sk1
, y
, CRYPTO_AES128_KEY_SIZE
);
237 memcpy(sk2
, y
, CRYPTO_AES128_KEY_SIZE
);
240 // https://www.nxp.com/docs/en/application-note/AN12304.pdf
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};
249 for (int i
= 0; i
< datalen
/ CRYPTO_AES128_KEY_SIZE
; i
++) {
250 if (datalen
- clen
<= CRYPTO_AES128_KEY_SIZE
)
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
);
265 bin_xor(y
, bl
, CRYPTO_AES128_KEY_SIZE
);
267 bin_xor(y
, sk1
, CRYPTO_AES128_KEY_SIZE
);
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];