mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
make style
This commit is contained in:
parent
f0367ad2f7
commit
f3f3a5a270
5 changed files with 169 additions and 164 deletions
|
@ -38,7 +38,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu,
|
||||||
DropField();
|
DropField();
|
||||||
msleep(50);
|
msleep(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// long messages is not allowed
|
// long messages is not allowed
|
||||||
if (apdu.Lc > 228)
|
if (apdu.Lc > 228)
|
||||||
return 20;
|
return 20;
|
||||||
|
@ -50,7 +50,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu,
|
||||||
xle = Le;
|
xle = Le;
|
||||||
|
|
||||||
CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le);
|
CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le);
|
||||||
|
|
||||||
if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) {
|
if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) {
|
||||||
PrintAndLogEx(ERR, "APDU encoding error.");
|
PrintAndLogEx(ERR, "APDU encoding error.");
|
||||||
return 201;
|
return 201;
|
||||||
|
@ -66,11 +66,11 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu,
|
||||||
|
|
||||||
if (GetAPDULogging())
|
if (GetAPDULogging())
|
||||||
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen));
|
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen));
|
||||||
|
|
||||||
if (*ResultLen < 2) {
|
if (*ResultLen < 2) {
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t rlen = 0;
|
size_t rlen = 0;
|
||||||
if (*ResultLen == 2) {
|
if (*ResultLen == 2) {
|
||||||
if (cipurseContext.RequestSecurity == CPSMACed || cipurseContext.RequestSecurity == CPSEncrypted)
|
if (cipurseContext.RequestSecurity == CPSMACed || cipurseContext.RequestSecurity == CPSEncrypted)
|
||||||
|
@ -81,10 +81,10 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu,
|
||||||
CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw);
|
CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw);
|
||||||
memcpy(Result, securedata, rlen);
|
memcpy(Result, securedata, rlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ResultLen != NULL)
|
if (ResultLen != NULL)
|
||||||
*ResultLen = rlen;
|
*ResultLen = rlen;
|
||||||
|
|
||||||
if (sw != NULL)
|
if (sw != NULL)
|
||||||
*sw = isw;
|
*sw = isw;
|
||||||
|
|
||||||
|
@ -158,13 +158,13 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) {
|
||||||
|
|
||||||
CipurseContext cpc = {0};
|
CipurseContext cpc = {0};
|
||||||
CipurseCSetKey(&cpc, keyIndex, key);
|
CipurseCSetKey(&cpc, keyIndex, key);
|
||||||
|
|
||||||
// get RP, rP
|
// get RP, rP
|
||||||
int res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw);
|
int res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || len != 0x16) {
|
if (res != 0 || len != 0x16) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CipurseCSetRandomFromPICC(&cpc, buf);
|
CipurseCSetRandomFromPICC(&cpc, buf);
|
||||||
|
@ -172,7 +172,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) {
|
||||||
// make auth data
|
// make auth data
|
||||||
uint8_t authparams[16 + 16 + 6] = {0};
|
uint8_t authparams[16 + 16 + 6] = {0};
|
||||||
CipurseCAuthenticateHost(&cpc, authparams);
|
CipurseCAuthenticateHost(&cpc, authparams);
|
||||||
|
|
||||||
// authenticate
|
// authenticate
|
||||||
res = CIPURSEMutalAuthenticate(keyIndex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
|
res = CIPURSEMutalAuthenticate(keyIndex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000 || len != 16) {
|
if (res != 0 || sw != 0x9000 || len != 16) {
|
||||||
|
@ -186,22 +186,22 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
CipurseCClearContext(&cipurseContext);
|
CipurseCClearContext(&cipurseContext);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CipurseCCheckCT(&cpc, buf)) {
|
if (CipurseCCheckCT(&cpc, buf)) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "Authentication " _GREEN_("OK"));
|
PrintAndLogEx(INFO, "Authentication " _GREEN_("OK"));
|
||||||
|
|
||||||
CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed);
|
CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed);
|
||||||
memcpy(&cipurseContext, &cpc, sizeof(CipurseContext));
|
memcpy(&cipurseContext, &cpc, sizeof(CipurseContext));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT");
|
PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT");
|
||||||
|
|
||||||
CipurseCClearContext(&cipurseContext);
|
CipurseCClearContext(&cipurseContext);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||||
PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR"));
|
PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------");
|
PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------");
|
||||||
if (fileAttr[0] == 0x38) {
|
if (fileAttr[0] == 0x38) {
|
||||||
PrintAndLogEx(INFO, "Type: MF, ADF");
|
PrintAndLogEx(INFO, "Type: MF, ADF");
|
||||||
|
@ -281,14 +281,14 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||||
else
|
else
|
||||||
PrintAndLogEx(INFO, "PxSE select returns FCPTemplate ON");
|
PrintAndLogEx(INFO, "PxSE select returns FCPTemplate ON");
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]);
|
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 custom EFs: %d", fileAttr[4]);
|
||||||
PrintAndLogEx(INFO, "Maximum number of EFs with SFID: %d", fileAttr[5]);
|
PrintAndLogEx(INFO, "Maximum number of EFs with SFID: %d", fileAttr[5]);
|
||||||
uint8_t keyNum = fileAttr[6];
|
uint8_t keyNum = fileAttr[6];
|
||||||
PrintAndLogEx(INFO, "Keys assigned: %d", keyNum);
|
PrintAndLogEx(INFO, "Keys assigned: %d", keyNum);
|
||||||
|
|
||||||
if (len >= 9) {
|
if (len >= 9) {
|
||||||
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||||
if (len >= 10 + keyNum + 1) {
|
if (len >= 10 + keyNum + 1) {
|
||||||
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], keyNum + 1));
|
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], keyNum + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= 11 + keyNum + 1 + keyNum * 7) {
|
if (len >= 11 + keyNum + 1 + keyNum * 7) {
|
||||||
for (int i = 0; i < keyNum; i++) {
|
for (int i = 0; i < keyNum; i++) {
|
||||||
PrintAndLogEx(INFO, "Key %d Attributes: %s", i, sprint_hex(&fileAttr[11 + keyNum + 1 + i * 7], 7));
|
PrintAndLogEx(INFO, "Key %d Attributes: %s", i, sprint_hex(&fileAttr[11 + keyNum + 1 + i * 7], 7));
|
||||||
|
@ -307,7 +307,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||||
if (fileAttr[1] == 0x00) {
|
if (fileAttr[1] == 0x00) {
|
||||||
PrintAndLogEx(INFO, "Total memory size: %d", (fileAttr[len - 6] << 16) + (fileAttr[len - 1] << 5) + fileAttr[len - 4]);
|
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]);
|
PrintAndLogEx(INFO, "Free memory size: %d", (fileAttr[len - 3] << 16) + (fileAttr[len - 2] << 8) + fileAttr[len - 1]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int ptr = 11 + keyNum + 1 + keyNum * 7;
|
int ptr = 11 + keyNum + 1 + keyNum * 7;
|
||||||
if (len > ptr)
|
if (len > ptr)
|
||||||
|
@ -322,27 +322,27 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) {
|
||||||
PrintAndLogEx(INFO, "SFI: 0x%02x", fileAttr[1]);
|
PrintAndLogEx(INFO, "SFI: 0x%02x", fileAttr[1]);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]);
|
PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]);
|
||||||
|
|
||||||
if (fileAttr[0] == 0x01 || fileAttr[0] == 0x11)
|
if (fileAttr[0] == 0x01 || fileAttr[0] == 0x11)
|
||||||
PrintAndLogEx(INFO, "File size: %d", (fileAttr[4] << 8) + fileAttr[5]);
|
PrintAndLogEx(INFO, "File size: %d", (fileAttr[4] << 8) + fileAttr[5]);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(INFO, "Record num: %d record size: %d", fileAttr[4], fileAttr[5]);
|
PrintAndLogEx(INFO, "Record num: %d record size: %d", fileAttr[4], fileAttr[5]);
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Keys assigned: %d", fileAttr[6]);
|
PrintAndLogEx(INFO, "Keys assigned: %d", fileAttr[6]);
|
||||||
|
|
||||||
if (len >= 9) {
|
if (len >= 9) {
|
||||||
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len >= 10) {
|
if (len >= 10) {
|
||||||
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], len - 9));
|
PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], len - 9));
|
||||||
if (fileAttr[6] + 1 != len - 9)
|
if (fileAttr[6] + 1 != len - 9)
|
||||||
PrintAndLogEx(WARNING, "ART length is wrong");
|
PrintAndLogEx(WARNING, "ART length is wrong");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,16 +27,21 @@ uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
|
||||||
|
|
||||||
uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) {
|
uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) {
|
||||||
switch (lvl) {
|
switch (lvl) {
|
||||||
case CPSNone: return 0x00;
|
case CPSNone:
|
||||||
case CPSPlain: return 0x00;
|
return 0x00;
|
||||||
case CPSMACed: return 0x01;
|
case CPSPlain:
|
||||||
case CPSEncrypted: return 0x02;
|
return 0x00;
|
||||||
default: return 0x00;
|
case CPSMACed:
|
||||||
|
return 0x01;
|
||||||
|
case CPSEncrypted:
|
||||||
|
return 0x02;
|
||||||
|
default:
|
||||||
|
return 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) {
|
static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) {
|
||||||
for(size_t i = 0; i < len; i++)
|
for (size_t i = 0; i < len; i++)
|
||||||
d1[i] = d1[i] ^ d2[i];
|
d1[i] = d1[i] ^ d2[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,14 +79,14 @@ static uint64_t rotateLeft48(uint64_t src) {
|
||||||
|
|
||||||
static uint64_t computeNLM48(uint64_t x, uint64_t y) {
|
static uint64_t computeNLM48(uint64_t x, uint64_t y) {
|
||||||
uint64_t res = 0;
|
uint64_t res = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 48; i++) {
|
for (int i = 0; i < 48; i++) {
|
||||||
res = rotateLeft48(res);
|
res = rotateLeft48(res);
|
||||||
if (res & 1)
|
if (res & 1)
|
||||||
res = res ^ CIPURSE_POLY;
|
res = res ^ CIPURSE_POLY;
|
||||||
y = rotateLeft48(y);
|
y = rotateLeft48(y);
|
||||||
if (y & 1)
|
if (y & 1)
|
||||||
res = res ^ x;
|
res = res ^ x;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -89,25 +94,25 @@ static uint64_t computeNLM48(uint64_t x, uint64_t y) {
|
||||||
static void computeNLM(uint8_t *res, uint8_t *x, uint8_t *y) {
|
static void computeNLM(uint8_t *res, uint8_t *x, uint8_t *y) {
|
||||||
uint64_t x64 = 0;
|
uint64_t x64 = 0;
|
||||||
uint64_t y64 = 0;
|
uint64_t y64 = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
x64 = (x64 << 8) | x[i];
|
x64 = (x64 << 8) | x[i];
|
||||||
y64 = (y64 << 8) | y[i];
|
y64 = (y64 << 8) | y[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t res64 = computeNLM48(x64, y64);
|
uint64_t res64 = computeNLM48(x64, y64);
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
res[5 - i] = res64 & 0xff;
|
res[5 - i] = res64 & 0xff;
|
||||||
res64 = res64 >> 8;
|
res64 = res64 >> 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CipurseCGenerateK0AndCp(CipurseContext *ctx) {
|
static void CipurseCGenerateK0AndCp(CipurseContext *ctx) {
|
||||||
uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0};
|
uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0};
|
||||||
|
|
||||||
// session key derivation function
|
// session key derivation function
|
||||||
// kP := NLM(EXT(kID), rP)
|
// kP := NLM(EXT(kID), rP)
|
||||||
// k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID
|
// k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID
|
||||||
|
@ -116,11 +121,11 @@ static void CipurseCGenerateK0AndCp(CipurseContext *ctx) {
|
||||||
bin_pad2(temp1, CIPURSE_AES_KEY_LENGTH, kp, CIPURSE_SECURITY_PARAM_N);
|
bin_pad2(temp1, CIPURSE_AES_KEY_LENGTH, kp, CIPURSE_SECURITY_PARAM_N);
|
||||||
bin_pad(temp2, CIPURSE_AES_KEY_LENGTH, ctx->rT, CIPURSE_SECURITY_PARAM_N);
|
bin_pad(temp2, CIPURSE_AES_KEY_LENGTH, ctx->rT, CIPURSE_SECURITY_PARAM_N);
|
||||||
bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
// session key K0
|
// session key K0
|
||||||
aes_encode(NULL, temp1, ctx->key, ctx->k0, CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, temp1, ctx->key, ctx->k0, CIPURSE_AES_KEY_LENGTH);
|
||||||
bin_xor(ctx->k0, ctx->key, CIPURSE_AES_KEY_LENGTH);
|
bin_xor(ctx->k0, ctx->key, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
// first frame key k1, function to calculate k1,
|
// first frame key k1, function to calculate k1,
|
||||||
// k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT)
|
// k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT)
|
||||||
memcpy(temp1, ctx->k0, CIPURSE_AES_KEY_LENGTH);
|
memcpy(temp1, ctx->k0, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
@ -128,7 +133,7 @@ static void CipurseCGenerateK0AndCp(CipurseContext *ctx) {
|
||||||
aes_encode(NULL, ctx->RP, temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, ctx->RP, temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
||||||
bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH);
|
||||||
memcpy(ctx->frameKey, temp1, CIPURSE_AES_KEY_LENGTH);
|
memcpy(ctx->frameKey, temp1, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
// function to caluclate cP := AES(key=k0, RP).
|
// function to caluclate cP := AES(key=k0, RP).
|
||||||
// terminal response
|
// terminal response
|
||||||
aes_encode(NULL, ctx->k0, ctx->RP, ctx->cP, CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, ctx->k0, ctx->RP, ctx->cP, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
@ -148,16 +153,16 @@ void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) {
|
||||||
void CipurseCClearContext(CipurseContext *ctx) {
|
void CipurseCClearContext(CipurseContext *ctx) {
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(ctx, 0, sizeof(CipurseContext));
|
memset(ctx, 0, sizeof(CipurseContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) {
|
void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) {
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CipurseCClearContext(ctx);
|
CipurseCClearContext(ctx);
|
||||||
|
|
||||||
ctx->keyId = keyId;
|
ctx->keyId = keyId;
|
||||||
memcpy(ctx->key, key, member_size(CipurseContext, key));
|
memcpy(ctx->key, key, member_size(CipurseContext, key));
|
||||||
}
|
}
|
||||||
|
@ -174,7 +179,7 @@ bool isCipurseCChannelSecuritySet(CipurseContext *ctx) {
|
||||||
void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) {
|
void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) {
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(ctx->RP, random, member_size(CipurseContext, RP));
|
memcpy(ctx->RP, random, member_size(CipurseContext, RP));
|
||||||
memcpy(ctx->rP, random + member_size(CipurseContext, RP), member_size(CipurseContext, rP));
|
memcpy(ctx->rP, random + member_size(CipurseContext, RP), member_size(CipurseContext, rP));
|
||||||
}
|
}
|
||||||
|
@ -194,13 +199,13 @@ uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent) {
|
||||||
static void CipurseCFillAuthData(CipurseContext *ctx, uint8_t *authdata) {
|
static void CipurseCFillAuthData(CipurseContext *ctx, uint8_t *authdata) {
|
||||||
memcpy(authdata, ctx->cP, member_size(CipurseContext, cP));
|
memcpy(authdata, ctx->cP, member_size(CipurseContext, cP));
|
||||||
memcpy(&authdata[member_size(CipurseContext, cP)], ctx->RT, member_size(CipurseContext, RT));
|
memcpy(&authdata[member_size(CipurseContext, cP)], ctx->RT, member_size(CipurseContext, RT));
|
||||||
memcpy(&authdata[member_size(CipurseContext, cP) + member_size(CipurseContext, RT)], ctx->rT, member_size(CipurseContext, rT));
|
memcpy(&authdata[member_size(CipurseContext, cP) + member_size(CipurseContext, RT)], ctx->rT, member_size(CipurseContext, rT));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) {
|
void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) {
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CipurseCSetRandomHost(ctx);
|
CipurseCSetRandomHost(ctx);
|
||||||
CipurseCGenerateK0AndCp(ctx);
|
CipurseCGenerateK0AndCp(ctx);
|
||||||
CipurseCGenerateCT(ctx->k0, ctx->RT, ctx->CT);
|
CipurseCGenerateCT(ctx->k0, ctx->RT, ctx->CT);
|
||||||
|
@ -231,7 +236,7 @@ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t CipurseCComputeMICCRC (uint8_t *data, size_t len) {
|
static uint16_t CipurseCComputeMICCRC(uint8_t *data, size_t len) {
|
||||||
uint16_t initCRC = 0x6363;
|
uint16_t initCRC = 0x6363;
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
uint8_t ch = data[i] ^ initCRC;
|
uint8_t ch = data[i] ^ initCRC;
|
||||||
|
@ -245,16 +250,16 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) {
|
||||||
size_t plen = 0;
|
size_t plen = 0;
|
||||||
uint8_t pdata[datalen + CIPURSE_MIC_LENGTH];
|
uint8_t pdata[datalen + CIPURSE_MIC_LENGTH];
|
||||||
memset(pdata, 0, sizeof(pdata));
|
memset(pdata, 0, sizeof(pdata));
|
||||||
|
|
||||||
// 0x00 padding
|
// 0x00 padding
|
||||||
memcpy(pdata, data, datalen);
|
memcpy(pdata, data, datalen);
|
||||||
plen = datalen;
|
plen = datalen;
|
||||||
if (datalen % CIPURSE_MIC_LENGTH)
|
if (datalen % CIPURSE_MIC_LENGTH)
|
||||||
plen += CIPURSE_MIC_LENGTH - datalen % CIPURSE_MIC_LENGTH;
|
plen += CIPURSE_MIC_LENGTH - datalen % CIPURSE_MIC_LENGTH;
|
||||||
|
|
||||||
// crc
|
// crc
|
||||||
uint16_t crc1 = CipurseCComputeMICCRC(pdata, plen);
|
uint16_t crc1 = CipurseCComputeMICCRC(pdata, plen);
|
||||||
|
|
||||||
for (size_t i = 0; i < datalen; i += 4) {
|
for (size_t i = 0; i < datalen; i += 4) {
|
||||||
uint8_t tmp1 = pdata[i + 0];
|
uint8_t tmp1 = pdata[i + 0];
|
||||||
uint8_t tmp2 = pdata[i + 1];
|
uint8_t tmp2 = pdata[i + 1];
|
||||||
|
@ -263,7 +268,7 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) {
|
||||||
pdata[i + 2] = tmp1;
|
pdata[i + 2] = tmp1;
|
||||||
pdata[i + 3] = tmp2;
|
pdata[i + 3] = tmp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc2 = CipurseCComputeMICCRC(pdata, plen);
|
uint16_t crc2 = CipurseCComputeMICCRC(pdata, plen);
|
||||||
if (mic != NULL) {
|
if (mic != NULL) {
|
||||||
mic[0] = crc2 >> 8;
|
mic[0] = crc2 >> 8;
|
||||||
|
@ -275,16 +280,16 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) {
|
||||||
|
|
||||||
bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) {
|
bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) {
|
||||||
uint8_t xmic[CIPURSE_MIC_LENGTH] = {0};
|
uint8_t xmic[CIPURSE_MIC_LENGTH] = {0};
|
||||||
|
|
||||||
CipurseCGenerateMIC(data, datalen, xmic);
|
CipurseCGenerateMIC(data, datalen, xmic);
|
||||||
return (memcmp(xmic, mic, CIPURSE_MIC_LENGTH) == 0);
|
return (memcmp(xmic, mic, CIPURSE_MIC_LENGTH) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521
|
/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521
|
||||||
*
|
*
|
||||||
* Encrypt/Decrypt the given data using ciphering mechanism explained the OPST.
|
* Encrypt/Decrypt the given data using ciphering mechanism explained the OPST.
|
||||||
* Data should be already padded.
|
* Data should be already padded.
|
||||||
*
|
*
|
||||||
* hx-1 := ki , hx := AES( key = hx-1 ; q) XOR q, Cx := AES( key = hx ;
|
* hx-1 := ki , hx := AES( key = hx-1 ; q) XOR q, Cx := AES( key = hx ;
|
||||||
* Dx ), hx+1 := AES( key = hx ; q ) XOR q, Cx+1 := AES( key = hx+1 ;
|
* Dx ), hx+1 := AES( key = hx ; q ) XOR q, Cx+1 := AES( key = hx+1 ;
|
||||||
* Dx+1 ), ... hy := AES( key = hy-1 ; q ) XOR q, Cy := AES( key = hy ;
|
* Dx+1 ), ... hy := AES( key = hy-1 ; q ) XOR q, Cy := AES( key = hy ;
|
||||||
|
@ -292,21 +297,21 @@ 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 CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt) {
|
||||||
uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0};
|
uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0};
|
||||||
|
|
||||||
if (datalen == 0 || datalen % CIPURSE_AES_KEY_LENGTH != 0)
|
if (datalen == 0 || datalen % CIPURSE_AES_KEY_LENGTH != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH);
|
memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (datalen > i) {
|
while (datalen > i) {
|
||||||
aes_encode(NULL, QConstant, ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, QConstant, ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH);
|
||||||
bin_xor(hx, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
bin_xor(hx, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
if (isEncrypt)
|
if (isEncrypt)
|
||||||
aes_encode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH);
|
||||||
else
|
else
|
||||||
aes_decode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH);
|
aes_decode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
memcpy(ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH);
|
memcpy(ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH);
|
||||||
i += CIPURSE_AES_KEY_LENGTH;
|
i += CIPURSE_AES_KEY_LENGTH;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +322,7 @@ void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen,
|
||||||
uint8_t pdata[datalen + CIPURSE_AES_KEY_LENGTH];
|
uint8_t pdata[datalen + CIPURSE_AES_KEY_LENGTH];
|
||||||
size_t pdatalen = 0;
|
size_t pdatalen = 0;
|
||||||
AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH);
|
AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
CipurseCEncryptDecrypt(ctx, pdata, pdatalen, encdata, true);
|
CipurseCEncryptDecrypt(ctx, pdata, pdatalen, encdata, true);
|
||||||
*encdatalen = pdatalen;
|
*encdatalen = pdatalen;
|
||||||
}
|
}
|
||||||
|
@ -328,10 +333,10 @@ void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L473
|
/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L473
|
||||||
*
|
*
|
||||||
* Generate OSPT MAC on the given input data.
|
* Generate OSPT MAC on the given input data.
|
||||||
* Data should be already padded.
|
* Data should be already padded.
|
||||||
*
|
*
|
||||||
* Calculation of Mi and ki+1: hx := ki , hx+1 := AES( key = hx ; Dx )
|
* Calculation of Mi and ki+1: hx := ki , hx+1 := AES( key = hx ; Dx )
|
||||||
* XOR Dx , hx+2 := AES( key = hx+1 ; Dx+1 ) XOR Dx+1, hx+3 := AES( key =
|
* XOR Dx , hx+2 := AES( key = hx+1 ; Dx+1 ) XOR Dx+1, hx+3 := AES( key =
|
||||||
* hx+2 ; Dx+2 ) XOR Dx+2, ... hy+1 := AES( key = hy ; Dy ) XOR Dy, ki+1 :=
|
* hx+2 ; Dx+2 ) XOR Dx+2, ... hy+1 := AES( key = hy ; Dy ) XOR Dy, ki+1 :=
|
||||||
|
@ -349,7 +354,7 @@ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uin
|
||||||
memcpy(ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH);
|
memcpy(ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH);
|
||||||
i += CIPURSE_AES_KEY_LENGTH;
|
i += CIPURSE_AES_KEY_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH);
|
aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH);
|
||||||
bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
||||||
memcpy(ctx->frameKey, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
memcpy(ctx->frameKey, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
@ -377,7 +382,7 @@ static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t orig
|
||||||
data[3] = apdu->P2;
|
data[3] = apdu->P2;
|
||||||
data[4] = apdu->Lc;
|
data[4] = apdu->Lc;
|
||||||
*datalen = 5 + apdu->Lc;
|
*datalen = 5 + apdu->Lc;
|
||||||
|
|
||||||
if (ctx->RequestSecurity == CPSMACed || ctx->RequestSecurity == CPSEncrypted)
|
if (ctx->RequestSecurity == CPSMACed || ctx->RequestSecurity == CPSEncrypted)
|
||||||
*datalen = 5 + originalLc;
|
*datalen = 5 + originalLc;
|
||||||
memcpy(&data[5], apdu->data, *datalen);
|
memcpy(&data[5], apdu->data, *datalen);
|
||||||
|
@ -387,12 +392,12 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu,
|
||||||
uint8_t mac[CIPURSE_MAC_LENGTH] = {0};
|
uint8_t mac[CIPURSE_MAC_LENGTH] = {0};
|
||||||
uint8_t buf[260] = {0};
|
uint8_t buf[260] = {0};
|
||||||
size_t buflen = 0;
|
size_t buflen = 0;
|
||||||
|
|
||||||
memcpy(dstapdu, srcapdu, sizeof(sAPDU));
|
memcpy(dstapdu, srcapdu, sizeof(sAPDU));
|
||||||
|
|
||||||
if (isCipurseCChannelSecuritySet(ctx) == false)
|
if (isCipurseCChannelSecuritySet(ctx) == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dstapdu->CLA |= 0x04;
|
dstapdu->CLA |= 0x04;
|
||||||
dstapdu->data = dstdatabuf;
|
dstapdu->data = dstdatabuf;
|
||||||
dstapdu->data[0] = CipurseCGetSMI(ctx, includeLe);
|
dstapdu->data[0] = CipurseCGetSMI(ctx, includeLe);
|
||||||
|
@ -406,23 +411,23 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu,
|
||||||
|
|
||||||
switch (ctx->RequestSecurity) {
|
switch (ctx->RequestSecurity) {
|
||||||
case CPSNone:
|
case CPSNone:
|
||||||
break;
|
break;
|
||||||
case CPSPlain:
|
case CPSPlain:
|
||||||
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
||||||
CipurseCCalcMACPadded(ctx, buf, buflen, NULL);
|
CipurseCCalcMACPadded(ctx, buf, buflen, NULL);
|
||||||
break;
|
break;
|
||||||
case CPSMACed:
|
case CPSMACed:
|
||||||
dstapdu->Lc += CIPURSE_MAC_LENGTH;
|
dstapdu->Lc += CIPURSE_MAC_LENGTH;
|
||||||
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
||||||
CipurseCCalcMACPadded(ctx, buf, buflen, mac);
|
CipurseCCalcMACPadded(ctx, buf, buflen, mac);
|
||||||
memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH);
|
memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH);
|
||||||
break;
|
break;
|
||||||
case CPSEncrypted:
|
case CPSEncrypted:
|
||||||
dstapdu->Lc = srcapdu->Lc + CIPURSE_MIC_LENGTH;
|
dstapdu->Lc = srcapdu->Lc + CIPURSE_MIC_LENGTH;
|
||||||
dstapdu->Lc += CIPURSE_AES_BLOCK_LENGTH - dstapdu->Lc % CIPURSE_AES_BLOCK_LENGTH + 1; // 1 - SMI
|
dstapdu->Lc += CIPURSE_AES_BLOCK_LENGTH - dstapdu->Lc % CIPURSE_AES_BLOCK_LENGTH + 1; // 1 - SMI
|
||||||
if (includeLe)
|
if (includeLe)
|
||||||
dstapdu->Lc++;
|
dstapdu->Lc++;
|
||||||
|
|
||||||
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen);
|
||||||
CipurseCGenerateMIC(buf, buflen, mac);
|
CipurseCGenerateMIC(buf, buflen, mac);
|
||||||
buf[0] = dstapdu->CLA;
|
buf[0] = dstapdu->CLA;
|
||||||
|
@ -433,9 +438,9 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu,
|
||||||
memcpy(&buf[4 + srcapdu->Lc], mac, CIPURSE_MIC_LENGTH);
|
memcpy(&buf[4 + srcapdu->Lc], mac, CIPURSE_MIC_LENGTH);
|
||||||
//PrintAndLogEx(INFO, "data plain[%d]: %s", 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, sprint_hex(buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH));
|
//PrintAndLogEx(INFO, "data plain[%d]: %s", 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, sprint_hex(buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH));
|
||||||
CipurseCChannelEncrypt(ctx, buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, &dstdatabuf[1], &buflen);
|
CipurseCChannelEncrypt(ctx, buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, &dstdatabuf[1], &buflen);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -450,37 +455,37 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat
|
||||||
*dstdatalen = 0;
|
*dstdatalen = 0;
|
||||||
if (sw != NULL)
|
if (sw != NULL)
|
||||||
*sw = 0;
|
*sw = 0;
|
||||||
|
|
||||||
if (srcdatalen < 2)
|
if (srcdatalen < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
srcdatalen -= 2;
|
srcdatalen -= 2;
|
||||||
uint16_t xsw = srcdata[srcdatalen] * 0x0100 + srcdata[srcdatalen + 1];
|
uint16_t xsw = srcdata[srcdatalen] * 0x0100 + srcdata[srcdatalen + 1];
|
||||||
if (sw)
|
if (sw)
|
||||||
*sw = xsw;
|
*sw = xsw;
|
||||||
|
|
||||||
if (isCipurseCChannelSecuritySet(ctx) == false) {
|
if (isCipurseCChannelSecuritySet(ctx) == false) {
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
if (dstdatalen != NULL)
|
if (dstdatalen != NULL)
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctx->ResponseSecurity) {
|
switch (ctx->ResponseSecurity) {
|
||||||
case CPSNone:
|
case CPSNone:
|
||||||
break;
|
break;
|
||||||
case CPSPlain:
|
case CPSPlain:
|
||||||
memcpy(buf, srcdata, srcdatalen);
|
memcpy(buf, srcdata, srcdatalen);
|
||||||
buflen = srcdatalen;
|
buflen = srcdatalen;
|
||||||
memcpy(&buf[buflen], &srcdata[srcdatalen], 2);
|
memcpy(&buf[buflen], &srcdata[srcdatalen], 2);
|
||||||
buflen += 2;
|
buflen += 2;
|
||||||
CipurseCCalcMACPadded(ctx, buf, buflen, NULL);
|
CipurseCCalcMACPadded(ctx, buf, buflen, NULL);
|
||||||
|
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
if (dstdatalen != NULL)
|
if (dstdatalen != NULL)
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
break;
|
break;
|
||||||
case CPSMACed:
|
case CPSMACed:
|
||||||
if (srcdatalen < CIPURSE_MAC_LENGTH)
|
if (srcdatalen < CIPURSE_MAC_LENGTH)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -496,28 +501,28 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat
|
||||||
memcpy(dstdata, srcdata, srcdatalen);
|
memcpy(dstdata, srcdata, srcdatalen);
|
||||||
if (dstdatalen != NULL)
|
if (dstdatalen != NULL)
|
||||||
*dstdatalen = srcdatalen;
|
*dstdatalen = srcdatalen;
|
||||||
break;
|
break;
|
||||||
case CPSEncrypted:
|
case CPSEncrypted:
|
||||||
CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen);
|
CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen);
|
||||||
//PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen));
|
//PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen));
|
||||||
|
|
||||||
micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH;
|
micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH;
|
||||||
memcpy(micdata, buf, buflen);
|
memcpy(micdata, buf, buflen);
|
||||||
memcpy(&micdata[micdatalen], &buf[buflen - 2], 2);
|
memcpy(&micdata[micdatalen], &buf[buflen - 2], 2);
|
||||||
micdatalen += 2;
|
micdatalen += 2;
|
||||||
|
|
||||||
if (CipurseCCheckMIC(micdata, micdatalen, &buf[micdatalen - 2]) == false) {
|
if (CipurseCCheckMIC(micdata, micdatalen, &buf[micdatalen - 2]) == false) {
|
||||||
PrintAndLogEx(ERR, "APDU response MIC is not valid!");
|
PrintAndLogEx(ERR, "APDU response MIC is not valid!");
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dstdata, buf, micdatalen - 2);
|
memcpy(dstdata, buf, micdatalen - 2);
|
||||||
if (dstdatalen != NULL)
|
if (dstdatalen != NULL)
|
||||||
*dstdatalen = micdatalen - 2;
|
*dstdatalen = micdatalen - 2;
|
||||||
if (sw)
|
if (sw)
|
||||||
*sw = micdata[micdatalen - 2] * 0x0100 + micdata[micdatalen - 1];
|
*sw = micdata[micdatalen - 2] * 0x0100 + micdata[micdatalen - 1];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,19 +35,19 @@ typedef enum {
|
||||||
typedef struct CipurseContextS {
|
typedef struct CipurseContextS {
|
||||||
uint8_t keyId;
|
uint8_t keyId;
|
||||||
uint8_t key[CIPURSE_AES_KEY_LENGTH];
|
uint8_t key[CIPURSE_AES_KEY_LENGTH];
|
||||||
|
|
||||||
uint8_t RP[CIPURSE_AES_KEY_LENGTH];
|
uint8_t RP[CIPURSE_AES_KEY_LENGTH];
|
||||||
uint8_t rP[CIPURSE_SECURITY_PARAM_N];
|
uint8_t rP[CIPURSE_SECURITY_PARAM_N];
|
||||||
uint8_t RT[CIPURSE_AES_KEY_LENGTH];
|
uint8_t RT[CIPURSE_AES_KEY_LENGTH];
|
||||||
uint8_t rT[CIPURSE_SECURITY_PARAM_N];
|
uint8_t rT[CIPURSE_SECURITY_PARAM_N];
|
||||||
|
|
||||||
uint8_t k0[CIPURSE_AES_KEY_LENGTH];
|
uint8_t k0[CIPURSE_AES_KEY_LENGTH];
|
||||||
uint8_t cP[CIPURSE_AES_KEY_LENGTH];
|
uint8_t cP[CIPURSE_AES_KEY_LENGTH];
|
||||||
uint8_t CT[CIPURSE_AES_KEY_LENGTH];
|
uint8_t CT[CIPURSE_AES_KEY_LENGTH];
|
||||||
|
|
||||||
uint8_t frameKey[CIPURSE_AES_KEY_LENGTH];
|
uint8_t frameKey[CIPURSE_AES_KEY_LENGTH];
|
||||||
uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH];
|
uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH];
|
||||||
|
|
||||||
CipurseChannelSecurityLevel RequestSecurity;
|
CipurseChannelSecurityLevel RequestSecurity;
|
||||||
CipurseChannelSecurityLevel ResponseSecurity;
|
CipurseChannelSecurityLevel ResponseSecurity;
|
||||||
} CipurseContext;
|
} CipurseContext;
|
||||||
|
|
|
@ -128,7 +128,7 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
res = PM3_SUCCESS;
|
res = PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, " Searching for Cipurse tag...");
|
PrintAndLogEx(INPLACE, " Searching for Cipurse tag...");
|
||||||
if (IfPm3Iso14443a()) {
|
if (IfPm3Iso14443a()) {
|
||||||
|
|
|
@ -86,7 +86,7 @@ static int CmdHFCipurseInfo(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
PrintAndLogEx(INFO, "Info file: " _GREEN_("OK"));
|
PrintAndLogEx(INFO, "Info file: " _GREEN_("OK"));
|
||||||
PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len));
|
PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len));
|
||||||
|
@ -119,13 +119,13 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
keyId = arg_get_int_def(ctx, 3, 1);
|
keyId = arg_get_int_def(ctx, 3, 1);
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 16) {
|
if (hdatalen && hdatalen != 16) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only.");
|
||||||
|
@ -134,39 +134,39 @@ static int CmdHFCipurseAuth(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
|
memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
|
uint8_t kvv[CIPURSE_KVV_LENGTH] = {0};
|
||||||
CipurseCGetKVV(key, kvv);
|
CipurseCGetKVV(key, kvv);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "Key id: %d key: %s KVV: %s", keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH));
|
PrintAndLogEx(INFO, "Key id: %d key: %s KVV: %s", keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH));
|
||||||
|
|
||||||
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
|
bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose);
|
||||||
|
|
||||||
if (verbose == false) {
|
if (verbose == false) {
|
||||||
if (bres)
|
if (bres)
|
||||||
PrintAndLogEx(INFO, "Authentication " _GREEN_("OK"));
|
PrintAndLogEx(INFO, "Authentication " _GREEN_("OK"));
|
||||||
else
|
else
|
||||||
PrintAndLogEx(ERR, "Authentication " _RED_("ERROR"));
|
PrintAndLogEx(ERR, "Authentication " _RED_("ERROR"));
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return bres ? PM3_SUCCESS : PM3_ESOFT;
|
return bres ? PM3_SUCCESS : PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
|
static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) {
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 16) {
|
if (hdatalen && hdatalen != 16) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only.");
|
||||||
|
@ -175,12 +175,12 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
|
memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH);
|
||||||
|
|
||||||
*sreq = CPSMACed;
|
*sreq = CPSMACed;
|
||||||
*sresp = CPSMACed;
|
*sresp = CPSMACed;
|
||||||
|
|
||||||
char cdata[250] = {0};
|
char cdata[250] = {0};
|
||||||
int cdatalen = sizeof(cdata);
|
int cdatalen = sizeof(cdata);
|
||||||
cdatalen--; // for trailer 0x00
|
cdatalen--; // for trailer 0x00
|
||||||
CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen);
|
CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen);
|
||||||
if (cdatalen) {
|
if (cdatalen) {
|
||||||
|
@ -197,7 +197,7 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cdatalen = sizeof(cdata);
|
cdatalen = sizeof(cdata);
|
||||||
memset(cdata, 0, cdatalen);
|
memset(cdata, 0, cdatalen);
|
||||||
cdatalen--; // for trailer 0x00
|
cdatalen--; // for trailer 0x00
|
||||||
CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen);
|
CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen);
|
||||||
|
@ -214,7 +214,7 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,11 +244,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
||||||
|
|
||||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
|
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
|
||||||
|
@ -258,9 +258,9 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t fileId = 0x2ff7;
|
uint16_t fileId = 0x2ff7;
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 2) {
|
if (hdatalen && hdatalen != 2) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
||||||
|
@ -269,7 +269,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
fileId = (hdata[0] << 8) + hdata[1];
|
fileId = (hdata[0] << 8) + hdata[1];
|
||||||
|
|
||||||
size_t offset = arg_get_int_def(ctx, 6, 0);
|
size_t offset = arg_get_int_def(ctx, 6, 0);
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 7);
|
bool noAuth = arg_get_lit(ctx, 7);
|
||||||
|
@ -277,14 +277,14 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
||||||
|
|
||||||
|
@ -296,11 +296,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set channel security levels
|
// set channel security levels
|
||||||
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -311,7 +311,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
||||||
|
|
||||||
res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
|
res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -319,12 +319,12 @@ static int CmdHFCipurseReadFile(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
PrintAndLogEx(INFO, "File id: %x is empty", fileId);
|
PrintAndLogEx(INFO, "File id: %x is empty", fileId);
|
||||||
else
|
else
|
||||||
PrintAndLogEx(INFO, "File id: %x data[%d]: %s", fileId, len, sprint_hex(buf, len));
|
PrintAndLogEx(INFO, "File id: %x data[%d]: %s", fileId, len, sprint_hex(buf, len));
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -356,11 +356,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
||||||
|
|
||||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
|
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp);
|
||||||
|
@ -370,9 +370,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t fileId = 0x2ff7;
|
uint16_t fileId = 0x2ff7;
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 2) {
|
if (hdatalen && hdatalen != 2) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
||||||
|
@ -381,12 +381,12 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
fileId = (hdata[0] << 8) + hdata[1];
|
fileId = (hdata[0] << 8) + hdata[1];
|
||||||
|
|
||||||
size_t offset = arg_get_int_def(ctx, 6, 0);
|
size_t offset = arg_get_int_def(ctx, 6, 0);
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 7);
|
bool noAuth = arg_get_lit(ctx, 7);
|
||||||
|
|
||||||
hdatalen = sizeof(hdata);
|
hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
||||||
if (hdatalen == 0) {
|
if (hdatalen == 0) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0.");
|
||||||
|
@ -397,14 +397,14 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
||||||
PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
|
PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen));
|
||||||
|
@ -418,11 +418,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set channel security levels
|
// set channel security levels
|
||||||
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -433,7 +433,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
||||||
|
|
||||||
res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -441,9 +441,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File id: %x successfully written.", fileId);
|
PrintAndLogEx(INFO, "File id: %x successfully written.", fileId);
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -470,16 +470,16 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
arg_lit0(NULL, "noauth", "read file attributes without authentication"),
|
arg_lit0(NULL, "noauth", "read file attributes without authentication"),
|
||||||
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
arg_str0(NULL, "sreq", "<plain|mac(default)|encode>", "communication reader-PICC security level"),
|
||||||
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
arg_str0(NULL, "sresp", "<plain|mac(default)|encode>", "communication PICC-reader security level"),
|
||||||
arg_lit0(NULL, "sel-adf","show info about ADF itself"),
|
arg_lit0(NULL, "sel-adf", "show info about ADF itself"),
|
||||||
arg_lit0(NULL, "sel-mf", "show info about master file"),
|
arg_lit0(NULL, "sel-mf", "show info about master file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
||||||
|
|
||||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp);
|
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp);
|
||||||
|
@ -489,9 +489,9 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t fileId = 0x2ff7;
|
uint16_t fileId = 0x2ff7;
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 2) {
|
if (hdatalen && hdatalen != 2) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
||||||
|
@ -500,23 +500,23 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
fileId = (hdata[0] << 8) + hdata[1];
|
fileId = (hdata[0] << 8) + hdata[1];
|
||||||
|
|
||||||
bool noAuth = arg_get_lit(ctx, 6);
|
bool noAuth = arg_get_lit(ctx, 6);
|
||||||
|
|
||||||
bool seladf = arg_get_lit(ctx, 9);
|
bool seladf = arg_get_lit(ctx, 9);
|
||||||
bool selmf = arg_get_lit(ctx, 10);
|
bool selmf = arg_get_lit(ctx, 10);
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
||||||
|
|
||||||
|
@ -528,7 +528,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set channel security levels
|
// set channel security levels
|
||||||
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
||||||
}
|
}
|
||||||
|
@ -538,7 +538,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw);
|
||||||
else
|
else
|
||||||
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||||
|
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw);
|
||||||
|
@ -549,7 +549,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId);
|
||||||
|
|
||||||
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -557,18 +557,18 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
PrintAndLogEx(WARNING, "File id: %x attributes is empty", fileId);
|
PrintAndLogEx(WARNING, "File id: %x attributes is empty", fileId);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "File id: %x attributes[%d]: %s", fileId, len, sprint_hex(buf, len));
|
PrintAndLogEx(INFO, "File id: %x attributes[%d]: %s", fileId, len, sprint_hex(buf, len));
|
||||||
|
|
||||||
CIPURSEPrintFileAttr(buf, len);
|
CIPURSEPrintFileAttr(buf, len);
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -597,11 +597,11 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(ctx, 1);
|
bool APDULogging = arg_get_lit(ctx, 1);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
uint8_t keyId = arg_get_int_def(ctx, 3, 1);
|
||||||
|
|
||||||
CipurseChannelSecurityLevel sreq = CPSMACed;
|
CipurseChannelSecurityLevel sreq = CPSMACed;
|
||||||
CipurseChannelSecurityLevel sresp = CPSMACed;
|
CipurseChannelSecurityLevel sresp = CPSMACed;
|
||||||
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp);
|
int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp);
|
||||||
|
@ -611,9 +611,9 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t fileId = 0x2ff7;
|
uint16_t fileId = 0x2ff7;
|
||||||
|
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
int hdatalen = sizeof(hdata);
|
int hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 2) {
|
if (hdatalen && hdatalen != 2) {
|
||||||
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only.");
|
||||||
|
@ -622,18 +622,18 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (hdatalen)
|
if (hdatalen)
|
||||||
fileId = (hdata[0] << 8) + hdata[1];
|
fileId = (hdata[0] << 8) + hdata[1];
|
||||||
|
|
||||||
SetAPDULogging(APDULogging);
|
SetAPDULogging(APDULogging);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw);
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH));
|
||||||
|
|
||||||
|
@ -644,10 +644,10 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set channel security levels
|
// set channel security levels
|
||||||
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
CIPURSECSetActChannelSecurityLevels(sreq, sresp);
|
||||||
|
|
||||||
res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
|
res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw);
|
||||||
if (res != 0 || sw != 0x9000) {
|
if (res != 0 || sw != 0x9000) {
|
||||||
if (verbose == false)
|
if (verbose == false)
|
||||||
|
@ -657,7 +657,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "File id: 04x deleted " _GREEN_("succesfully"), fileId);
|
PrintAndLogEx(INFO, "File id: 04x deleted " _GREEN_("succesfully"), fileId);
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue