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 // Support functions for smart card
17 //-----------------------------------------------------------------------------
18 #include "cardhelper.h"
21 #include "cmdparser.h"
22 #include "cmdsmartcard.h"
25 #include "commonutil.h"
27 #define CARD_INS_DECRYPT 0x01
28 #define CARD_INS_ENCRYPT 0x02
29 #define CARD_INS_VERIFY_RRG 0x05
30 #define CARD_INS_DECODE 0x06
31 #define CARD_INS_NUMBLOCKS 0x07
32 #define CARD_INS_PINSIZE 0x08
33 #define CARD_INS_CC 0x81
34 #define CARD_INS_CC_DESC 0x82
36 // look for CardHelper
37 bool IsCardHelperPresent(bool verbose
) {
39 if (IfPm3Smartcard() == false) {
44 uint8_t version
[] = {0x96, 0x69, 0x00, 0x00, 0x00};
45 uint8_t resp
[30] = {0};
46 ExchangeAPDUSC(verbose
, version
, sizeof(version
), true, true, resp
, sizeof(resp
), &resp_len
);
52 if (strstr("CryptoHelper", (char *)resp
) == 0) {
54 PrintAndLogEx(INFO
, "Found smart card helper");
61 bool IsHIDSamPresent(bool verbose
) {
63 if (IfPm3Smartcard() == false) {
64 PrintAndLogEx(WARNING
, "Proxmark3 does not have SMARTCARD support enabled, exiting");
69 smart_card_atr_t card
;
70 smart_select(verbose
, &card
);
71 if (card
.atr_len
== 0) {
72 PrintAndLogEx(ERR
, "Can't get ATR from a smart card");
77 smart_card_atr_t supported
[] = {
78 {15, {0x3B, 0x95, 0x96, 0x80, 0xB1, 0xFE, 0x55, 0x1F, 0xC7, 0x47, 0x72, 0x61, 0x63, 0x65, 0x13}},
79 {11, {0x3b, 0x90, 0x96, 0x91, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0xd4}},
82 for (int i
= 0; i
< ARRAYLEN(supported
); i
++) {
83 if ((card
.atr_len
== supported
[i
].atr_len
) &&
84 (memcmp(card
.atr
, supported
[i
].atr
, supported
[i
].atr_len
) == 0)) {
91 PrintAndLogEx(SUCCESS
, "Not detecting a SAM");
96 // Suspect some SAMs has version name in the historical bytes
97 uint8_t T0
= card
.atr
[1];
98 uint8_t K
= T0
& 0x0F; // Number of historical bytes
99 if (K
> 0 && (K
< (card
.atr_len
- 3)) && verbose
) {
100 // Last byte of ATR is CRC and before that we have K bytes of
101 // "historical bytes".
102 // By construction K can't go above 15
103 char sam_name
[16] = {0};
104 memcpy(sam_name
, &card
.atr
[card
.atr_len
- 1 - K
], K
);
105 PrintAndLogEx(SUCCESS
, "SAM (%s) detected", sam_name
);
110 static bool executeCrypto(uint8_t ins
, uint8_t *src
, uint8_t *dest
) {
111 uint8_t cmd
[] = {0x96, ins
, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
112 memcpy(cmd
+ 5, src
, 8);
115 uint8_t dec
[11] = {0};
116 ExchangeAPDUSC(false, cmd
, sizeof(cmd
), true, true, dec
, sizeof(dec
), &resp_len
);
117 if (resp_len
== 10) {
118 memcpy(dest
, dec
, 8);
124 bool Decrypt(uint8_t *src
, uint8_t *dest
) {
125 return executeCrypto(CARD_INS_DECRYPT
, src
, dest
);
128 bool Encrypt(uint8_t *src
, uint8_t *dest
) {
129 return executeCrypto(CARD_INS_ENCRYPT
, src
, dest
);
133 void DecodeBlock6(uint8_t *src
) {
135 uint8_t c
[] = {0x96, CARD_INS_DECODE
, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
136 memcpy(c
+ 6, src
, 8);
139 uint8_t resp
[254] = {0};
142 ExchangeAPDUSC(false, c
, sizeof(c
), false, true, resp
, sizeof(resp
), &resp_len
);
145 PrintAndLogEx(DEBUG
, "decodeblock6, wrong response len, expected 11 got ( " _RED_("%d") " )", resp_len
);
149 PrintAndLogEx(SUCCESS
, "%.*s", resp_len
- 11, resp
+ 9);
153 ExchangeAPDUSC(false, c
, sizeof(c
), false, false, resp
, sizeof(resp
), &resp_len
);
156 PrintAndLogEx(DEBUG
, "decodeblock6, wrong response len, expected 11 got ( " _RED_("%d") " )", resp_len
);
160 PrintAndLogEx(SUCCESS
, "%.*s", resp_len
- 11, resp
+ 9);
164 uint8_t GetNumberBlocksForUserId(uint8_t *src
) {
166 uint8_t resp
[254] = {0};
167 uint8_t c
[] = {0x96, CARD_INS_NUMBLOCKS
, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
168 memcpy(c
+ 5, src
, 8);
169 ExchangeAPDUSC(false, c
, sizeof(c
), false, false, resp
, sizeof(resp
), &resp_len
);
179 uint8_t GetPinSize(uint8_t *src
) {
181 uint8_t resp
[254] = {0};
182 uint8_t c
[] = {0x96, CARD_INS_PINSIZE
, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
183 memcpy(c
+ 5, src
, 8);
184 ExchangeAPDUSC(false, c
, sizeof(c
), false, false, resp
, sizeof(resp
), &resp_len
);
189 if (resp
[resp_len
- 2] == 0x90 && resp
[resp_len
- 1] == 0x00) {
195 int GetConfigCardByIdx(uint8_t typ
, uint8_t *blocks
) {
196 if (blocks
== NULL
) {
201 uint8_t resp
[254] = {0};
202 uint8_t c
[] = {0x96, CARD_INS_CC
, 0x00, 0x00, 17, typ
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
203 ExchangeAPDUSC(false, c
, sizeof(c
), false, true, resp
, sizeof(resp
), &resp_len
);
209 if (resp
[resp_len
- 2] == 0x90 && resp
[resp_len
- 1] == 0x00) {
210 memcpy(blocks
, resp
+ 1, 16);
216 int GetConfigCardStrByIdx(uint8_t typ
, uint8_t *out
) {
222 uint8_t resp
[254] = {0};
223 uint8_t c
[] = {0x96, CARD_INS_CC_DESC
, 0x00, 0x00, 1, typ
};
224 ExchangeAPDUSC(false, c
, sizeof(c
), false, true, resp
, sizeof(resp
), &resp_len
);
230 if (resp
[resp_len
- 2] == 0x90 && resp
[resp_len
- 1] == 0x00) {
231 memcpy(out
, resp
+ 1, resp_len
- 2 - 1);
237 int VerifyRdv4Signature(uint8_t *memid
, uint8_t *signature
) {
238 if (memid
== NULL
|| signature
== NULL
) {
243 uint8_t resp
[254] = {0};
244 uint8_t c
[5 + 8 + 128] = {0x96, CARD_INS_VERIFY_RRG
, 0x00, 0x00, 8 + 128};
246 memcpy(c
+ 5, memid
, 8);
247 memcpy(c
+ 5 + 8, signature
, 128);
249 ExchangeAPDUSC(false, c
, sizeof(c
), true, false, resp
, sizeof(resp
), &resp_len
);
254 if (memcmp(resp
+ resp_len
- 4, "\x6f\x6b\x90\x00", 4) == 0) {