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