//----------------------------------------------------------------------------- // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // See LICENSE.txt for the text of the license. //----------------------------------------------------------------------------- // Support functions for smart card //----------------------------------------------------------------------------- #include "cardhelper.h" #include #include #include "cmdparser.h" #include "cmdsmartcard.h" #include "ui.h" #include "util.h" #include "commonutil.h" #define CARD_INS_DECRYPT 0x01 #define CARD_INS_ENCRYPT 0x02 #define CARD_INS_VERIFY_RRG 0x05 #define CARD_INS_DECODE 0x06 #define CARD_INS_NUMBLOCKS 0x07 #define CARD_INS_PINSIZE 0x08 #define CARD_INS_CC 0x81 #define CARD_INS_CC_DESC 0x82 // look for CardHelper bool IsCardHelperPresent(bool verbose) { if (IfPm3Smartcard() == false) { return false; } int resp_len = 0; uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; uint8_t resp[30] = {0}; ExchangeAPDUSC(verbose, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); if (resp_len < 8) { return false; } if (strstr("CryptoHelper", (char *)resp) == 0) { if (verbose) { PrintAndLogEx(INFO, "Found smart card helper"); } return true; } return false; } bool IsHIDSamPresent(bool verbose) { if (IfPm3Smartcard() == false) { PrintAndLogEx(WARNING, "Proxmark3 does not have SMARTCARD support enabled, exiting"); return false; } // detect SAM smart_card_atr_t card; smart_select(verbose, &card); if (card.atr_len == 0) { PrintAndLogEx(ERR, "Can't get ATR from a smart card"); return false; } // SAM identification smart_card_atr_t supported[] = { {15, {0x3B, 0x95, 0x96, 0x80, 0xB1, 0xFE, 0x55, 0x1F, 0xC7, 0x47, 0x72, 0x61, 0x63, 0x65, 0x13}}, {11, {0x3b, 0x90, 0x96, 0x91, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0xd4}}, }; bool found = false; for (int i = 0; i < ARRAYLEN(supported); i++) { if ((card.atr_len == supported[i].atr_len) && (memcmp(card.atr, supported[i].atr, supported[i].atr_len) == 0)) { found = true; break; } } if (found == false) { if (verbose) { PrintAndLogEx(SUCCESS, "Not detecting a SAM"); } return false; } // Suspect some SAMs has version name in the historical bytes uint8_t T0 = card.atr[1]; uint8_t K = T0 & 0x0F; // Number of historical bytes if (K > 0 && (K < (card.atr_len - 3)) && verbose) { // Last byte of ATR is CRC and before that we have K bytes of // "historical bytes". // By construction K can't go above 15 char sam_name[16] = {0}; memcpy(sam_name, &card.atr[card.atr_len - 1 - K], K); PrintAndLogEx(SUCCESS, "SAM (%s) detected", sam_name); } return true; } static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) { uint8_t cmd[] = {0x96, ins, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(cmd + 5, src, 8); int resp_len = 0; uint8_t dec[11] = {0}; ExchangeAPDUSC(false, cmd, sizeof(cmd), true, true, dec, sizeof(dec), &resp_len); if (resp_len == 10) { memcpy(dest, dec, 8); return true; } return false; } bool Decrypt(uint8_t *src, uint8_t *dest) { return executeCrypto(CARD_INS_DECRYPT, src, dest); } bool Encrypt(uint8_t *src, uint8_t *dest) { return executeCrypto(CARD_INS_ENCRYPT, src, dest); } // Call with block6 void DecodeBlock6(uint8_t *src) { uint8_t c[] = {0x96, CARD_INS_DECODE, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(c + 6, src, 8); int resp_len = 0; uint8_t resp[254] = {0}; // first part ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); if (resp_len < 11) { PrintAndLogEx(DEBUG, "decodeblock6, wrong response len, expected 11 got ( " _RED_("%d") " )", resp_len); return; } PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); // second part c[5] = 0x02; ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len); if (resp_len < 11) { PrintAndLogEx(DEBUG, "decodeblock6, wrong response len, expected 11 got ( " _RED_("%d") " )", resp_len); return; } PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); } // Call with block6 uint8_t GetNumberBlocksForUserId(uint8_t *src) { int resp_len = 0; uint8_t resp[254] = {0}; uint8_t c[] = {0x96, CARD_INS_NUMBLOCKS, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(c + 5, src, 8); ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len); if (resp_len < 8) { return 0; } return resp[8]; } // Call with block6 uint8_t GetPinSize(uint8_t *src) { int resp_len = 0; uint8_t resp[254] = {0}; uint8_t c[] = {0x96, CARD_INS_PINSIZE, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(c + 5, src, 8); ExchangeAPDUSC(false, c, sizeof(c), false, false, resp, sizeof(resp), &resp_len); if (resp_len < 2) { return 0; } if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) { return resp[8]; } return 0; } int GetConfigCardByIdx(uint8_t typ, uint8_t *blocks) { if (blocks == NULL) { return PM3_EINVARG; } int resp_len = 0; uint8_t resp[254] = {0}; 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}; ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); if (resp_len < 2) { return PM3_ESOFT; } if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) { memcpy(blocks, resp + 1, 16); return PM3_SUCCESS; } return PM3_ESOFT; } int GetConfigCardStrByIdx(uint8_t typ, uint8_t *out) { if (out == NULL) { return PM3_EINVARG; } int resp_len = 0; uint8_t resp[254] = {0}; uint8_t c[] = {0x96, CARD_INS_CC_DESC, 0x00, 0x00, 1, typ}; ExchangeAPDUSC(false, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); if (resp_len < 2) { return PM3_ESOFT; } if (resp[resp_len - 2] == 0x90 && resp[resp_len - 1] == 0x00) { memcpy(out, resp + 1, resp_len - 2 - 1); return PM3_SUCCESS; } return PM3_ESOFT; } int VerifyRdv4Signature(uint8_t *memid, uint8_t *signature) { if (memid == NULL || signature == NULL) { return PM3_EINVARG; } int resp_len = 0; uint8_t resp[254] = {0}; uint8_t c[5 + 8 + 128] = {0x96, CARD_INS_VERIFY_RRG, 0x00, 0x00, 8 + 128}; memcpy(c + 5, memid, 8); memcpy(c + 5 + 8, signature, 128); ExchangeAPDUSC(false, c, sizeof(c), true, false, resp, sizeof(resp), &resp_len); if (resp_len < 2) { return PM3_ESOFT; } if (memcmp(resp + resp_len - 4, "\x6f\x6b\x90\x00", 4) == 0) { return PM3_SUCCESS; } return PM3_ESOFT; }