001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.emv.cryptogram; 020 021import org.jpos.emv.EMVStandardTagType; 022import org.jpos.emv.IssuerApplicationData; 023import org.jpos.iso.ISOUtil; 024import org.jpos.tlv.TLVList; 025 026import java.util.*; 027 028 029/** 030 * Interface that provides methods to build strings for ARPC and ARQC generation 031 * 032 * @author Rainer Reyes 033 */ 034public interface CryptogramDataBuilder { 035 036 enum PaddingMethod { 037 NO_PADDING, 038 039 /** 040 * ISO/IEC 9797-1 padding method 1 041 * for Block size 8, n = 64 042 */ 043 ISO9797Method1 { 044 @Override 045 public String apply(String data) { 046 return data.isEmpty() ? 047 "0000000000000000" : 048 ISOUtil.zeropadRight(data, data.length() % 16 == 0 ? data.length() : data.length() + 16 - data.length() % 16); 049 } 050 }, 051 052 /** 053 * ISO/IEC 9797-1 padding method 2 054 * for Block size 8, n = 64 055 */ 056 ISO9797Method2 { 057 @Override 058 public String apply(String data) { 059 return ISO9797Method1.apply(data + "80"); 060 } 061 }, 062 063 /** 064 * ISO/IEC 9797-1 padding method 3 065 * for Block size 8, n = 64 066 */ 067 ISO9797Method3 { 068 @Override 069 public String apply(String data) { 070 StringBuilder sb = new StringBuilder(); 071 String D = ISO9797Method1.apply(data); 072 String Ld = ISOUtil.byte2hex(ISOUtil.int2byte(data.length() / 2)); 073 String Lp = ISO9797Method1.apply(Ld); 074 Lp = Ld.length() % 16 == 0 ? "" : Lp.substring(Ld.length()); 075 return sb.append(Lp).append(Ld).append(D).toString(); 076 } 077 }; 078 079 public String apply(String data) { 080 return data; 081 } 082 } 083 084 /** 085 * Method that selects the minimum set of data elements recommended for 086 * the generation of application cryptograms described in EMV Book 2 sec 8.1.1 087 * 088 * @param data ICC data 089 * @return Minimum Set of Data Elements for Application Cryptogram Generation 090 */ 091 static List<String> minimumSetOfDataElement(TLVList data) { 092 return Arrays.asList( 093 data.getString(EMVStandardTagType.AMOUNT_AUTHORISED_NUMERIC_0x9F02.getTagNumber()), 094 Optional.ofNullable(data.getString(EMVStandardTagType.AMOUNT_OTHER_NUMERIC_0x9F03.getTagNumber())) 095 .orElse("000000000000"), 096 data.getString(EMVStandardTagType.TERMINAL_COUNTRY_CODE_0x9F1A.getTagNumber()), 097 data.getString(EMVStandardTagType.TERMINAL_VERIFICATION_RESULTS_0x95.getTagNumber()), 098 data.getString(EMVStandardTagType.TRANSACTION_CURRENCY_CODE_0x5F2A.getTagNumber()), 099 data.getString(EMVStandardTagType.TRANSACTION_DATE_0x9A.getTagNumber()), 100 data.getString(EMVStandardTagType.TRANSACTION_TYPE_0x9C.getTagNumber()), 101 data.getString(EMVStandardTagType.UNPREDICTABLE_NUMBER_0x9F37.getTagNumber()), 102 data.getString(EMVStandardTagType.APPLICATION_INTERCHANGE_PROFILE_0x82.getTagNumber()), 103 data.getString(EMVStandardTagType.APPLICATION_TRANSACTION_COUNTER_0x9F36.getTagNumber()) 104 ); 105 } 106 107 /** 108 * Method that returns default issuer response data (ARC or CSU) 109 * 110 * @param approved true if transaction was approved, otherwise false 111 * @return String representing default issuer response data that will be used to generate the ARPC 112 */ 113 String getDefaultARPCRequest(boolean approved); 114 115 /** 116 * Select necessary data elements and create the string used to generate the ARQC with no padding 117 * <p> 118 * 119 * @param data ICC data received 120 * @param iad Issuer application Data 121 * @return String used to generate the ARQC 122 */ 123 String buildARQCRequest(TLVList data, IssuerApplicationData iad); 124 125 /** 126 * Select necessary data elements and create the string used to generate the ARQC with padding 127 * <p> 128 * 129 * @param data ICC data received 130 * @param iad Issuer application Data 131 * @return String used to generate the ARQC 132 */ 133 default String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad) { 134 return getPaddingMethod().apply(buildARQCRequest(data, iad)); 135 } 136 137 /** Defines how to pad the request data when generating the ARQC. 138 * @return PaddingMethod this builder uses 139 */ 140 PaddingMethod getPaddingMethod(); 141 142}