diff --git a/app/src/main/cpp/api.cpp b/app/src/main/cpp/api.cpp index 8a86bdb..6a0717e 100644 --- a/app/src/main/cpp/api.cpp +++ b/app/src/main/cpp/api.cpp @@ -42,10 +42,12 @@ bytes Connector::finalizeAPDU(int cla, int ins, int p1, int p2, int ne, bytes& d } Connector::Response Connector::sendICC(int cla, int ins, int p1, int p2, int ne, bytes& data) { + LOGI("========================================"); LOGI("send %02x%02x%02x%02x", cla, ins, p1, p2); logBytes(" send data %s", data); if (sm) { + LOGI("encrypting message"); // wrap cla |= ISO7816_CLA::SM_HEADER_AUTHN; @@ -66,14 +68,20 @@ Connector::Response Connector::sendICC(int cla, int ins, int p1, int p2, int ne, iso9797_pad(M); M.insert(M.end(), dataDO.begin(), dataDO.end()); M.insert(M.end(), do97.begin(), do97.end()); + logBytes("M %s", M); bytes N = sm->next_ssc(); N.insert(N.end(), M.begin(), M.end()); iso9797_pad(N); + logBytes("N %s", N); + bytes CC = sm->mac(N); bytes do8e = sm->do8e(CC); + logBytes("CC %s", CC); + logBytes("do8e %s", do8e); + data.clear(); data.insert(data.end(), dataDO.begin(), dataDO.end()); data.insert(data.end(), do97.begin(), do97.end()); @@ -82,15 +90,19 @@ Connector::Response Connector::sendICC(int cla, int ins, int p1, int p2, int ne, ne = 256; } bytes command = finalizeAPDU(cla, ins, p1, p2, ne, data); + LOGI(" send encrypted %02x%02x%02x%02x", cla, ins, p1, p2); + logBytes(" send encrypted data %s", data); + bytes raw_response = transceive(command); logBytes("raw response %s", raw_response); auto response = decodeResponse(raw_response); - logBytes(" raw decoded %s", response.data); LOGI(" status %02x%02x", response.code >> 8, response.code & 0x0f); logBytes(" raw %s", raw_response); + logBytes(" raw decoded %s", response.data); if (sm) { + LOGI("decrypting message"); // unwrap // data missing || data invalid @@ -99,24 +111,47 @@ Connector::Response Connector::sendICC(int cla, int ins, int p1, int p2, int ne, } if (response.data.empty()) return response; - auto do = sm->parseDO(response.data); - auto do99 = sm->parseDO99(response.data, do.size); - auto do8e = sm->parseDO8E(response.data, do99.size); - bytes K = sm->generateK(response.data, do8e); + // DO do8e can't be null, default to throw on null + auto DO = sm->parseDO(response.data); + auto do99 = sm->parseDO99(response.data, DO->size); // this can be null + auto do8e = sm->parseDO8E(response.data, DO->size + do99->size); + + logBytes("do %s", DO->value); + logBytes("do99 %s", do99->value); + logBytes("do8e %s", do8e->value); + + bytes K = sm->next_ssc(); + K.insert(K.end(), response.data.begin(), response.data.begin() + DO->size + do99->size); + iso9797_pad(K); + uint64_t CC = bytes2num(sm->mac(K)); + LOGI("mac check %llx", CC); - if (CC != bytes2num(do8e.value)) { - throw "Decoding message failure"; + if (CC != bytes2num(do8e->value)) { + throw "Decoding message failure: different mac"; } - response.data = sm->decrypt(do.value); - response.success = true; - response.code = do99; + if (DO->tag != 0x85 && DO->tag != 0x87) { + throw "Encrypted data has wrong tag"; + } + + bool isDO87 = DO->tag == 0x87; + bool isPadded = !isDO87 || DO->value[0] == 0x01; + if (isDO87) { + DO->value.erase(DO->value.begin()); + } + sm->decrypt(DO->value); + response.data = DO->value; + logBytes("decrypted %s", response.data); + if (isPadded) { + iso9797_unpad(response.data); + } + response.success = true; + response.code = (do99->value[0] << 8) | do99->value[1]; } - auto response = decodeResponse(raw_response); - logBytes(" decoded %s", response.data); LOGI(" status %02x%02x", response.code >> 8, response.code & 0x0f); - logBytes(" raw %s", raw_response); + logBytes(" decrypted raw %s", raw_response); + logBytes(" decrypted decoded %s", response.data); return response; } @@ -157,6 +192,7 @@ Connector::Response Connector::externalAuthenticate(bytes& eifd, uint64_t mifd) Connector::Response Connector::readBinaryBySFI(int sfi, int offset) { bytes t; + sfi |= 0x80; return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::READ_BINARY, sfi, offset, readAheadLength, t); } @@ -181,6 +217,7 @@ void Connector::initBAC() { int eLen = sLen; int macLen = 8; + // mrz = id's last 9 digits // mrz.padRight(9, '<') + mrz_check_digit // + birth yymmdd + birth_check_digit // + expiry yymmdd + expiry_check_digit @@ -218,7 +255,7 @@ void Connector::initBAC() { logBytes("S %s", S); bytes Eifd = tripledes_cbc_encrypt(S, Kenc1, Kenc2, Kenc1); - uint64_t Mifd = iso9797_mac(Eifd, Kmac1, Kmac2, Kmac1); + uint64_t Mifd = iso9797_mac(Eifd, Kmac1, Kmac2); logBytes("Eifd %s", Eifd); LOGI("Mifd: %llx", Mifd); @@ -233,14 +270,14 @@ void Connector::initBAC() { logBytes("Eicc %s", Eifd); LOGI("Micc: %llx", Micc); - uint64_t Micc_verify = iso9797_mac(Eicc, 0x58effeadb594fe7c, 0x8a43e9f8c2d0a408, 0x58effeadb594fe7c); + uint64_t Micc_verify = iso9797_mac(Eicc, Kmac1, Kmac2); LOGI("Verify Mac: %llx", Micc_verify); if (Micc != Micc_verify) { throw "Authentication fail"; } - const bytes R = tripledes_cbc_decrypt(Eicc, 0xfe43f1ab686eb334, 0xe68fea8cea31dfc7, 0xfe43f1ab686eb334); + const bytes R = tripledes_cbc_decrypt(Eicc, Kenc1, Kenc2, Kenc1); const bytes eRNDifd = bytes(R.begin() + nonceLen, R.begin() + nonceLen * 2); const bytes Kicc = bytes(R.begin() + nonceLen * 2, R.end()); @@ -278,5 +315,6 @@ void Connector::initBAC() { } void Connector::readEFCOM() { - + auto binary = readBinaryBySFI(EFCOM_SFI, 0); + auto decoded = TLV(binary.data); } \ No newline at end of file diff --git a/app/src/main/cpp/api.h b/app/src/main/cpp/api.h index 1cbf315..6ea229d 100644 --- a/app/src/main/cpp/api.h +++ b/app/src/main/cpp/api.h @@ -73,6 +73,7 @@ public: encoded.insert(encoded.end(), tag_encoded.begin(), tag_encoded.end()); encoded.insert(encoded.end(), len_encoded.begin(), len_encoded.end()); encoded.insert(value.end(), value.begin(), value.end()); + return encoded; } }; @@ -122,8 +123,10 @@ public: if (ne == 256 || ne == 65536) { return buildDO(0x97, bytes(ne == 256 ? 1 : 2)); } - // intToBin(ne, minLen=0) - return buildDO(0x97, bytes()); + auto b = num2bytes(ne); + auto ne_nbytes = bytecount(ne); + b.erase(b.begin(), b.begin() + 8 - ne_nbytes); + return buildDO(0x97, b); } bytes do85(bytes data) { return buildDO(0x85, data); @@ -140,33 +143,37 @@ public: } TLV* parseDO(bytes data) { - if (data.empty() || data[0] != 0x85 || data[0] != 0x87) { + if (data.empty() || (data[0] != 0x85 && data[0] != 0x87)) { return nullptr; } auto t = new TLV(data); return t; } - TLV parseDO99(bytes data, size_t offset) { - if (data.empty()) { + TLV* parseDO99(bytes data, size_t offset) { + if (data.empty() || data[offset] != 0x99) { return nullptr; } + auto t = new TLV(bytes(data.begin() + offset, data.end())); + return t; } - TLV parseDO8E(bytes data, size_t offset) { - + TLV* parseDO8E(bytes data, size_t offset) { + if (data.empty() || data[offset] != 0x8e) { + return nullptr; + } + auto t = new TLV(bytes(data.begin() + offset, data.end())); + return t; } - bytes generateK(bytes data, ) {} - bytes mac(bytes data) { const uint64_t Kmac1 = bytes2num(bytes(macKey.begin(), macKey.begin() + 8)); const uint64_t Kmac2 = bytes2num(bytes(macKey.begin() + 8, macKey.end())); - uint64_t m = iso9797_mac(data, Kmac1, Kmac2, Kmac1); + uint64_t m = iso9797_mac(data, Kmac1, Kmac2, Kmac1, false); return num2bytes(m); } - bytes encrypt(bytes& data) { + void encrypt(bytes& data) { const uint64_t Kenc1 = bytes2num(bytes(encKey.begin(), encKey.begin() + 8)); const uint64_t Kenc2 = bytes2num(bytes(encKey.begin() + 8, encKey.end())); @@ -174,7 +181,9 @@ public: data = d; } - bytes decrypt(bytes& data) { + void decrypt(bytes& data) { + if (data.empty()) return; + const uint64_t Kenc1 = bytes2num(bytes(encKey.begin(), encKey.begin() + 8)); const uint64_t Kenc2 = bytes2num(bytes(encKey.begin() + 8, encKey.end())); @@ -215,7 +224,7 @@ private: public: transceive_type transceive; - SecureMessaging* sm; + SecureMessaging* sm = nullptr; int readAheadLength = 8;