diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 2ddd94554..0fa1c6911 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -38,7 +38,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, DropField(); msleep(50); } - + // long messages is not allowed if (apdu.Lc > 228) return 20; @@ -50,7 +50,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, xle = Le; CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le); - + if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) { PrintAndLogEx(ERR, "APDU encoding error."); return 201; @@ -66,11 +66,11 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, 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) @@ -81,10 +81,10 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw); memcpy(Result, securedata, rlen); } - + if (ResultLen != NULL) *ResultLen = rlen; - + if (sw != NULL) *sw = isw; @@ -158,13 +158,13 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { 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); @@ -172,7 +172,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { // 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) { @@ -186,22 +186,22 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { 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; } @@ -257,7 +257,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR")); return; } - + PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------"); if (fileAttr[0] == 0x38) { PrintAndLogEx(INFO, "Type: MF, ADF"); @@ -281,14 +281,14 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { 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]); } @@ -296,7 +296,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { 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)); @@ -307,7 +307,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { 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) @@ -322,27 +322,27 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { 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"); } - + } - - + + } diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 7e31fba07..e68adc14f 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -27,16 +27,21 @@ uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x74, 0x74, 0x74, 0x74, 0x74, 0x74, uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) { switch (lvl) { - case CPSNone: return 0x00; - case CPSPlain: return 0x00; - case CPSMACed: return 0x01; - case CPSEncrypted: return 0x02; - default: return 0x00; + case CPSNone: + return 0x00; + case CPSPlain: + 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) { - for(size_t i = 0; i < len; i++) + for (size_t i = 0; i < len; 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) { uint64_t res = 0; - + for (int i = 0; i < 48; i++) { res = rotateLeft48(res); if (res & 1) res = res ^ CIPURSE_POLY; y = rotateLeft48(y); if (y & 1) - res = res ^ x; + res = res ^ x; } 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) { uint64_t x64 = 0; uint64_t y64 = 0; - + for (int i = 0; i < 6; i++) { x64 = (x64 << 8) | x[i]; y64 = (y64 << 8) | y[i]; } - + uint64_t res64 = computeNLM48(x64, y64); - + for (int i = 0; i < 6; i++) { res[5 - i] = res64 & 0xff; res64 = res64 >> 8; } } -static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { +static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0}; - + // session key derivation function // kP := NLM(EXT(kID), rP) // 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_pad(temp2, CIPURSE_AES_KEY_LENGTH, ctx->rT, CIPURSE_SECURITY_PARAM_N); 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); bin_xor(ctx->k0, ctx->key, CIPURSE_AES_KEY_LENGTH); - + // first frame key k1, function to calculate k1, // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) 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); bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH); memcpy(ctx->frameKey, temp1, CIPURSE_AES_KEY_LENGTH); - + // function to caluclate cP := AES(key=k0, RP). // terminal response 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) { if (ctx == NULL) return; - + memset(ctx, 0, sizeof(CipurseContext)); } void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { if (ctx == NULL) return; - + CipurseCClearContext(ctx); - + ctx->keyId = keyId; memcpy(ctx->key, key, member_size(CipurseContext, key)); } @@ -174,7 +179,7 @@ bool isCipurseCChannelSecuritySet(CipurseContext *ctx) { void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { if (ctx == NULL) return; - + memcpy(ctx->RP, random, 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) { 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) + 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) { if (ctx == NULL) return; - + CipurseCSetRandomHost(ctx); CipurseCGenerateK0AndCp(ctx); CipurseCGenerateCT(ctx->k0, ctx->RT, ctx->CT); @@ -231,7 +236,7 @@ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) { 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; for (size_t i = 0; i < len; i++) { 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; uint8_t pdata[datalen + CIPURSE_MIC_LENGTH]; memset(pdata, 0, sizeof(pdata)); - + // 0x00 padding memcpy(pdata, data, datalen); plen = datalen; if (datalen % CIPURSE_MIC_LENGTH) plen += CIPURSE_MIC_LENGTH - datalen % CIPURSE_MIC_LENGTH; - + // crc uint16_t crc1 = CipurseCComputeMICCRC(pdata, plen); - + for (size_t i = 0; i < datalen; i += 4) { uint8_t tmp1 = pdata[i + 0]; 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 + 3] = tmp2; } - + uint16_t crc2 = CipurseCComputeMICCRC(pdata, plen); if (mic != NULL) { 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) { uint8_t xmic[CIPURSE_MIC_LENGTH] = {0}; - + CipurseCGenerateMIC(data, datalen, xmic); 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 - * + * * Encrypt/Decrypt the given data using ciphering mechanism explained the OPST. * Data should be already padded. - * + * * 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+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) { uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0}; - + if (datalen == 0 || datalen % CIPURSE_AES_KEY_LENGTH != 0) return; - + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { aes_encode(NULL, QConstant, ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); bin_xor(hx, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); - + if (isEncrypt) aes_encode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); else aes_decode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); - + memcpy(ctx->frameKeyNext, hx, 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]; size_t pdatalen = 0; AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH); - + CipurseCEncryptDecrypt(ctx, pdata, pdatalen, encdata, true); *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 - * + * * Generate OSPT MAC on the given input data. * Data should be already padded. - * + * * 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 = * 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); i += 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); 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[4] = apdu->Lc; *datalen = 5 + apdu->Lc; - + if (ctx->RequestSecurity == CPSMACed || ctx->RequestSecurity == CPSEncrypted) *datalen = 5 + originalLc; 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 buf[260] = {0}; size_t buflen = 0; - + memcpy(dstapdu, srcapdu, sizeof(sAPDU)); - + if (isCipurseCChannelSecuritySet(ctx) == false) return; - + dstapdu->CLA |= 0x04; dstapdu->data = dstdatabuf; dstapdu->data[0] = CipurseCGetSMI(ctx, includeLe); @@ -406,23 +411,23 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, switch (ctx->RequestSecurity) { case CPSNone: - break; - case CPSPlain: + break; + case CPSPlain: CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, NULL); - break; + break; case CPSMACed: dstapdu->Lc += CIPURSE_MAC_LENGTH; CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, mac); memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); - break; + break; case CPSEncrypted: dstapdu->Lc = srcapdu->Lc + CIPURSE_MIC_LENGTH; dstapdu->Lc += CIPURSE_AES_BLOCK_LENGTH - dstapdu->Lc % CIPURSE_AES_BLOCK_LENGTH + 1; // 1 - SMI if (includeLe) dstapdu->Lc++; - + CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCGenerateMIC(buf, buflen, mac); 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); //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); - break; - default: - break; + break; + default: + break; } } @@ -450,37 +455,37 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat *dstdatalen = 0; if (sw != NULL) *sw = 0; - + if (srcdatalen < 2) return; - + srcdatalen -= 2; uint16_t xsw = srcdata[srcdatalen] * 0x0100 + srcdata[srcdatalen + 1]; if (sw) *sw = xsw; - + if (isCipurseCChannelSecuritySet(ctx) == false) { memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; return; } - + switch (ctx->ResponseSecurity) { case CPSNone: - break; - case CPSPlain: + break; + case CPSPlain: memcpy(buf, srcdata, srcdatalen); buflen = srcdatalen; memcpy(&buf[buflen], &srcdata[srcdatalen], 2); buflen += 2; CipurseCCalcMACPadded(ctx, buf, buflen, NULL); - + memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; - break; - case CPSMACed: + break; + case CPSMACed: if (srcdatalen < CIPURSE_MAC_LENGTH) return; @@ -496,28 +501,28 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; - break; + break; case CPSEncrypted: CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen); //PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen)); - + micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH; memcpy(micdata, buf, buflen); memcpy(&micdata[micdatalen], &buf[buflen - 2], 2); micdatalen += 2; - + if (CipurseCCheckMIC(micdata, micdatalen, &buf[micdatalen - 2]) == false) { PrintAndLogEx(ERR, "APDU response MIC is not valid!"); } - + memcpy(dstdata, buf, micdatalen - 2); if (dstdatalen != NULL) *dstdatalen = micdatalen - 2; if (sw) *sw = micdata[micdatalen - 2] * 0x0100 + micdata[micdatalen - 1]; - break; - default: - break; + break; + default: + break; } - + } diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index b554f54de..189ba7c5a 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -35,19 +35,19 @@ typedef enum { 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; diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index ca4753d7c..6fd9faaac 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -128,7 +128,7 @@ int CmdHFSearch(const char *Cmd) { res = PM3_SUCCESS; } } - + PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for Cipurse tag..."); if (IfPm3Iso14443a()) { diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 4379d6b02..6ce7c8895 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -86,7 +86,7 @@ static int CmdHFCipurseInfo(const char *Cmd) { DropField(); return PM3_SUCCESS; } - + if (len > 0) { PrintAndLogEx(INFO, "Info file: " _GREEN_("OK")); PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len)); @@ -119,13 +119,13 @@ static int CmdHFCipurseAuth(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); keyId = arg_get_int_def(ctx, 3, 1); - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); if (hdatalen && hdatalen != 16) { 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) memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); 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)); bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); - + if (verbose == false) { if (bres) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); else PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); } - + DropField(); 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) { uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen); if (hdatalen && hdatalen != 16) { 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) memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); - + *sreq = CPSMACed; *sresp = CPSMACed; char cdata[250] = {0}; - int cdatalen = sizeof(cdata); + int cdatalen = sizeof(cdata); cdatalen--; // for trailer 0x00 CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &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); cdatalen--; // for trailer 0x00 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_SUCCESS; } @@ -244,11 +244,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); @@ -258,9 +258,9 @@ static int CmdHFCipurseReadFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -269,7 +269,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + size_t offset = arg_get_int_def(ctx, 6, 0); bool noAuth = arg_get_lit(ctx, 7); @@ -277,14 +277,14 @@ static int CmdHFCipurseReadFile(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) 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(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } - + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -311,7 +311,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -319,12 +319,12 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + if (len == 0) PrintAndLogEx(INFO, "File id: %x is empty", fileId); else PrintAndLogEx(INFO, "File id: %x data[%d]: %s", fileId, len, sprint_hex(buf, len)); - + DropField(); return PM3_SUCCESS; } @@ -356,11 +356,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); @@ -370,9 +370,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -381,12 +381,12 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + size_t offset = arg_get_int_def(ctx, 6, 0); bool noAuth = arg_get_lit(ctx, 7); - hdatalen = sizeof(hdata); + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen == 0) { PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0."); @@ -397,14 +397,14 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + 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, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen)); @@ -418,11 +418,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } - + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -433,7 +433,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -441,9 +441,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + PrintAndLogEx(INFO, "File id: %x successfully written.", fileId); - + DropField(); return PM3_SUCCESS; } @@ -470,16 +470,16 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { arg_lit0(NULL, "noauth", "read file attributes without authentication"), arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), arg_str0(NULL, "sresp", "", "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_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp); @@ -489,9 +489,9 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -500,23 +500,23 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + bool noAuth = arg_get_lit(ctx, 6); bool seladf = arg_get_lit(ctx, 9); bool selmf = arg_get_lit(ctx, 10); - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) 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(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } @@ -538,7 +538,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw); else res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); - + if (res != 0 || sw != 0x9000) { if (verbose == false) PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); @@ -549,7 +549,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -557,18 +557,18 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { DropField(); return PM3_ESOFT; } - + if (len == 0) { PrintAndLogEx(WARNING, "File id: %x attributes is empty", fileId); DropField(); return PM3_SUCCESS; } - + if (verbose) PrintAndLogEx(INFO, "File id: %x attributes[%d]: %s", fileId, len, sprint_hex(buf, len)); - + CIPURSEPrintFileAttr(buf, len); - + DropField(); return PM3_SUCCESS; } @@ -597,11 +597,11 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp); @@ -611,9 +611,9 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -622,18 +622,18 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) 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(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); - + res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -657,7 +657,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } PrintAndLogEx(INFO, "File id: 04x deleted " _GREEN_("succesfully"), fileId); - + DropField(); return PM3_SUCCESS; }