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 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
19 #include "cipursetest.h"
22 #include <string.h> // memcpy memset
23 #include "fileutils.h"
25 #include "crypto/libpcrypto.h"
26 #include "cipurse/cipursecrypto.h"
27 #include "cipurse/cipursecore.h"
29 uint8_t Key
[] = CIPURSE_DEFAULT_KEY
;
30 uint8_t KeyKvv
[CIPURSE_KVV_LENGTH
] = {0x5f, 0xd6, 0x7b, 0xcb};
32 uint8_t TestRandom
[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22};
34 uint8_t TestData
[16] = {0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
35 uint8_t TestDataPadded
[16] = {0x11, 0x22, 0x33, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
37 static bool TestKVV(void) {
38 uint8_t kvv
[CIPURSE_KVV_LENGTH
] = {0};
39 CipurseCGetKVV(Key
, kvv
);
41 bool res
= memcmp(KeyKvv
, kvv
, CIPURSE_KVV_LENGTH
) == 0;
43 PrintAndLogEx(SUCCESS
, "kvv.............. ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
47 static bool TestISO9797M2(void) {
48 uint8_t data
[32] = {0};
51 AddISO9797M2Padding(data
, &ddatalen
, TestData
, 4, 16);
52 bool res
= (ddatalen
== 16);
53 res
= res
&& (memcmp(data
, TestDataPadded
, ddatalen
) == 0);
55 res
= res
&& (FindISO9797M2PaddingDataLen(data
, ddatalen
) == 4);
57 PrintAndLogEx(SUCCESS
, "ISO9797M2........ ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
61 static bool TestSMI(void) {
62 CipurseContext_t ctx
= {0};
63 CipurseCClearContext(&ctx
);
65 bool res
= (isCipurseCChannelSecuritySet(&ctx
) == false);
67 CipurseCChannelSetSecurityLevels(&ctx
, CPSPlain
, CPSPlain
);
68 res
= res
&& (CipurseCGetSMI(&ctx
, false) == 0x00);
69 res
= res
&& (CipurseCGetSMI(&ctx
, true) == 0x01);
71 CipurseCChannelSetSecurityLevels(&ctx
, CPSPlain
, CPSMACed
);
72 res
= res
&& (CipurseCGetSMI(&ctx
, false) == 0x04);
73 res
= res
&& (CipurseCGetSMI(&ctx
, true) == 0x05);
75 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSMACed
);
76 res
= res
&& (CipurseCGetSMI(&ctx
, false) == 0x44);
77 res
= res
&& (CipurseCGetSMI(&ctx
, true) == 0x45);
79 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSEncrypted
);
80 res
= res
&& (CipurseCGetSMI(&ctx
, false) == 0x48);
81 res
= res
&& (CipurseCGetSMI(&ctx
, true) == 0x49);
83 CipurseCChannelSetSecurityLevels(&ctx
, CPSEncrypted
, CPSEncrypted
);
84 res
= res
&& (CipurseCGetSMI(&ctx
, false) == 0x88);
85 res
= res
&& (CipurseCGetSMI(&ctx
, true) == 0x89);
87 PrintAndLogEx(SUCCESS
, "SMI.............. ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
91 static bool TestMIC(void) {
94 CipurseCGenerateMIC(TestData
, 4, mic
);
95 uint8_t valid_mic4
[4] = {0xD4, 0x71, 0xA7, 0x73};
96 bool res
= (memcmp(mic
, valid_mic4
, 4) == 0);
98 res
= res
&& (CipurseCCheckMIC(TestData
, 4, mic
));
100 CipurseCGenerateMIC(TestData
, 6, mic
);
101 uint8_t valid_mic6
[4] = {0xAA, 0x90, 0xFC, 0x5A};
102 res
= res
&& (memcmp(mic
, valid_mic6
, 4) == 0);
104 res
= res
&& (CipurseCCheckMIC(TestData
, 6, mic
));
106 PrintAndLogEx(SUCCESS
, "MIC.............. ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
110 static bool TestAuth(void) {
111 CipurseContext_t ctx
= {0};
112 CipurseCClearContext(&ctx
);
114 bool res
= (isCipurseCChannelSecuritySet(&ctx
) == false);
116 CipurseCSetKey(&ctx
, 1, Key
);
117 res
= res
&& (memcmp(ctx
.key
, Key
, 16) == 0);
118 res
= res
&& (ctx
.keyId
== 1);
120 CipurseCSetRandomFromPICC(&ctx
, TestRandom
);
121 res
= res
&& (memcmp(ctx
.RP
, TestRandom
, 16) == 0);
122 res
= res
&& (memcmp(ctx
.rP
, &TestRandom
[16], 6) == 0);
124 uint8_t hrandom
[] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
125 CipurseCSetRandomHost(&ctx
);
126 res
= res
&& (memcmp(ctx
.RT
, hrandom
, 16) == 0);
127 res
= res
&& (memcmp(ctx
.rT
, &hrandom
[16], 6) == 0);
129 uint8_t authparams
[16 + 16 + 6] = {0};
130 CipurseCAuthenticateHost(&ctx
, authparams
);
131 uint8_t aparamstest
[] = {0x12, 0xAA, 0x79, 0xA9, 0x03, 0xC5, 0xB4, 0x6A, 0x27, 0x1B, 0x13, 0xAE, 0x02, 0x50, 0x1C, 0x99, 0x10, 0x10, 0x10, 0x10, 0x10,
132 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
134 res
= res
&& (memcmp(authparams
, aparamstest
, sizeof(authparams
)) == 0);
136 uint8_t ct
[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
137 res
= res
&& CipurseCCheckCT(&ctx
, ct
);
139 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSMACed
);
140 res
= res
&& (isCipurseCChannelSecuritySet(&ctx
) == true);
142 uint8_t framekey
[] = {0xCF, 0x6F, 0x3A, 0x47, 0xFC, 0xAC, 0x8D, 0x38, 0x25, 0x75, 0x8B, 0xFC, 0x8B, 0x61, 0x68, 0xF3};
143 res
= res
&& (memcmp(ctx
.frameKey
, framekey
, sizeof(framekey
)) == 0);
145 PrintAndLogEx(SUCCESS
, "Auth............. ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
149 static bool TestMAC(void) {
150 CipurseContext_t ctx
= {0};
153 CipurseCClearContext(&ctx
);
154 CipurseCSetKey(&ctx
, 1, Key
);
155 CipurseCSetRandomFromPICC(&ctx
, TestRandom
);
156 uint8_t authparams
[16 + 16 + 6] = {0};
157 CipurseCAuthenticateHost(&ctx
, authparams
);
158 uint8_t ct
[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
159 bool res
= CipurseCCheckCT(&ctx
, ct
);
160 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSMACed
);
161 res
= res
&& (isCipurseCChannelSecuritySet(&ctx
) == true);
164 uint8_t mac
[8] = {0};
166 CipurseCGenerateMAC(&ctx
, TestData
, 4, mac
);
167 uint8_t testmac1
[8] = {0xAB, 0x5C, 0x86, 0x18, 0x7F, 0x73, 0xEC, 0x4E};
168 res
= res
&& (memcmp(mac
, testmac1
, 8) == 0);
170 uint8_t framekey1
[] = {0x7D, 0x6F, 0x31, 0x40, 0xC8, 0x47, 0xED, 0x3F, 0x0A, 0x21, 0xE6, 0xFB, 0xC7, 0xDB, 0x27, 0xB0};
171 res
= res
&& (memcmp(ctx
.frameKey
, framekey1
, sizeof(framekey1
)) == 0);
173 CipurseCCalcMACPadded(&ctx
, TestData
, 4, mac
);
174 uint8_t testmac2
[8] = {0x9F, 0xE9, 0x54, 0xBF, 0xFC, 0xA0, 0x7D, 0x75};
175 res
= res
&& (memcmp(mac
, testmac2
, 8) == 0);
177 uint8_t framekey2
[] = {0x1E, 0xD4, 0xB6, 0x87, 0x85, 0x93, 0x5B, 0xAF, 0xA9, 0xF2, 0xF0, 0x8F, 0xA9, 0xF0, 0xA5, 0xFB};
178 res
= res
&& (memcmp(ctx
.frameKey
, framekey2
, sizeof(framekey2
)) == 0);
180 CipurseCCalcMACPadded(&ctx
, TestData
, 4, mac
);
181 uint8_t testmac3
[8] = {0x15, 0x6F, 0x08, 0x5C, 0x0F, 0x80, 0xE7, 0x07};
182 res
= res
&& (memcmp(mac
, testmac3
, 8) == 0);
184 uint8_t framekey3
[] = {0x0C, 0x42, 0x93, 0x73, 0x88, 0x8F, 0x63, 0xB3, 0x10, 0x8E, 0xDF, 0xDB, 0xC1, 0x20, 0x63, 0x4C};
185 res
= res
&& (memcmp(ctx
.frameKey
, framekey3
, sizeof(framekey3
)) == 0);
187 uint8_t testmac4
[8] = {0x0E, 0xF0, 0x70, 0xA6, 0xA1, 0x15, 0x9A, 0xB6};
188 res
= res
&& CipurseCCheckMACPadded(&ctx
, TestData
, 4, testmac4
);
190 uint8_t framekey4
[] = {0xA0, 0x65, 0x1A, 0x62, 0x56, 0x5D, 0xD7, 0xC9, 0x32, 0xAE, 0x1D, 0xE0, 0xCF, 0x8D, 0xC1, 0xB9};
191 res
= res
&& (memcmp(ctx
.frameKey
, framekey4
, sizeof(framekey4
)) == 0);
193 PrintAndLogEx(SUCCESS
, "channel MAC...... ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
197 static bool TestEncDec(void) {
198 CipurseContext_t ctx
= {0};
201 CipurseCClearContext(&ctx
);
202 CipurseCSetKey(&ctx
, 1, Key
);
203 CipurseCSetRandomFromPICC(&ctx
, TestRandom
);
204 uint8_t authparams
[16 + 16 + 6] = {0};
205 CipurseCAuthenticateHost(&ctx
, authparams
);
206 uint8_t ct
[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
207 bool res
= CipurseCCheckCT(&ctx
, ct
);
208 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSMACed
);
209 res
= res
&& (isCipurseCChannelSecuritySet(&ctx
) == true);
211 // check Encode-Decode
212 uint8_t dstdata
[32] = {0};
213 size_t dstdatalen
= 0;
215 CipurseCEncryptDecrypt(&ctx
, TestData
, 16, dstdata
, true);
216 uint8_t tested1
[16] = {0x5F, 0x01, 0x18, 0x79, 0xE0, 0x57, 0xA7, 0xE5, 0x34, 0x39, 0x6E, 0x32, 0x62, 0xF2, 0x71, 0x27};
217 res
= res
&& (memcmp(dstdata
, tested1
, 16) == 0);
219 uint8_t tested2
[16] = {0xA6, 0x22, 0xB5, 0xCF, 0xE8, 0x6E, 0x67, 0xF4, 0xAA, 0x88, 0xB1, 0x19, 0x87, 0xCF, 0xC9, 0xD2};
220 CipurseCEncryptDecrypt(&ctx
, tested2
, 16, dstdata
, false);
221 res
= res
&& (memcmp(dstdata
, TestData
, 16) == 0);
223 CipurseCChannelEncrypt(&ctx
, TestData
, 16, dstdata
, &dstdatalen
);
224 uint8_t tested3
[32] = {0x1E, 0x0C, 0xD1, 0xF5, 0x8E, 0x0B, 0xAE, 0xF0, 0x06, 0xC6, 0xED, 0x73, 0x3F, 0x8A, 0x87, 0xCF,
225 0x36, 0xCC, 0xF2, 0xF4, 0x7D, 0x33, 0x50, 0xF1, 0x8E, 0xFF, 0xD1, 0x7D, 0x42, 0x88, 0xD5, 0xEE
227 res
= res
&& (dstdatalen
== 32);
228 res
= res
&& (memcmp(dstdata
, tested3
, 32) == 0);
230 uint8_t tested4
[32] = {0xC0, 0x42, 0xDB, 0xD9, 0x53, 0xFF, 0x01, 0xE5, 0xCC, 0x49, 0x8C, 0x9C, 0xDA, 0x60, 0x73, 0xA7,
231 0xE1, 0xEB, 0x14, 0x69, 0xF6, 0x39, 0xF3, 0xE1, 0x07, 0x03, 0x32, 0xF4, 0x27, 0xF9, 0x48, 0x3D
233 CipurseCChannelDecrypt(&ctx
, tested4
, 32, dstdata
, &dstdatalen
);
234 res
= res
&& (dstdatalen
== 16);
235 res
= res
&& (memcmp(dstdata
, TestData
, 16) == 0);
237 PrintAndLogEx(SUCCESS
, "channel EncDec... ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
241 //void CipurseCAPDUReqEncode(CipurseContext_t *ctx, sAPDU_t *srcapdu, sAPDU_t *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le);
242 //void CipurseCAPDURespDecode(CipurseContext_t *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw);
243 static bool TestAPDU(void) {
244 CipurseContext_t ctx
= {0};
247 CipurseCClearContext(&ctx
);
248 CipurseCSetKey(&ctx
, 1, Key
);
249 CipurseCSetRandomFromPICC(&ctx
, TestRandom
);
250 uint8_t authparams
[16 + 16 + 6] = {0};
251 CipurseCAuthenticateHost(&ctx
, authparams
);
252 uint8_t ct
[] = {0xBE, 0x10, 0x6B, 0xB9, 0xAD, 0x84, 0xBC, 0xE1, 0x9F, 0xAE, 0x0C, 0x62, 0xCC, 0xC7, 0x0D, 0x41};
253 bool res
= CipurseCCheckCT(&ctx
, ct
);
254 CipurseCChannelSetSecurityLevels(&ctx
, CPSMACed
, CPSMACed
);
255 res
= res
&& (isCipurseCChannelSecuritySet(&ctx
) == true);
257 // check APDU formatting
258 sAPDU_t srcAPDU
= {0};
259 sAPDU_t dstAPDU
= {0};
260 uint8_t dstdata
[256] = {0};
261 size_t dstdatalen
= 0;
268 srcAPDU
.data
= TestData
;
271 CipurseCAPDUReqEncode(&ctx
, &srcAPDU
, &dstAPDU
, dstdata
, true, 0x88);
272 uint8_t test1
[] = {0x45, 0x11, 0x22, 0x33, 0x44, 0x00, 0x88, 0x79, 0x2B, 0xB7, 0xDD, 0xD1, 0x69, 0xA6, 0x66};
273 res
= res
&& ((srcAPDU
.CLA
| 0x04) == dstAPDU
.CLA
);
274 res
= res
&& (srcAPDU
.INS
== dstAPDU
.INS
);
275 res
= res
&& (srcAPDU
.P1
== dstAPDU
.P1
);
276 res
= res
&& (srcAPDU
.P2
== dstAPDU
.P2
);
277 res
= res
&& (dstAPDU
.Lc
== sizeof(test1
));
278 res
= res
&& (memcmp(dstdata
, test1
, sizeof(test1
)) == 0);
281 uint8_t test2
[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x9D, 0x80, 0xE7, 0xE3, 0x34, 0xE9, 0x97, 0x82, 0xdd, 0xee};
282 CipurseCAPDURespDecode(&ctx
, test2
, sizeof(test2
), dstdata
, &dstdatalen
, &sw
);
283 res
= res
&& (dstdatalen
== 6);
284 res
= res
&& (memcmp(test2
, dstdata
, dstdatalen
) == 0);
285 res
= res
&& (sw
== 0xddee);
288 CipurseCChannelSetSecurityLevels(&ctx
, CPSPlain
, CPSPlain
);
289 CipurseCAPDUReqEncode(&ctx
, &srcAPDU
, &dstAPDU
, dstdata
, true, 0x55);
290 uint8_t test3
[] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x00, 0x55};
291 res
= res
&& ((srcAPDU
.CLA
| 0x04) == dstAPDU
.CLA
);
292 res
= res
&& (srcAPDU
.INS
== dstAPDU
.INS
);
293 res
= res
&& (srcAPDU
.P1
== dstAPDU
.P1
);
294 res
= res
&& (srcAPDU
.P2
== dstAPDU
.P2
);
295 res
= res
&& (dstAPDU
.Lc
== sizeof(test3
));
296 res
= res
&& (memcmp(dstdata
, test3
, sizeof(test3
)) == 0);
298 uint8_t test4
[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xcc, 0xdd};
299 CipurseCAPDURespDecode(&ctx
, test4
, sizeof(test4
), dstdata
, &dstdatalen
, &sw
);
300 res
= res
&& (dstdatalen
== 6);
301 res
= res
&& (memcmp(test4
, dstdata
, dstdatalen
) == 0);
302 res
= res
&& (sw
== 0xccdd);
305 CipurseCChannelSetSecurityLevels(&ctx
, CPSEncrypted
, CPSEncrypted
);
306 CipurseCAPDUReqEncode(&ctx
, &srcAPDU
, &dstAPDU
, dstdata
, true, 0x55);
307 uint8_t test5
[] = {0x89, 0x7D, 0xED, 0x0D, 0x04, 0x8E, 0xE1, 0x99, 0x08, 0x70, 0x56, 0x7C, 0xEE, 0x67, 0xB3, 0x33, 0x6F, 0x00};
308 res
= res
&& ((srcAPDU
.CLA
| 0x04) == dstAPDU
.CLA
);
309 res
= res
&& (srcAPDU
.INS
== dstAPDU
.INS
);
310 res
= res
&& (srcAPDU
.P1
== dstAPDU
.P1
);
311 res
= res
&& (srcAPDU
.P2
== dstAPDU
.P2
);
312 res
= res
&& (dstAPDU
.Lc
== sizeof(test5
));
313 res
= res
&& (memcmp(dstdata
, test5
, sizeof(test5
)) == 0);
315 uint8_t test6
[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x7E, 0x4B, 0xA0, 0xB7, 0xcc, 0xdd};
316 //CipurseCChannelEncrypt(&ctx, test6, sizeof(test6), dstdata, &dstdatalen);
317 //PrintAndLogEx(INFO, "dstdata[%d]: %s", dstdatalen, sprint_hex(dstdata, dstdatalen));
319 uint8_t test7
[] = {0x07, 0xEF, 0x16, 0x91, 0xE7, 0x0F, 0xB5, 0x10, 0x63, 0xCE, 0x66, 0xDB, 0x3B, 0xC6, 0xD4, 0xE0, 0x90, 0x00};
320 CipurseCAPDURespDecode(&ctx
, test7
, sizeof(test7
), dstdata
, &dstdatalen
, &sw
);
321 res
= res
&& (dstdatalen
== 8);
322 res
= res
&& (memcmp(test6
, dstdata
, dstdatalen
) == 0);
323 res
= res
&& (sw
== 0xccdd);
325 PrintAndLogEx(SUCCESS
, "apdu............. ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
329 bool CIPURSETest(bool verbose
) {
332 PrintAndLogEx(INFO
, "------ " _CYAN_("CIPURSE tests") " ------");
334 res
= res
&& TestKVV();
335 res
= res
&& TestISO9797M2();
336 res
= res
&& TestSMI();
337 res
= res
&& TestMIC();
338 res
= res
&& TestAuth();
339 res
= res
&& TestMAC();
340 res
= res
&& TestEncDec();
341 res
= res
&& TestAPDU();
343 PrintAndLogEx(INFO
, "---------------------------");
344 PrintAndLogEx(SUCCESS
, "Tests ( %s )", (res
) ? _GREEN_("ok") : _RED_("fail"));
345 PrintAndLogEx(NORMAL
, "");