Amadis
AES Dukpt Online pin Example
Following the Neptune Lite version update(NeptuneLiteApi_V4.02.00_20230921), we can now perform iso4 pin mode.
The obtained KSN will be in the format below:
Depending on the length of your AES key, you may choose between AES 128, AES 192, AES 256.
Â
An example code will be provided below on the creation of the online pin and then the message creation.
public int do_online_pin(byte[] bytes) {
int ret = 0;
Log.d("do_online_pin","Starting online pin");
EnterPinFragment.openDialog();
try {
String expectPinLen = "4,5,6,7,8,9,10,11,12";
//ped.setKeyboardLayoutLandscape(false);
ped.setInputPinListener(EnterPinFragment.pedInputListener);
EnterPinFragment.setExpectPinLen(expectPinLen);
ped.setKeyboardRandom(false);
//ped.inputPin(expectPinLen, 300000, (byte)0x00);
TlvTree txContext = TlvTree.FromRaw(bytes);
String PAN = txContext.GetElementAscii(0xC7);
PAN = "0000" + PAN.substring(PAN.length() - 13, PAN.length() - 1);
byte[] accountNb = new byte[16];
for (int i = 0; i < 16; i++) {
accountNb[i] = Byte.parseByte(PAN.substring(i, i+1));
}
incrementKSNIfNecessary();
pindukptResult = ped.getAesDUKPTPin((byte)0x01,expectPinLen, accountNb, EAlgorithmType._AES128_, (byte) 0x24,300000);
String ksn = bytesToHex(pindukptResult.getKsn());
Log.d("pin", "ksn is:" + ksn);
String result = bytesToHex(pindukptResult.getResult());
Log.d("pin", "result is:" + result);
} catch (PedDevException e) {
e.printStackTrace();
ret = 1;
}
EnterPinFragment.closeDialog();
return ret;
}
Â
It is important to note that ISO4 == 0x24.
You can refer to Pax documentation if it is unclear.
The obtained KSN will be 12 bytes long.
public byte[] getOnlinePin(byte [] data) {
Log.d("getOnlinePin", "Getting pin block");
DUKPTResult result = pindukptResult;
byte [] encryptedPinBlock = result.getResult();
byte [] ksn = result.getKsn();
Log.d("getOnlinePin", "KSN is : " + hex(ksn) + " and encrypted pinblock is " + hex(encryptedPinBlock));
StringBuilder message = new StringBuilder();
message.append("<CrdhldrOnLinePIN>" +
"<NcrptdPINBlck>" +
"<CnttTp>EVLP</CnttTp>" +
"<EnvlpdData>" +
"<Vrsn>1</Vrsn>" +
"<Rcpt>" +
"<KEK>" +
"<Vrsn>1</Vrsn>" +
"<KEKId>" +
"<KeyId>nexoAESD128TestKey</KeyId>" +
"<KeyVrsn>20190522</KeyVrsn>" +
"<SeqNb>1</SeqNb>" +
"<DerivtnId>" + Base64.encodeToString(Arrays.copyOfRange(ksn, 0, 5), Base64.NO_WRAP) + "</DerivtnId>" +
"</KEKId>" +
"<KeyNcrptnAlgo>" +
"<Algo>DA12</Algo>" +
"</KeyNcrptnAlgo>" +
"<NcrptdKey>" + Base64.encodeToString(Arrays.copyOfRange(ksn, 5, 12), Base64.NO_WRAP) + "</NcrptdKey>" +
"</KEK>" +
"</Rcpt>" +
"<NcrptdCntt>" +
"<CnttTp>DATA</CnttTp>" +
"<CnttNcrptnAlgo>" +
"<Algo>EA2C</Algo>" +
"</CnttNcrptnAlgo>" +
"<NcrptdData>" + Base64.encodeToString(encryptedPinBlock, Base64.NO_WRAP) + "</NcrptdData>" +
"</NcrptdCntt>" +
"</EnvlpdData>" +
"</NcrptdPINBlck>" +
"<PINFrmt>ISO4</PINFrmt>" +
"</CrdhldrOnLinePIN>");
TlvTree cardholderpin = TlvTree.Empty();
cardholderpin.AddEnum(0xDF9F34, 0);
cardholderpin.AddAscii(0xDF9F14, message.toString());
Log.d("getOnlinePin", cardholderpin.Stringify());
return cardholderpin.AsBytes();
}