working PoC for secure messaging

This commit is contained in:
nganhkhoa 2023-03-01 13:05:04 +07:00
parent ce0fe6788c
commit 10a40be1b0
2 changed files with 77 additions and 30 deletions

View File

@ -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);
}

View File

@ -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;