Skip to content

Commit

Permalink
Merge pull request #577 from T-eli/fixes/emv-ac-data-builder
Browse files Browse the repository at this point in the history
Added a padding option to cryptogram builder
  • Loading branch information
ar authored Dec 24, 2023
2 parents 97e4a88 + 944c009 commit 41cd7e0
Show file tree
Hide file tree
Showing 17 changed files with 505 additions and 35 deletions.
2 changes: 1 addition & 1 deletion jpos/src/main/java/org/jpos/emv/IssuerApplicationData.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public IssuerApplicationData(String hexIAD) {
//Therefore, the length of the Issuer Application Data is 18 bytes and for
// M/Chip Advance it may be 18, 20, 26, or 28.
unpackMCHIP(iad);
} else if (len == 32 && iad.startsWith("0F") && iad.startsWith("0F", 32)) {
} else if (len == 32 && (iad.startsWith("0F") || iad.startsWith("0f")) && (iad.startsWith("0F", 32) || iad.startsWith("0f", 32))) {
// EMV_v4.3_Book_3
// C7.2 Issuer Application Data for Format Code 'A'
unpackEMVFormatA(iad);
Expand Down
35 changes: 35 additions & 0 deletions jpos/src/main/java/org/jpos/emv/cryptogram/CPACryptogram.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.jpos.emv.cryptogram;

import org.jpos.security.ARPCMethod;
import org.jpos.security.MKDMethod;
import org.jpos.security.SKDMethod;

import org.jpos.emv.cryptogram.CryptogramDataBuilder.PaddingMethod;

/**
* Common Payment Application (CPA) Cryptogram Specification
*/
public class CPACryptogram implements CryptogramSpec {

final PaddingMethod paddingMethod = CryptogramDataBuilder.ISO9797Method2;

@Override
public MKDMethod getMKDMethod() {
return MKDMethod.OPTION_A;
}

@Override
public SKDMethod getSKDMethod() {
return SKDMethod.EMV_CSKD;
}

@Override
public ARPCMethod getARPCMethod() {
return ARPCMethod.METHOD_2;
}

@Override
public CryptogramDataBuilder getDataBuilder() {
return new CVNCPADataBuilder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* @author Rainer Reyes
*/
public class CVN10DataBuilder implements CryptogramDataBuilder {

@Override
public String getDefaultARPCRequest(boolean approved) {
return approved ? "0000" : "9900";
Expand All @@ -44,4 +44,9 @@ public String buildARQCRequest(TLVList data, IssuerApplicationData iad) {
sb.append(iad.getCardVerificationResults());
return sb.toString();
}

@Override
public String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad, PaddingMethod paddingMethod){
return paddingMethod.apply(buildARQCRequest(data, iad));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* @author Rainer Reyes
*/
public class CVN18DataBuilder implements CryptogramDataBuilder {

@Override
public String getDefaultARPCRequest(boolean approved) {
/* for success:
Expand All @@ -47,4 +47,9 @@ public String buildARQCRequest(TLVList data, IssuerApplicationData iad) {
sb.append(iad.toString());
return sb.toString();
}

@Override
public String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad, PaddingMethod paddingMethod) {
return paddingMethod.apply(buildARQCRequest(data, iad));
}
}
26 changes: 26 additions & 0 deletions jpos/src/main/java/org/jpos/emv/cryptogram/CVNCPADataBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.jpos.emv.cryptogram;

import org.jpos.emv.IssuerApplicationData;
import org.jpos.tlv.TLVList;
import static org.jpos.emv.cryptogram.CryptogramDataBuilder.minimumSetOfDataElement;

public class CVNCPADataBuilder implements CryptogramDataBuilder {

@Override
public String getDefaultARPCRequest(boolean approved) {
return approved ? "3030" : "3031";
}

@Override
public String buildARQCRequest(TLVList data, IssuerApplicationData iad) {
StringBuilder sb = new StringBuilder();
minimumSetOfDataElement(data).stream().forEach(sb::append);
sb.append(iad.toString());
return sb.toString();
}

@Override
public String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad, PaddingMethod paddingMethod) {
return paddingMethod.apply(buildARQCRequest(data, iad));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ public String buildARQCRequest(TLVList data, IssuerApplicationData iad) {
return sb.toString();
}

@Override
public String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad, PaddingMethod paddingMethod) {
return paddingMethod.apply(buildARQCRequest(data, iad));
}

@Override
public String getDefaultARPCRequest(boolean approved) {
return approved ? "0012" : "9900";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@

import org.jpos.emv.EMVStandardTagType;
import org.jpos.emv.IssuerApplicationData;
import org.jpos.iso.ISOUtil;
import org.jpos.tlv.TLVList;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.*;


/**
Expand All @@ -34,6 +33,36 @@
*/
public interface CryptogramDataBuilder {

final PaddingMethod NO_PADDING = data -> data;

/**
* ISO/IEC 9797-1 padding method 1
* for Block size 8, n = 64
*/
final PaddingMethod ISO9797Method1 = data -> data.isEmpty() ?
"0000000000000000" :
ISOUtil.zeropadRight(data, data.length() % 16 == 0 ? data.length() : data.length() + 16 - data.length() % 16);

/**
* ISO/IEC 9797-1 padding method 2
* for Block size 8, n = 64
*/
final PaddingMethod ISO9797Method2 = data -> ISO9797Method1.apply(data + "80");

/**
* ISO/IEC 9797-1 padding method 3
* for Block size 8, n = 64
*/
final PaddingMethod ISO9797Method3 = data -> {
StringBuilder sb = new StringBuilder();
String D = ISO9797Method1.apply(data);
String Ld = ISOUtil.byte2hex(ISOUtil.int2byte(data.length() / 2));
String Lp = ISO9797Method1.apply(Ld);
Lp = Ld.length() % 16 == 0 ? "" : Lp.substring(Ld.length());
return sb.append(Lp).append(Ld).append(D).toString();
};


/**
* Method that selects the minimum set of data elements recommended for
* the generation of application cryptograms described in EMV Book 2 sec 8.1.1
Expand Down Expand Up @@ -67,7 +96,7 @@ static List<String> minimumSetOfDataElement(TLVList data) {
String getDefaultARPCRequest(boolean approved);

/**
* Select necessary data elements and create the string used to generate the ARQC
* Select necessary data elements and create the string used to generate the ARQC with no padding
* <p>
*
* @param data ICC data received
Expand All @@ -76,4 +105,22 @@ static List<String> minimumSetOfDataElement(TLVList data) {
*/
String buildARQCRequest(TLVList data, IssuerApplicationData iad);


/**
* Select necessary data elements and create the string used to generate the ARQC with padding
* <p>
*
* @param data ICC data received
* @param iad Issuer application Data
* @param paddingMethod Padding method to use
* @return String used to generate the ARQC
*/
String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad, PaddingMethod paddingMethod);

/**
* Padding Method Interface
*/
interface PaddingMethod {
String apply(String data);
}
}
2 changes: 1 addition & 1 deletion jpos/src/main/java/org/jpos/security/BaseSMAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2035,7 +2035,7 @@ protected boolean verifyCVC3Impl(T imkcvc3, String accountNo, String acctSeqNo,
* @param atc
* @param upn
* @param txnData
* @return true if ARQC/TC/AAC is falid or false if not
* @return true if ARQC/TC/AAC is valid or false if not
* @throws SMException
*/
protected boolean verifyARQCImpl(MKDMethod mkdm, SKDMethod skdm, T imkac
Expand Down
51 changes: 26 additions & 25 deletions jpos/src/main/java/org/jpos/security/SKDMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,34 @@
*/
public enum SKDMethod {

/**
* Visa Smart Debit/Credit or UKIS in England
* <br>
* Described in Visa Integrated Circuit Card
* Specification (VIS) Version 1.5 - May 2009, section B.4
*/
VSDC
/**
* Visa Smart Debit/Credit or UKIS in England
* <br>
* Described in Visa Integrated Circuit Card
* Specification (VIS) Version 1.5 - May 2009, section B.4
*/
VSDC,

/**
* MasterCard Proprietary SKD method
*/
,MCHIP
/**
* American Express
*/
,AEPIS_V40
/**
* MasterCard Proprietary SKD method
*/
MCHIP,

/**
* EMV Common Session Key Derivation Method
* Described in EMV v4.2 Book 2 - June 2008, Annex A1.3
*/
,EMV_CSKD
/**
* American Express
*/
AEPIS_V40,

/**
* EMV2000 Session Key Method
* Described in EMV 2000 v4.0 Book 2 - December 2000, Annex A1.3
*/
,EMV2000_SKM
/**
* EMV Common Session Key Derivation Method
* Described in EMV v4.2 Book 2 - June 2008, Annex A1.3
*/
EMV_CSKD,

/**
* EMV2000 Session Key Method
* Described in EMV 2000 v4.0 Book 2 - December 2000, Annex A1.3
*/
EMV2000_SKM,

}
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ private static byte[] preparePANPSN(String pan, String psn){
* </ul>
* @param pan application primary account number
* @param psn PAN Sequence Number
* @return 8-bytes representing first 16 digits
* @return 8-bytes representing rightmost 16 digits
*/
private static byte[] formatPANPSNOptionA(String pan, String psn){
if ( pan.length() < 14 )
Expand Down
21 changes: 21 additions & 0 deletions jpos/src/test/java/org/jpos/emv/cryptogram/CPACryptogramTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jpos.emv.cryptogram;

import org.jpos.security.ARPCMethod;
import org.jpos.security.MKDMethod;
import org.jpos.security.SKDMethod;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class CPACryptogramTest {
@Test
void test(){
CPACryptogram spec = new CPACryptogram();
assertEquals(spec.paddingMethod, CryptogramDataBuilder.ISO9797Method2);
assertEquals(spec.getMKDMethod(), MKDMethod.OPTION_A);
assertEquals(spec.getSKDMethod(), SKDMethod.EMV_CSKD);
assertEquals(spec.getARPCMethod(), ARPCMethod.METHOD_2);
assertTrue(spec.getDataBuilder() instanceof CVNCPADataBuilder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ void testBuildARQCRequest() {
builder.buildARQCRequest(data, iad)
);

assertEquals(
"00000000010000000000000008400000000000084018123101ABCDEF101800000203000000000000",
builder.buildARQCRequest_padded(data, iad, builder.ISO9797Method1)
);


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ void testBuildARQCRequest() {
builder.buildARQCRequest(data, iad)
);

assertEquals(
"00000000010000000000000008400000000000084018123101ABCDEF101800000106011203000000",
builder.buildARQCRequest_padded(data, iad, builder.ISO9797Method1)
);


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.jpos.emv.cryptogram;

import org.jpos.emv.IssuerApplicationData;
import org.jpos.tlv.TLVList;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CVNCPADataBuilderTest {
private final CVNCPADataBuilder builder = new CVNCPADataBuilder();

/**
* Test Data is based of EMV Issuer and Application Security Guidelines v3.0 Annex A.3.3 - Example of ARQC Generation
*/
@Test
void testBuildARQCRequest() {

TLVList data = new TLVList();
data.append(0x9F02, "000000010000");
data.append(0x9F03, "000000001000");
data.append(0x9F1A, "0840");
data.append(0x95, "0000001080");
data.append(0x5F2A, "0840");
data.append(0x9A, "980704");
data.append(0x9C, "00");
data.append(0x9F37, "11111111");
data.append(0x82, "5800");
data.append(0x9F36, "3456");
data.append(0x9f10, "0FA500A03800000000000000000000000F010000000000000000000000000000");

IssuerApplicationData iad = new IssuerApplicationData(data.getString(0x9f10));

assertEquals(
"0000000100000000000010000840000000108008409807040011111111580034560FA500A03800000000000000000000000F010000000000000000000000000000",
builder.buildARQCRequest(data, iad)
);

assertEquals(
"0000000100000000000010000840000000108008409807040011111111580034560FA500A03800000000000000000000000F01000000000000000000000000000080000000000000",
builder.buildARQCRequest_padded(data, iad, builder.ISO9797Method2)
);
}
}
Loading

0 comments on commit 41cd7e0

Please sign in to comment.