diff --git a/jpos/src/main/java/org/jpos/security/KeySerialNumber.java b/jpos/src/main/java/org/jpos/security/KeySerialNumber.java index 8497cc76b8..c08362f44e 100644 --- a/jpos/src/main/java/org/jpos/security/KeySerialNumber.java +++ b/jpos/src/main/java/org/jpos/security/KeySerialNumber.java @@ -23,6 +23,8 @@ import java.io.PrintStream; import java.io.Serializable; +import java.nio.ByteBuffer; +import java.util.Objects; /** @@ -31,31 +33,13 @@ * Transaction) method is used.
* Refer to ANSI X9.24 for more information about DUKPT * @author Hani S. Kirollos - * @version $Revision$ $Date$ * @see EncryptedPIN */ -public class KeySerialNumber - implements Serializable, Loggeable { - - private static final long serialVersionUID = -8388775376202253082L; - /** - * baseKeyID a HexString representing the BaseKeyID (also called KeySet ID) - */ - String baseKeyID; - /** - * deviceID a HexString representing the Device ID (also called TRSM ID) - */ - String deviceID; - /** - * transactionCounter a HexString representing the transaction counter - */ - String transactionCounter; - - /** - * Constructs a key serial number object - */ - public KeySerialNumber () { - } +public class KeySerialNumber implements Serializable, Loggeable { + private static final long serialVersionUID = 5588769944206835776L; + private long baseId; + private long deviceId; + private int transactionCounter; /** * Constructs a key serial number object @@ -64,87 +48,108 @@ public KeySerialNumber () { * @param transactionCounter a HexString representing the transaction counter */ public KeySerialNumber (String baseKeyID, String deviceID, String transactionCounter) { - setBaseKeyID(baseKeyID); - setDeviceID(deviceID); - setTransactionCounter(transactionCounter); + try { + baseKeyID = ISOUtil.padleft(baseKeyID, 10, 'F'); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid baseKeyID."); + } + baseId = Long.parseLong(baseKeyID, 16); + deviceId = Long.parseLong (deviceID, 16); + this.transactionCounter = Integer.parseInt (transactionCounter, 16); } - + /** - * Constructs a key serial number object from its hexadecimal representation. - * @param hexKSN hexadecimal representation of the KSN. - * @param idLength length of the base key ID. - * @param deviceLength length of the device ID. - * @param counterLength length of the transaction counter. + * Constructs a key serial number object from its binary representation. + * @param ksn binary representation of the KSN. */ - public KeySerialNumber(String hexKSN, int idLength, int deviceLength, int counterLength) { - if (hexKSN == null || hexKSN.trim().length() == 0) - throw new IllegalArgumentException("KSN cannot be empty."); - if (idLength + deviceLength + counterLength > hexKSN.length()) - throw new IllegalArgumentException("Length spec doesn't match KSN."); - setBaseKeyID(hexKSN.substring(0, idLength)); - setDeviceID(hexKSN.substring(idLength, idLength + deviceLength)); - setTransactionCounter(hexKSN.substring(idLength + deviceLength, idLength + deviceLength + counterLength)); + public KeySerialNumber(byte[] ksn) { + Objects.requireNonNull (ksn, "KSN cannot be null"); + if (ksn.length < 8 || ksn.length > 10) { + throw new IllegalArgumentException("KSN must be 8 to 10 bytes long."); + } + parseKsn (ksn); } - /** - * Constructs a key serial number object from its binary representation. - * @param binKSN binary representation of the KSN. - * @param idLength length of the base key ID. - * @param deviceLength length of the device ID. - * @param counterLength length of the transaction counter. + * Returns the base key ID as a hexadecimal string padded with leading zeros to a length of 10 characters. + * + * @return a String representing the base key ID. */ - public KeySerialNumber(byte[] binKSN, int idLength, int deviceLength, int counterLength) { - this(ISOUtil.byte2hex(binKSN).toUpperCase(), idLength, deviceLength, counterLength); + public String getBaseKeyID () { + return String.format ("%010X", baseId); } /** - * - * @param baseKeyID a HexString representing the BaseKeyID (also called KeySet ID) + * Returns the base key ID as an array of bytes. + * @return a 5 bytes array representing the base key ID. */ - public void setBaseKeyID (String baseKeyID) { - this.baseKeyID = baseKeyID; + public byte[] getBaseKeyIDBytes () { + ByteBuffer buf = ByteBuffer.allocate(8); + buf.putLong(baseId); + buf.position(3); + byte[] lastFive = new byte[5]; + buf.get(lastFive); + return lastFive; } /** - * - * @return baseKeyID a HexString representing the BaseKeyID (also called KeySet ID) + * Returns the device ID as a hexadecimal string padded with leading zeros to a length of 6 characters. + * @return a String representing the device ID. */ - public String getBaseKeyID () { - return baseKeyID; + public String getDeviceID () { + return String.format ("%06X", deviceId); } /** + * Returns the deviceID as an array of bytes. * - * @param deviceID a HexString representing the Device ID (also called TRSM ID) + * @ return a 3 bytes array representing the deviceID */ - public void setDeviceID (String deviceID) { - this.deviceID = deviceID; + public byte[] getDeviceIDBytes () { + ByteBuffer buf = ByteBuffer.allocate(8); + buf.putLong(deviceId); + buf.position(5); + byte[] lastThree = new byte[3]; + buf.get (lastThree); + return lastThree; } /** + * Returns the transaction counter as a hexadecimal string padded with leading zeros to a length of 6 characters. * - * @return deviceID a HexString representing the Device ID (also called TRSM ID) + * @return a String representing the transaction counter. */ - public String getDeviceID () { - return deviceID; + public String getTransactionCounter () { + return String.format ("%06X", transactionCounter); } /** + * Returns the transaction counter as an array of bytes. * - * @param transactionCounter a HexString representing the transaction counter + * @ return a 3 byte array representing the transaction counter. */ - public void setTransactionCounter (String transactionCounter) { - this.transactionCounter = transactionCounter; + public byte[] getTransactionCounterBytes () { + ByteBuffer buf = ByteBuffer.allocate(4); + buf.putInt(transactionCounter); + buf.position(1); + byte[] lastThree = new byte[3]; + buf.get (lastThree); + return lastThree; } /** + * Constructs a 10-byte Key Serial Number (KSN) array using the base key ID, device ID, and transaction counter. + * The method first extracts the last 5 bytes from the base key ID and device ID (shifted and combined with the + * transaction counter), and then combines them into a single ByteBuffer of size 10. * - * @return transactionCounter a HexString representing the transaction counter + * @return A byte array containing the 10-byte Key Serial Number. */ - public String getTransactionCounter () { - return transactionCounter; + public byte[] getBytes() { + ByteBuffer buf = ByteBuffer.allocate(10); + buf.put (last5(baseId)); + buf.put (last5(deviceId >> 1 << 21 | transactionCounter)); + return buf.array(); } - + /** * dumps Key Serial Number * @param p a PrintStream usually supplied by Logger @@ -154,12 +159,88 @@ public String getTransactionCounter () { public void dump (PrintStream p, String indent) { String inner = indent + " "; p.println(indent + ""); + p.printf ("%s%s%n", inner, ISOUtil.hexString(getBytes())); p.println(inner + "" + getBaseKeyID() + ""); p.println(inner + "" + getDeviceID() + ""); p.println(inner + "" + getTransactionCounter() + ""); } -} + + @Override + public String toString() { + return String.format( + "KeySerialNumber{base=%X, device=%X, counter=%X}", baseId, deviceId, transactionCounter + ); + } + + /** + * Parses a Key Serial Number (KSN) into its base key ID, device ID, and transaction counter components. + * The KSN is first padded to a length of 10 bytes, and then the base key ID, device ID, and transaction counter + * are extracted. + * The base key id has a fixed length of 5 bytes. + * The sequence number has a fixed length of 19 bits. + * The transaction counter has a fixed length of 21 bits per ANS X9.24 spec. + * + * It is important to mention that the device ID is a 19-bit value, which has been shifted one bit to the right + * from its original hexadecimal representation. To facilitate readability and manipulation when reconstructing + * the KSN byte image, the device ID is maintained in a left-shifted position by one bit. + * + * @param ksn The input KSN byte array to be parsed. + * @throws IllegalArgumentException If the base key ID length is smaller than 0 or greater than 8. + */ + private void parseKsn(byte[] ksn) { + ByteBuffer buf = padleft (ksn, 10, (byte) 0xFF); + + byte[] baseKeyIdBytes = new byte[5]; + buf.get(baseKeyIdBytes); + baseId = padleft (baseKeyIdBytes, 8, (byte) 0x00).getLong(); + ByteBuffer sliceCopy = buf.slice().duplicate(); + ByteBuffer remaining = ByteBuffer.allocate(8); + remaining.position(8 - sliceCopy.remaining()); + remaining.put(sliceCopy); + remaining.flip(); + long l = remaining.getLong(); + int mask = (1 << 21) - 1; + transactionCounter = (int) l & mask; + deviceId = l >>> 21 << 1; + } + + /** + * Pads the input byte array with a specified padding byte on the left side to achieve a desired length. + * + * @param b The input byte array to be padded. + * @param len The desired length of the resulting padded byte array. + * @param padbyte The byte value used for padding the input byte array. + * @return A ByteBuffer containing the padded byte array with the specified length. + * @throws IllegalArgumentException If the desired length is smaller than the length of the input byte array. + */ + private ByteBuffer padleft (byte[] b, int len, byte padbyte) { + if (len < b.length) { + throw new IllegalArgumentException("Desired length must be greater than or equal to the length of the input byte array."); + } + ByteBuffer buf = ByteBuffer.allocate(len); + for (int i=0; i 16) sn = sn.substring(sn.length()-16); - byte[] smidr = ISOUtil.hex2byte(sn); - byte[] reg3 = ISOUtil.hex2byte(ksn.getTransactionCounter()); + byte[] smidr = new byte[8]; + System.arraycopy (ksn.getBytes(), 2, smidr, 0, smidr.length); + + byte[] ksnImage = ksn.getBytes(); + byte[] reg3; + if (dataEncryption && ksnImage[0] != (byte) 0xFF && ksnImage[1] != (byte) 0xFF) { + // jPOS 2.x compatibility mode - + reg3 = new byte[5]; + System.arraycopy (ksnImage, 5, reg3, 0, reg3.length); + } else { + reg3 = ksn.getTransactionCounterBytes(); + } reg3 = and(reg3, _1FFFFF); byte[] shiftr = _100000; byte[] temp; @@ -2322,6 +2318,7 @@ private byte[] calculateDerivedKeyTDES(KeySerialNumber ksn, SecureDESKey bdk, bo byte[] curkeyL = new byte[8]; byte[] curkeyR = new byte[8]; smidr = and(smidr, _E00000, 5); + do { temp = and(shiftr, reg3); @@ -2382,13 +2379,10 @@ public SecureDESKey importBDK(String clearComponent1HexString, clearComponent3HexString); } - private KeySerialNumber getKSN(String s) - { - return new KeySerialNumber( - s.substring(0, 6), - s.substring(6, 10), - s.substring(10, Math.min(s.length(), 20)) - ); + private KeySerialNumber getKSN(byte[] b) { + ByteBuffer buf = ByteBuffer.allocate(10); + buf.put(b, 0, 10); + return new KeySerialNumber (buf.array()); } protected EncryptedPIN translatePINImpl diff --git a/jpos/src/test/java/org/jpos/security/BaseSMAdapterTest.java b/jpos/src/test/java/org/jpos/security/BaseSMAdapterTest.java index 7bd4d075d1..826404a30c 100644 --- a/jpos/src/test/java/org/jpos/security/BaseSMAdapterTest.java +++ b/jpos/src/test/java/org/jpos/security/BaseSMAdapterTest.java @@ -215,23 +215,7 @@ public void testImportPINImplThrowsSMException() throws Throwable { assertNull(ex.getNested(), "ex.getNested()"); } } - - @Test - public void testImportPINImplThrowsSMException1() throws Throwable { - BaseSMAdapter baseSMAdapter = new BaseSMAdapter(new SubConfiguration(new SimpleConfiguration(new Properties(null)), - "testBaseSMAdapterPrefix"), new Logger(), "testBaseSMAdapterRealm"); - try { - baseSMAdapter.importPINImpl(new EncryptedPIN("testBaseSMAdapterPinBlockHexString", (byte) 0, - "testBaseSMAdapterAccountNumber"), new KeySerialNumber(), new SecureDESKey((short) 100, - "testBaseSMAdapterKeyType", "testBaseSMAdapterKeyHexString1", "testBaseSMAdapterKeyCheckValueHexString1")); - fail("Expected SMException to be thrown"); - } catch (SMException ex) { - assertEquals("Operation not supported in: org.jpos.security.BaseSMAdapter", ex.getMessage(), "ex.getMessage()"); - assertNull(ex.nested, "ex.nested"); - assertNull(ex.getNested(), "ex.getNested()"); - } - } - + @Test public void testSetConfiguration() throws Throwable { BaseSMAdapter baseSMAdapter = new BaseSMAdapter(); @@ -255,21 +239,7 @@ public void testSetName() throws Throwable { baseSMAdapter.setName("testBaseSMAdapterName"); assertEquals("testBaseSMAdapterName", baseSMAdapter.getName(), "baseSMAdapter.getName()"); } - - @Test - public void testTranslatePINImplThrowsSMException() throws Throwable { - BaseSMAdapter baseSMAdapter = new BaseSMAdapter(); - SecureDESKey bdk = new SecureDESKey(); - try { - baseSMAdapter.translatePINImpl(new EncryptedPIN(), new KeySerialNumber(), bdk, bdk, (byte) 0); - fail("Expected SMException to be thrown"); - } catch (SMException ex) { - assertEquals("Operation not supported in: org.jpos.security.BaseSMAdapter", ex.getMessage(), "ex.getMessage()"); - assertNull(ex.nested, "ex.nested"); - assertNull(ex.getNested(), "ex.getNested()"); - } - } - + @Test public void testTranslatePINImplThrowsSMException1() throws Throwable { BaseSMAdapter baseSMAdapter = new BaseSMAdapter(new SubConfiguration(new SimpleConfiguration(new Properties(null)), diff --git a/jpos/src/test/java/org/jpos/security/KeySerialNumberTest.java b/jpos/src/test/java/org/jpos/security/KeySerialNumberTest.java index 6d2683104b..5050bda712 100644 --- a/jpos/src/test/java/org/jpos/security/KeySerialNumberTest.java +++ b/jpos/src/test/java/org/jpos/security/KeySerialNumberTest.java @@ -34,134 +34,37 @@ public class KeySerialNumberTest { - @Test - public void testConstructor() throws Throwable { - KeySerialNumber keySerialNumber = new KeySerialNumber(); - assertNull(keySerialNumber.getBaseKeyID(), "keySerialNumber.getBaseKeyID()"); - } - - @Test - public void testConstructor1() throws Throwable { - KeySerialNumber keySerialNumber = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter"); - assertEquals("testKeySerialNumberBaseKeyID", keySerialNumber.baseKeyID, "keySerialNumber.baseKeyID"); - assertEquals("testKeySerialNumberDeviceID", keySerialNumber.deviceID, "keySerialNumber.deviceID"); - assertEquals("testKeySerialNumberTransactionCounter", - keySerialNumber.transactionCounter, "keySerialNumber.transactionCounter"); - } @Test public void testDump() throws Throwable { PrintStream p = new PrintStream(new ByteArrayOutputStream(), true, "UTF-8"); Object[] objects = new Object[1]; p.format("testKeySerialNumberParam1", objects); - new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", "testKeySerialNumberTransactionCounter") + new KeySerialNumber("FFFF987654", "3210E", "000008") .dump(p, "testKeySerialNumberIndent"); assertTrue(true, "Test completed without Exception"); } - @Test - public void testDumpThrowsNullPointerException() throws Throwable { - try { - new KeySerialNumber().dump(null, "testKeySerialNumberIndent"); - fail("Expected NullPointerException to be thrown"); - } catch (NullPointerException ex) { - if (isJavaVersionAtMost(JAVA_14)) { - assertNull(ex.getMessage(), "ex.getMessage()"); - } else { - assertEquals("Cannot invoke \"java.io.PrintStream.println(String)\" because \"p\" is null", ex.getMessage(), "ex.getMessage()"); - } - } - } - - @Test - public void testGetBaseKeyID() throws Throwable { - String result = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter").getBaseKeyID(); - assertEquals("testKeySerialNumberBaseKeyID", result, "result"); - } - - @Test - public void testGetDeviceID() throws Throwable { - String result = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter").getDeviceID(); - assertEquals("testKeySerialNumberDeviceID", result, "result"); - } - - @Test - public void testGetTransactionCounter() throws Throwable { - String result = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter").getTransactionCounter(); - assertEquals("testKeySerialNumberTransactionCounter", result, "result"); - } - - @Test - public void testGetTransactionCounter1() throws Throwable { - String result = new KeySerialNumber().getTransactionCounter(); - assertNull(result, "result"); - } - - @Test - public void testSetBaseKeyID() throws Throwable { - KeySerialNumber keySerialNumber = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter"); - keySerialNumber.setBaseKeyID("testKeySerialNumberBaseKeyID1"); - assertEquals("testKeySerialNumberBaseKeyID1", keySerialNumber.baseKeyID, "keySerialNumber.baseKeyID"); - } - - @Test - public void testSetDeviceID() throws Throwable { - KeySerialNumber keySerialNumber = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter"); - keySerialNumber.setDeviceID("testKeySerialNumberDeviceID1"); - assertEquals("testKeySerialNumberDeviceID1", keySerialNumber.deviceID, "keySerialNumber.deviceID"); - } - - @Test - public void testSetTransactionCounter() throws Throwable { - KeySerialNumber keySerialNumber = new KeySerialNumber("testKeySerialNumberBaseKeyID", "testKeySerialNumberDeviceID", - "testKeySerialNumberTransactionCounter"); - keySerialNumber.setTransactionCounter("testKeySerialNumberTransactionCounter1"); - assertEquals("testKeySerialNumberTransactionCounter1", - keySerialNumber.transactionCounter, "keySerialNumber.transactionCounter"); - } - @Test public void testBinaryConstructor() { byte[] ksnBin = ISOUtil.hex2byte("9876543210E00008"); - KeySerialNumber ksn = new KeySerialNumber(ksnBin, 6, 5, 5); - assertEquals("987654", ksn.getBaseKeyID()); - assertEquals("3210E", ksn.getDeviceID()); - assertEquals("00008", ksn.getTransactionCounter()); - } - - @Test - public void testHexConstructor() { - String ksnHex = "9876543210E00008"; - KeySerialNumber ksn = new KeySerialNumber(ksnHex, 6, 5, 5); - assertEquals("987654", ksn.getBaseKeyID()); - assertEquals("3210E", ksn.getDeviceID()); - assertEquals("00008", ksn.getTransactionCounter()); + KeySerialNumber ksn = new KeySerialNumber(ksnBin); + assertEquals("FFFF987654", ksn.getBaseKeyID()); + assertEquals("03210E", ksn.getDeviceID()); + assertEquals("000008", ksn.getTransactionCounter()); } @Test public void testHexConstructorWrongLength() { assertThrows(IllegalArgumentException.class, () -> { - new KeySerialNumber("9876543210E008", 6, 5, 5); + new KeySerialNumber(ISOUtil.hex2byte("9876543210E008")); }); } @Test public void testHexConstructorNullKSN() { - assertThrows(IllegalArgumentException.class, () -> { - new KeySerialNumber((String) null, 6, 5, 5); - }); - } - - @Test - public void testHexConstructorEmptyKSN() { - assertThrows(IllegalArgumentException.class, () -> { - new KeySerialNumber(" ", 6, 5, 5); + assertThrows(NullPointerException.class, () -> { + new KeySerialNumber(null); }); } } diff --git a/jpos/src/test/java/org/jpos/security/jceadapter/DUKPTTest.java b/jpos/src/test/java/org/jpos/security/jceadapter/DUKPTTest.java index 72dd265fd3..adb868fa09 100644 --- a/jpos/src/test/java/org/jpos/security/jceadapter/DUKPTTest.java +++ b/jpos/src/test/java/org/jpos/security/jceadapter/DUKPTTest.java @@ -72,59 +72,61 @@ public void setUp() throws Exception @Test public void test_DUKPT() throws Exception { - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00002"), ISOUtil.hex2byte ("B76997F83C1479DB"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00003"), ISOUtil.hex2byte ("925BC2A39652CF75"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00009"), ISOUtil.hex2byte ("8DC939C56D0FD13C"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000F"), ISOUtil.hex2byte ("C578B541B9A58A5B"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00010"), ISOUtil.hex2byte ("6268FFC127118969"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF800"), ISOUtil.hex2byte ("A6552D24B01E71A0"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFFC00"), ISOUtil.hex2byte ("6DEF7FD593810AC7"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "F00000"), ISOUtil.hex2byte ("3FAC6F8763C0B60C"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF800"), ISOUtil.hex2byte ("A6552D24B01E71A0"), PAN); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00002"), ISOUtil.hex2byte ("E6F851D98E8DD722"), PAN2); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00003"), ISOUtil.hex2byte ("DE4FF9ABA523F853"), PAN2); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00006"), ISOUtil.hex2byte ("148F2CD3554F09F3"), PAN2); + test_DUKPT ("test-bdk", new KeySerialNumber (ISOUtil.hex2byte("FFFF9876543210E00002")), ISOUtil.hex2byte ("B76997F83C1479DB"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00002"), ISOUtil.hex2byte ("B76997F83C1479DB"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00003"), ISOUtil.hex2byte ("925BC2A39652CF75"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00009"), ISOUtil.hex2byte ("8DC939C56D0FD13C"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000F"), ISOUtil.hex2byte ("C578B541B9A58A5B"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00010"), ISOUtil.hex2byte ("6268FFC127118969"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF800"), ISOUtil.hex2byte ("A6552D24B01E71A0"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FFC00"), ISOUtil.hex2byte ("6DEF7FD593810AC7"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber (ISOUtil.hex2byte("FFFF9876543210F00000")), ISOUtil.hex2byte ("3FAC6F8763C0B60C"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "100000"), ISOUtil.hex2byte ("3FAC6F8763C0B60C"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210F", "FF800"), ISOUtil.hex2byte ("A6552D24B01E71A0"), PAN); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00002"), ISOUtil.hex2byte ("E6F851D98E8DD722"), PAN2); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00003"), ISOUtil.hex2byte ("DE4FF9ABA523F853"), PAN2); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00006"), ISOUtil.hex2byte ("148F2CD3554F09F3"), PAN2); // Test 3DES - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00001"), ISOUtil.hex2byte ("1B9C1845EB993A7A"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00002"), ISOUtil.hex2byte ("10A01C8D02C69107"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00003"), ISOUtil.hex2byte ("18DC07B94797B466"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00004"), ISOUtil.hex2byte ("0BC79509D5645DF7"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00005"), ISOUtil.hex2byte ("5BC0AF22AD87B327"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00006"), ISOUtil.hex2byte ("A16DF70AE36158D8"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00007"), ISOUtil.hex2byte ("27711C16CB257F8E"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00008"), ISOUtil.hex2byte ("50E55547A5027551"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00009"), ISOUtil.hex2byte ("536CF7F678ACFC8D"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000A"), ISOUtil.hex2byte ("EDABBA23221833FE"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000B"), ISOUtil.hex2byte ("2328981C57B4BDBA"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000C"), ISOUtil.hex2byte ("038D03CC926CF286"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000D"), ISOUtil.hex2byte ("6C8AA97088B62C68"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000E"), ISOUtil.hex2byte ("F17C9E1D72CD4950"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E0000F"), ISOUtil.hex2byte ("B170F6E7F7F2F64A"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00010"), ISOUtil.hex2byte ("D5D9638559EF53D6"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00011"), ISOUtil.hex2byte ("D544F8CDD292C863"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00012"), ISOUtil.hex2byte ("7A21BD10F36DC41D"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00013"), ISOUtil.hex2byte ("78649BD17D0DFA60"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00014"), ISOUtil.hex2byte ("7E7E16EA0C31AD56"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "E00015"), ISOUtil.hex2byte ("72105C22EBC791E6"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF800"), ISOUtil.hex2byte ("33365F5CC6F23C35"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF801"), ISOUtil.hex2byte ("3A86BF003F835C9D"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF802"), ISOUtil.hex2byte ("3DB977D05C36DF3F"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF804"), ISOUtil.hex2byte ("BA83243305712099"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF808"), ISOUtil.hex2byte ("B0DA04AC90A36D85"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF810"), ISOUtil.hex2byte ("2CF02BD9C309EEDA"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF820"), ISOUtil.hex2byte ("9D1E2F77AEEE81C6"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF840"), ISOUtil.hex2byte ("40870B0F8BA2011C"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF880"), ISOUtil.hex2byte ("22E340D6ABB40981"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFF900"), ISOUtil.hex2byte ("1A4C10AFBA03A430"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFFA00"), ISOUtil.hex2byte ("849763B43E5F9CFF"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "EFFC00"), ISOUtil.hex2byte ("DEFC6F09F8927B71"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210", "F00000"), ISOUtil.hex2byte ("73EC88AD0AC5830E"), PAN,true); - test_DUKPT ("test-bdk", new KeySerialNumber ("9876543210", "0000", "400002"), ISOUtil.hex2byte ("AEF0F261B1222EB1"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00001"), ISOUtil.hex2byte ("1B9C1845EB993A7A"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00002"), ISOUtil.hex2byte ("10A01C8D02C69107"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00003"), ISOUtil.hex2byte ("18DC07B94797B466"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00004"), ISOUtil.hex2byte ("0BC79509D5645DF7"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00005"), ISOUtil.hex2byte ("5BC0AF22AD87B327"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00006"), ISOUtil.hex2byte ("A16DF70AE36158D8"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00007"), ISOUtil.hex2byte ("27711C16CB257F8E"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00008"), ISOUtil.hex2byte ("50E55547A5027551"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00009"), ISOUtil.hex2byte ("536CF7F678ACFC8D"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000A"), ISOUtil.hex2byte ("EDABBA23221833FE"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000B"), ISOUtil.hex2byte ("2328981C57B4BDBA"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000C"), ISOUtil.hex2byte ("038D03CC926CF286"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000D"), ISOUtil.hex2byte ("6C8AA97088B62C68"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000E"), ISOUtil.hex2byte ("F17C9E1D72CD4950"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "0000F"), ISOUtil.hex2byte ("B170F6E7F7F2F64A"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00010"), ISOUtil.hex2byte ("D5D9638559EF53D6"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00011"), ISOUtil.hex2byte ("D544F8CDD292C863"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00012"), ISOUtil.hex2byte ("7A21BD10F36DC41D"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00013"), ISOUtil.hex2byte ("78649BD17D0DFA60"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00014"), ISOUtil.hex2byte ("7E7E16EA0C31AD56"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "00015"), ISOUtil.hex2byte ("72105C22EBC791E6"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF800"), ISOUtil.hex2byte ("33365F5CC6F23C35"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF801"), ISOUtil.hex2byte ("3A86BF003F835C9D"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF802"), ISOUtil.hex2byte ("3DB977D05C36DF3F"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF804"), ISOUtil.hex2byte ("BA83243305712099"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF808"), ISOUtil.hex2byte ("B0DA04AC90A36D85"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF810"), ISOUtil.hex2byte ("2CF02BD9C309EEDA"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF820"), ISOUtil.hex2byte ("9D1E2F77AEEE81C6"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF840"), ISOUtil.hex2byte ("40870B0F8BA2011C"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF880"), ISOUtil.hex2byte ("22E340D6ABB40981"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FF900"), ISOUtil.hex2byte ("1A4C10AFBA03A430"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FFA00"), ISOUtil.hex2byte ("849763B43E5F9CFF"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "FFC00"), ISOUtil.hex2byte ("DEFC6F09F8927B71"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("987654", "3210E", "100000"), ISOUtil.hex2byte ("73EC88AD0AC5830E"), PAN,true); + test_DUKPT ("test-bdk", new KeySerialNumber ("9876543210", "00004", "00002"), ISOUtil.hex2byte ("AEF0F261B1222EB1"), PAN,true); } @Test public void test_dataEncrypt() throws Exception { - SecureDESKey bdk = (SecureDESKey) ks.getKey("test-bdk"); + SecureDESKey bdk = ks.getKey("test-bdk"); byte[] original = "The quick brown fox jumps over the lazy dog".getBytes(); byte[] cryptogram = sm.dataEncrypt(bdk, original); byte[] cleartext = sm.dataDecrypt(bdk, cryptogram); @@ -136,6 +138,21 @@ public void test_dataEncrypt() throws Exception { } catch (Exception ignored) { } } + @Test + public void test_dataDecryptCompatibility() throws Exception { + SecureDESKey bdk = ks.getKey("test-bdk"); + byte[] original = "The quick brown fox jumps over the lazy dog".getBytes(); + // cryptogram was created with jPOS 2.1.9-SNAPSHOT master/afb3977 previous to KeySerialNumber class overhaul + byte[] cryptogram = ISOUtil.hex2byte("CE1CF4085E1AA8348F1316F8FD641CB3CE1CF4085E1AA8346FB168F8A730914FFCA386A289F185EF50696A13B994AD6CF373FEC56C1E8C25137D0A560FCF57630C5100F89E7BA6FCC3B7DDC86E87A495"); + byte[] cleartext = sm.dataDecrypt(bdk, cryptogram); + assertEqual(original, cleartext); + cryptogram[0] = (byte) (cryptogram[0] ^ 0xAA); + try { + sm.dataDecrypt(bdk, cryptogram); + fail("SMException not raised"); + } catch (Exception ignored) { } + } + private void test_DUKPT(String keyName, KeySerialNumber ksn, byte[] pinUnderDukpt, String pan) throws Exception { @@ -147,20 +164,24 @@ private void test_DUKPT(String keyName, KeySerialNumber ksn, byte[] pinUnderDukp { LogEvent evt = log.createInfo("test_DUKPT " + ksn); evt.addMessage(ksn); - EncryptedPIN pin = new EncryptedPIN( - pinUnderDukpt, SMAdapter.FORMAT01, pan - ); - SecureDESKey bdk = ks.getKey(keyName); - evt.addMessage(pin); - evt.addMessage(ksn); - evt.addMessage(bdk); - - EncryptedPIN pinUnderLMK = sm.importPIN(pin, ksn, bdk,tdes); - evt.addMessage(pinUnderLMK); - evt.addMessage( - "" + sm.decryptPIN(pinUnderLMK) + "" - ); - Logger.log(evt); + try { + EncryptedPIN pin = new EncryptedPIN( + pinUnderDukpt, SMAdapter.FORMAT01, pan + ); + SecureDESKey bdk = ks.getKey(keyName); + evt.addMessage(pin); + evt.addMessage(ksn); + evt.addMessage(bdk); + + EncryptedPIN pinUnderLMK = sm.importPIN(pin, ksn, bdk,tdes); + evt.addMessage(pinUnderLMK); + evt.addMessage( + "" + sm.decryptPIN(pinUnderLMK) + "" + ); + + } finally { + Logger.log (evt); + } } private void initKS() throws Exception