mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Merge pull request #1299 from merlokk/add_cp_cmds
Add commands to read cipurse transport card
This commit is contained in:
@@ -211,6 +211,8 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/fido/fidocore.c
|
||||
${PM3_ROOT}/client/src/iso7816/apduinfo.c
|
||||
${PM3_ROOT}/client/src/iso7816/iso7816core.c
|
||||
${PM3_ROOT}/client/src/cipurse/cipursecrypto.c
|
||||
${PM3_ROOT}/client/src/cipurse/cipursecore.c
|
||||
${PM3_ROOT}/client/src/loclass/cipher.c
|
||||
${PM3_ROOT}/client/src/loclass/cipherutils.c
|
||||
${PM3_ROOT}/client/src/loclass/elite_crack.c
|
||||
@@ -242,6 +244,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhfcipurse.c
|
||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||
${PM3_ROOT}/client/src/cmdhfjooki.c
|
||||
${PM3_ROOT}/client/src/cmdhflegic.c
|
||||
|
||||
@@ -473,6 +473,7 @@ SRCS = aiddesfire.c \
|
||||
cmdhfemrtd.c \
|
||||
cmdhffelica.c \
|
||||
cmdhffido.c \
|
||||
cmdhfcipurse.c \
|
||||
cmdhficlass.c \
|
||||
cmdhflegic.c \
|
||||
cmdhfjooki.c \
|
||||
@@ -556,6 +557,8 @@ SRCS = aiddesfire.c \
|
||||
fido/cose.c \
|
||||
fido/cbortools.c \
|
||||
fido/fidocore.c \
|
||||
cipurse/cipursecore.c \
|
||||
cipurse/cipursecrypto.c \
|
||||
fileutils.c \
|
||||
flash.c \
|
||||
generator.c \
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2021 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// CIPURSE transport cards data and commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cipursecore.h"
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "util_posix.h" // msleep
|
||||
#include <string.h> // memcpy memset
|
||||
|
||||
#include "cmdhf14a.h"
|
||||
#include "emv/emvcore.h"
|
||||
#include "emv/emvjson.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
|
||||
// context for secure channel
|
||||
CipurseContext cipurseContext;
|
||||
|
||||
static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
uint8_t securedata[APDU_RES_LEN] = {0};
|
||||
sAPDU secapdu;
|
||||
|
||||
*ResultLen = 0;
|
||||
if (sw) *sw = 0;
|
||||
uint16_t isw = 0;
|
||||
int res = 0;
|
||||
|
||||
if (ActivateField) {
|
||||
DropField();
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
// long messages is not allowed
|
||||
if (apdu.Lc > 228)
|
||||
return 20;
|
||||
|
||||
// COMPUTE APDU
|
||||
int datalen = 0;
|
||||
uint16_t xle = IncludeLe ? 0x100 : 0x00;
|
||||
if (xle == 0x100 && Le != 0)
|
||||
xle = Le;
|
||||
|
||||
CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le);
|
||||
|
||||
if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) {
|
||||
PrintAndLogEx(ERR, "APDU encoding error.");
|
||||
return 201;
|
||||
}
|
||||
|
||||
if (GetAPDULogging())
|
||||
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
|
||||
|
||||
res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (GetAPDULogging())
|
||||
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen));
|
||||
|
||||
if (*ResultLen < 2) {
|
||||
return 200;
|
||||
}
|
||||
|
||||
size_t rlen = 0;
|
||||
if (*ResultLen == 2) {
|
||||
if (cipurseContext.RequestSecurity == CPSMACed || cipurseContext.RequestSecurity == CPSEncrypted)
|
||||
CipurseCClearContext(&cipurseContext);
|
||||
|
||||
isw = Result[0] * 0x0100 + Result[1];
|
||||
} else {
|
||||
CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw);
|
||||
memcpy(Result, securedata, rlen);
|
||||
}
|
||||
|
||||
if (ResultLen != NULL)
|
||||
*ResultLen = rlen;
|
||||
|
||||
if (sw != NULL)
|
||||
*sw = isw;
|
||||
|
||||
if (isw != 0x9000) {
|
||||
if (GetAPDULogging()) {
|
||||
if (*sw >> 8 == 0x61) {
|
||||
PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CIPURSEExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchangeEx(false, true, apdu, true, 0, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31};
|
||||
CipurseCClearContext(&cipurseContext);
|
||||
|
||||
return EMVSelect(CC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
|
||||
}
|
||||
|
||||
int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, 0x16, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSECreateFile(uint8_t *attr, uint16_t attrlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xe4, 0x00, 0x00, attrlen, attr}, false, 0, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff};
|
||||
return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xe4, 0x00, 0x00, 02, fileIdBin}, false, 0, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff};
|
||||
return CIPURSEExchange((sAPDU) {0x00, 0xa4, 0x00, 0x00, 02, fileIdBin}, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchange((sAPDU) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSEReadFileAttributes(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchange((sAPDU) {0x80, 0xce, 0x00, 0x00, 0, NULL}, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchange((sAPDU) {0x00, 0xb0, (offset >> 8) & 0x7f, offset & 0xff, 0, NULL}, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xd6, (offset >> 8) & 0x7f, offset & 0xff, datalen, data}, true, 0, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
||||
CipurseContext cpc = {0};
|
||||
CipurseCSetKey(&cpc, keyIndex, key);
|
||||
|
||||
// get RP, rP
|
||||
int res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || len != 0x16) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||
|
||||
return false;
|
||||
}
|
||||
CipurseCSetRandomFromPICC(&cpc, buf);
|
||||
|
||||
// make auth data
|
||||
uint8_t authparams[16 + 16 + 6] = {0};
|
||||
CipurseCAuthenticateHost(&cpc, authparams);
|
||||
|
||||
// authenticate
|
||||
res = CIPURSEMutalAuthenticate(keyIndex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
|
||||
if (res != 0 || sw != 0x9000 || len != 16) {
|
||||
if (sw == 0x6988) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key.");
|
||||
} else if (sw == 0x6A88) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key number.");
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||
}
|
||||
|
||||
CipurseCClearContext(&cipurseContext);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CipurseCCheckCT(&cpc, buf)) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "Authentication " _GREEN_("OK"));
|
||||
|
||||
CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed);
|
||||
memcpy(&cipurseContext, &cpc, sizeof(CipurseContext));
|
||||
return true;
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT");
|
||||
|
||||
CipurseCClearContext(&cipurseContext);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp) {
|
||||
CipurseCChannelSetSecurityLevels(&cipurseContext, req, resp);
|
||||
}
|
||||
|
||||
void CIPURSEPrintInfoFile(uint8_t *data, size_t len) {
|
||||
if (len < 2) {
|
||||
PrintAndLogEx(ERR, "Info file length " _RED_("ERROR"));
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "------------ INFO ------------");
|
||||
PrintAndLogEx(INFO, "CIPURSE version %d revision %d", data[0], data[1]);
|
||||
}
|
||||
|
||||
static void CIPURSEPrintFileDescriptor(uint8_t desc) {
|
||||
if (desc == 0x01)
|
||||
PrintAndLogEx(INFO, "Binary file");
|
||||
else if (desc == 0x11)
|
||||
PrintAndLogEx(INFO, "Binary file with transactions");
|
||||
else if (desc == 0x02)
|
||||
PrintAndLogEx(INFO, "Linear record file");
|
||||
else if (desc == 0x12)
|
||||
PrintAndLogEx(INFO, "Linear record file with transactions");
|
||||
else if (desc == 0x06)
|
||||
PrintAndLogEx(INFO, "Cyclic record file");
|
||||
else if (desc == 0x16)
|
||||
PrintAndLogEx(INFO, "Cyclic record file with transactions");
|
||||
else if (desc == 0x1E)
|
||||
PrintAndLogEx(INFO, "Linear value-record file");
|
||||
else if (desc == 0x1F)
|
||||
PrintAndLogEx(INFO, "Linear value-record file with transactions");
|
||||
else
|
||||
PrintAndLogEx(INFO, "Unknown file 0x%02x", desc);
|
||||
}
|
||||
|
||||
static void CIPURSEPrintKeyAttrib(uint8_t *attr) {
|
||||
PrintAndLogEx(INFO, "-------- KEY ATTRIBUTES --------");
|
||||
PrintAndLogEx(INFO, "Additional info: 0x%02x", attr[0]);
|
||||
PrintAndLogEx(INFO, "Key length: %d", attr[1]);
|
||||
PrintAndLogEx(INFO, "Algorithm ID: 0x%02x", attr[2]);
|
||||
PrintAndLogEx(INFO, "Security attr: 0x%02x", attr[3]);
|
||||
PrintAndLogEx(INFO, "KVV: 0x%02x%02x%02x", attr[4], attr[5], attr[6]);
|
||||
PrintAndLogEx(INFO, "-------------------------------");
|
||||
}
|
||||
|
||||
void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||
if (len < 7) {
|
||||
PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR"));
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------");
|
||||
if (fileAttr[0] == 0x38) {
|
||||
PrintAndLogEx(INFO, "Type: MF, ADF");
|
||||
if (fileAttr[1] == 0x00) {
|
||||
PrintAndLogEx(INFO, "Type: MF");
|
||||
} else {
|
||||
if ((fileAttr[1] & 0xe0) == 0x00)
|
||||
PrintAndLogEx(INFO, "Type: Unknown");
|
||||
if ((fileAttr[1] & 0xe0) == 0x20)
|
||||
PrintAndLogEx(INFO, "Type: CIPURSE L");
|
||||
if ((fileAttr[1] & 0xe0) == 0x40)
|
||||
PrintAndLogEx(INFO, "Type: CIPURSE S");
|
||||
if ((fileAttr[1] & 0xe0) == 0x60)
|
||||
PrintAndLogEx(INFO, "Type: CIPURSE T");
|
||||
if ((fileAttr[1] & 0x02) == 0x00)
|
||||
PrintAndLogEx(INFO, "Autoselect on PxSE select OFF");
|
||||
else
|
||||
PrintAndLogEx(INFO, "Autoselect on PxSE select ON");
|
||||
if ((fileAttr[1] & 0x01) == 0x00)
|
||||
PrintAndLogEx(INFO, "PxSE select returns FCPTemplate OFF");
|
||||
else
|
||||
PrintAndLogEx(INFO, "PxSE select returns FCPTemplate ON");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]);
|
||||
|
||||
PrintAndLogEx(INFO, "Maximum number of custom EFs: %d", fileAttr[4]);
|
||||
PrintAndLogEx(INFO, "Maximum number of EFs with SFID: %d", fileAttr[5]);
|
||||
uint8_t keyNum = fileAttr[6];
|
||||
PrintAndLogEx(INFO, "Keys assigned: %d", keyNum);
|
||||
|
||||
if (len >= 9) {
|
||||
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
||||
}
|
||||
|
||||
if (len >= 10 + keyNum + 1) {
|
||||
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], keyNum + 1));
|
||||
}
|
||||
|
||||
if (len >= 11 + keyNum + 1 + keyNum * 7) {
|
||||
for (int i = 0; i < keyNum; i++) {
|
||||
PrintAndLogEx(INFO, "Key %d Attributes: %s", i, sprint_hex(&fileAttr[11 + keyNum + 1 + i * 7], 7));
|
||||
CIPURSEPrintKeyAttrib(&fileAttr[11 + keyNum + 1 + i * 7]);
|
||||
}
|
||||
}
|
||||
// MF
|
||||
if (fileAttr[1] == 0x00) {
|
||||
PrintAndLogEx(INFO, "Total memory size: %d", (fileAttr[len - 6] << 16) + (fileAttr[len - 1] << 5) + fileAttr[len - 4]);
|
||||
PrintAndLogEx(INFO, "Free memory size: %d", (fileAttr[len - 3] << 16) + (fileAttr[len - 2] << 8) + fileAttr[len - 1]);
|
||||
|
||||
} else {
|
||||
int ptr = 11 + keyNum + 1 + keyNum * 7;
|
||||
if (len > ptr)
|
||||
PrintAndLogEx(INFO, "TLV file control: %s", sprint_hex(&fileAttr[ptr], len - ptr));
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Type: EF");
|
||||
CIPURSEPrintFileDescriptor(fileAttr[0]);
|
||||
if (fileAttr[1] == 0)
|
||||
PrintAndLogEx(INFO, "SFI: not assigned");
|
||||
else
|
||||
PrintAndLogEx(INFO, "SFI: 0x%02x", fileAttr[1]);
|
||||
|
||||
PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]);
|
||||
|
||||
if (fileAttr[0] == 0x01 || fileAttr[0] == 0x11)
|
||||
PrintAndLogEx(INFO, "File size: %d", (fileAttr[4] << 8) + fileAttr[5]);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Record num: %d record size: %d", fileAttr[4], fileAttr[5]);
|
||||
|
||||
PrintAndLogEx(INFO, "Keys assigned: %d", fileAttr[6]);
|
||||
|
||||
if (len >= 9) {
|
||||
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
||||
}
|
||||
|
||||
if (len >= 10) {
|
||||
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], len - 9));
|
||||
if (fileAttr[6] + 1 != len - 9)
|
||||
PrintAndLogEx(WARNING, "ART length is wrong");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2021 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// CIPURSE transport cards data and commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __CIPURSECORE_H__
|
||||
#define __CIPURSECORE_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <jansson.h>
|
||||
#include "iso7816/apduinfo.h" // sAPDU
|
||||
#include "cipurse/cipursecrypto.h"
|
||||
|
||||
|
||||
#define CIPURSE_DEFAULT_KEY {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}
|
||||
|
||||
void CIPURSEPrintInfoFile(uint8_t *data, size_t len);
|
||||
|
||||
int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
|
||||
int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
|
||||
int CIPURSECreateFile(uint8_t *attr, uint16_t attrlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
|
||||
int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) ;
|
||||
int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int CIPURSEReadFileAttributes(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
|
||||
bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose);
|
||||
void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp);
|
||||
|
||||
void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len);
|
||||
|
||||
#endif /* __CIPURSECORE_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2021 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// CIPURSE crypto primitives
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __CIPURSECRYPTO_H__
|
||||
#define __CIPURSECRYPTO_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "iso7816/apduinfo.h" // sAPDU
|
||||
|
||||
#define CIPURSE_KVV_LENGTH 4
|
||||
#define CIPURSE_AES_KEY_LENGTH 16
|
||||
#define CIPURSE_AES_BLOCK_LENGTH 16
|
||||
#define CIPURSE_SECURITY_PARAM_N 6
|
||||
#define CIPURSE_MAC_LENGTH 8
|
||||
#define CIPURSE_MIC_LENGTH 4
|
||||
#define CIPURSE_POLY 0x35b088cce172UL
|
||||
#define ISO9797_M2_PAD_BYTE 0x80
|
||||
|
||||
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
typedef enum {
|
||||
CPSNone,
|
||||
CPSPlain,
|
||||
CPSMACed,
|
||||
CPSEncrypted
|
||||
} CipurseChannelSecurityLevel;
|
||||
|
||||
typedef struct CipurseContextS {
|
||||
uint8_t keyId;
|
||||
uint8_t key[CIPURSE_AES_KEY_LENGTH];
|
||||
|
||||
uint8_t RP[CIPURSE_AES_KEY_LENGTH];
|
||||
uint8_t rP[CIPURSE_SECURITY_PARAM_N];
|
||||
uint8_t RT[CIPURSE_AES_KEY_LENGTH];
|
||||
uint8_t rT[CIPURSE_SECURITY_PARAM_N];
|
||||
|
||||
uint8_t k0[CIPURSE_AES_KEY_LENGTH];
|
||||
uint8_t cP[CIPURSE_AES_KEY_LENGTH];
|
||||
uint8_t CT[CIPURSE_AES_KEY_LENGTH];
|
||||
|
||||
uint8_t frameKey[CIPURSE_AES_KEY_LENGTH];
|
||||
uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH];
|
||||
|
||||
CipurseChannelSecurityLevel RequestSecurity;
|
||||
CipurseChannelSecurityLevel ResponseSecurity;
|
||||
} CipurseContext;
|
||||
|
||||
uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl);
|
||||
|
||||
void CipurseCClearContext(CipurseContext *ctx);
|
||||
void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key);
|
||||
void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random);
|
||||
void CipurseCSetRandomHost(CipurseContext *ctx);
|
||||
uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent);
|
||||
|
||||
void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata);
|
||||
bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT);
|
||||
|
||||
void CipurseCChannelSetSecurityLevels(CipurseContext *ctx, CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp);
|
||||
bool isCipurseCChannelSecuritySet(CipurseContext *ctx);
|
||||
|
||||
void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen);
|
||||
size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen);
|
||||
|
||||
void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac);
|
||||
void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac);
|
||||
bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac);
|
||||
void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic);
|
||||
bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic);
|
||||
void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt);
|
||||
void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen);
|
||||
void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen);
|
||||
void CipurseCGetKVV(uint8_t *key, uint8_t *kvv);
|
||||
|
||||
void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le);
|
||||
void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw);
|
||||
|
||||
|
||||
#endif /* __CIPURSECRYPTO_H__ */
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "cmdhftopaz.h" // TOPAZ
|
||||
#include "cmdhffelica.h" // ISO18092 / FeliCa
|
||||
#include "cmdhffido.h" // FIDO authenticators
|
||||
#include "cmdhfcipurse.h" // CIPURSE transport cards
|
||||
#include "cmdhfthinfilm.h" // Thinfilm
|
||||
#include "cmdhflto.h" // LTO-CM
|
||||
#include "cmdhfcryptorf.h" // CryptoRF
|
||||
@@ -128,6 +129,15 @@ int CmdHFSearch(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, " Searching for Cipurse tag...");
|
||||
if (IfPm3Iso14443a()) {
|
||||
if (CheckCardCipurse()) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Cipurse tag") " found\n");
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// 14b is the longest test
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, " Searching for ISO14443-B tag...");
|
||||
@@ -399,6 +409,7 @@ static command_t CommandTable[] = {
|
||||
{"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"},
|
||||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"},
|
||||
{"cipurse", CmdHFCipurse, AlwaysAvailable, "{ Cipurse transport Cards... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2021 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// High frequency FIDO U2F and FIDO2 contactless authenticators
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// JAVA implementation here:
|
||||
//
|
||||
// https://github.com/duychuongvn/cipurse-card-core
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDHFCIPURSE_H__
|
||||
#define CMDHFCIPURSE_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdHFCipurse(const char *Cmd);
|
||||
|
||||
bool CheckCardCipurse(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user