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