dataAuthentication.js
Summary
The class DataAuthentication supports Static Data Authentication and Dynamic Data Authentication.
function DataAuthentication(emv) {
this.emv = emv;
this.crypto= emv.crypto;
this.schemePublicKeyTable = [];
}
DataAuthentication.prototype.getRID = function() {
var aid = this.emv.cardDE[EMV.AID];
var rid = aid.left(5);
return(rid);
}
DataAuthentication.prototype.getPubKeyIndex = function() {
var index = this.emv.cardDE[0x8F];
var index = index.toUnsigned();
return(index);
}
DataAuthentication.prototype.addSchemePublicKey = function(rid, index, key) {
if(typeof(this.schemePublicKeyTable[rid.toString(HEX)]) == "undefined") {
this.schemePublicKeyTable[rid.toString(HEX)] = [];
}
this.schemePublicKeyTable[rid.toString(HEX)][index] = key;
}
DataAuthentication.prototype.getSchemePublicKey = function() {
var rid = this.getRID();
var index = this.getPubKeyIndex();
if (typeof(this.schemePublicKeyTable[rid.toString(HEX)]) == "undefined") {
throw new GPError("DataAuthentication", GPError.OBJECT_NOT_FOUND, 0, "No scheme public key found for RID " + rid.toString(HEX));
}
var key = this.schemePublicKeyTable[rid.toString(HEX)][index];
return(key);
}
DataAuthentication.prototype.decryptIssuerPKCertificate = function() {
var certificate = this.emv.cardDE[0x90];
var key = this.getSchemePublicKey();
var decryptedCertificate = crypto.decrypt(key, Crypto.RSA, certificate);
return(decryptedCertificate);
}
DataAuthentication.prototype.retrieveIssuerPublicKey = function() {
var key = this.getSchemePublicKey();
var modulus = key.getComponent(Key.MODULUS);
var cert = this.decryptIssuerPKCertificate();
assert(cert.length == modulus.length);
assert(cert.byteAt(modulus.length - 1) == 0xBC);
assert(cert.byteAt(0) == 0x6A);
assert(cert.byteAt(1) == 0x02);
var list;
list = cert.bytes(1, 14 + (modulus.length - 36));
var remainder = this.emv.cardDE[0x92];
var exponent = this.emv.cardDE[0x9F32];
var remex = remainder.concat(exponent);
list = list.concat(remex);
var hashConcat = this.crypto.digest(Crypto.SHA_1, list);
var hashCert = cert.bytes(15 + (modulus.length - 36), 20);
assert(hashCert.equals(hashConcat));
var pan = this.emv.cardDE[0x5A];
pan = pan.left(4);
var panCert = cert.bytes(2, 4);
var panCert = panCert.toString(HEX);
var pan = pan.toString(HEX);
for(var i = 0; i < 8; i++) {
if(panCert.charAt(i) == 'F') {
var panCert = panCert.substr(0, i);
var pan = pan.substr(0, i);
}
}
assert(pan == panCert);
var pkAlgorithmIndicator = cert.byteAt(12);
var leftmostDigits = cert.bytes(15, (modulus.length - 36));
var issuerPublicKeyModulus = leftmostDigits.concat(remainder);
return(issuerPublicKeyModulus);
}
DataAuthentication.prototype.verifySSAD = function(issuerPublicKeyModulus) {
var issuerPublicKeyModulus = issuerPublicKeyModulus;
var key = new Key();
key.setType(Key.PUBLIC);
key.setComponent(Key.MODULUS, issuerPublicKeyModulus);
key.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F32]);
var SSAD = this.emv.cardDE[0x93];
assert(SSAD.length == issuerPublicKeyModulus.length);
var decryptedSSAD = crypto.decrypt(key, Crypto.RSA, SSAD);
assert(decryptedSSAD.byteAt(decryptedSSAD.length -1) == 0xBC);
assert(decryptedSSAD.byteAt(0) == 0x6A);
assert(decryptedSSAD.byteAt(1) == 0x03);
var list = decryptedSSAD.bytes(1, (decryptedSSAD.length - 22));
var daInput = this.emv.getDAInput();
var sdaTagList = this.emv.cardDE[0x9F4A];
var value = new ByteBuffer();
if(typeof(sdaTagList != "undefined")) {
for(var i = 0; i < sdaTagList.length; i++) {
var tag = sdaTagList.byteAt(i);
value = value.append(this.emv.cardDE[tag]);
}
}
list = list.concat(daInput);
if(value != 0) {
value = value.toByteString();
list = list.concat(value);
}
var hashConcat = this.crypto.digest(Crypto.SHA_1, list);
var hashSSAD = decryptedSSAD.bytes(decryptedSSAD.length - 21, 20);
assert(hashConcat.equals(hashSSAD));
this.emv.cardDE[0x9F45] = decryptedSSAD.bytes(3, 2);
print("<-----------------------------SDA was successful------------------------------>\n");
}
DataAuthentication.prototype.retrieveICCPublicKey = function(issuerPublicKeyModulus) {
var issuerPublicKeyModulus = issuerPublicKeyModulus;
var key = new Key();
key.setType(Key.PUBLIC);
key.setComponent(Key.MODULUS, issuerPublicKeyModulus);
key.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F32]);
var iccCert = this.emv.cardDE[0x9F46];
assert(iccCert.length == issuerPublicKeyModulus.length);
var decryptedICC = crypto.decrypt(key, Crypto.RSA, iccCert);
assert(decryptedICC.byteAt(decryptedICC.length - 1) == 0xBC);
assert(decryptedICC.byteAt(0) == 0x6A);
assert(decryptedICC.byteAt(1) == 0x04);
var list = decryptedICC.bytes(1, (decryptedICC.length - 22));
var remainder = this.emv.cardDE[0x9F48];
var exponent = this.emv.cardDE[0x9F47];
var remex = remainder.concat(exponent);
list = list.concat(remex);
var daInput = this.emv.getDAInput();
list = list.concat(daInput);
var sdaTagList = this.emv.cardDE[0x9F4A];
if(typeof(sdaTagList != "undefined")) {
var value = new ByteBuffer();
for(var i = 0; i < sdaTagList.length; i++) {
var tag = sdaTagList.byteAt(i);
value = value.append(this.emv.cardDE[tag]);
}
value = value.toByteString();
list = list.concat(value);
}
var hashConcat = this.crypto.digest(Crypto.SHA_1, list);
var hashICC = decryptedICC.bytes(decryptedICC.length - 21, 20);
assert(hashConcat.equals(hashICC));
var pan = this.emv.cardDE[0x5A];
var panCert = decryptedICC.bytes(2, 10);
var panCert = panCert.toString(HEX);
var pan = pan.toString(HEX);
for(var i = 0; i < 20; i++) {
if(panCert.charAt(i) == 'F') {
var panCert = panCert.substr(0, i);
var pan = pan.substr(0, i);
}
}
assert(pan == panCert);
var pkAlgorithmIndicator = decryptedICC.byteAt(18);
var modulus = key.getComponent(Key.MODULUS);
var leftmostDigits = decryptedICC.bytes(21, (modulus.length - 42));
var iccPublicKeyModulus = leftmostDigits.concat(remainder);
return(iccPublicKeyModulus)
}
DataAuthentication.prototype.dynamicDataAuthentication = function(iccPublicKeyModulus) {
var iccPublicKeyModulus = iccPublicKeyModulus;
var Data = crypto.generateRandom(4);
var internalAuthenticate = card.sendApdu(0x00, 0x88, 0x00, 0x00, Data, 0x00);
var asn = new ASN1(internalAuthenticate);
var tag = asn.find(0x9F4B);
var SDAD = tag.value;
var picKey = new Key();
picKey.setType(Key.PUBLIC);
picKey.setComponent(Key.MODULUS, iccPublicKeyModulus);
picKey.setComponent(Key.EXPONENT, this.emv.cardDE[0x9F47]);
var decryptedSDAD = crypto.decrypt(picKey, Crypto.RSA, SDAD);
assert(SDAD.length == iccPublicKeyModulus.length);
assert(decryptedSDAD.byteAt(decryptedSDAD.length - 1) == 0xBC);
assert(decryptedSDAD.byteAt(0) == 0x6A);
assert(decryptedSDAD.byteAt(1) == 0x05);
var LDD = decryptedSDAD.byteAt(3);
var list = decryptedSDAD.bytes(1, 3 + LDD + decryptedSDAD.length - LDD - 25);
list = list.concat(Data);
var hashConcat = this.crypto.digest(Crypto.SHA_1, list);
var hashSDAD = decryptedSDAD.bytes(decryptedSDAD.length - 21, 20);
assert(hashConcat.equals(hashSDAD));
print("<-----------------------------DDA was successful------------------------------>\n");
}
Documentation generated by
JSDoc on Tue Sep 3 22:29:44 2013