working PoC for secure messaging
This commit is contained in:
parent
ce0fe6788c
commit
10a40be1b0
@ -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);
|
||||
}
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user