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 /** Specifies the padding method applied when building cryptogram data. */ 037 enum PaddingMethod { 038 /** No padding is applied. */ 039 NO_PADDING, 040 041 /** 042 * ISO/IEC 9797-1 padding method 1 043 * for Block size 8, n = 64 044 */ 045 ISO9797Method1 { 046 @Override 047 public String apply(String data) { 048 return data.isEmpty() ? 049 "0000000000000000" : 050 ISOUtil.zeropadRight(data, data.length() % 16 == 0 ? data.length() : data.length() + 16 - data.length() % 16); 051 } 052 }, 053 054 /** 055 * ISO/IEC 9797-1 padding method 2 056 * for Block size 8, n = 64 057 */ 058 ISO9797Method2 { 059 @Override 060 public String apply(String data) { 061 return ISO9797Method1.apply(data + "80"); 062 } 063 }, 064 065 /** 066 * ISO/IEC 9797-1 padding method 3 067 * for Block size 8, n = 64 068 */ 069 ISO9797Method3 { 070 @Override 071 public String apply(String data) { 072 StringBuilder sb = new StringBuilder(); 073 String D = ISO9797Method1.apply(data); 074 String Ld = ISOUtil.byte2hex(ISOUtil.int2byte(data.length() / 2)); 075 String Lp = ISO9797Method1.apply(Ld); 076 Lp = Ld.length() % 16 == 0 ? "" : Lp.substring(Ld.length()); 077 return sb.append(Lp).append(Ld).append(D).toString(); 078 } 079 }; 080 081 /** 082 * Applies this padding method to the given hex string. 083 * @param data the hex string to pad 084 * @return the padded hex string 085 */ 086 public String apply(String data) { 087 return data; 088 } 089 } 090 091 /** 092 * Method that selects the minimum set of data elements recommended for 093 * the generation of application cryptograms described in EMV Book 2 sec 8.1.1 094 * 095 * @param data ICC data 096 * @return Minimum Set of Data Elements for Application Cryptogram Generation 097 */ 098 static List<String> minimumSetOfDataElement(TLVList data) { 099 return Arrays.asList( 100 data.getString(EMVStandardTagType.AMOUNT_AUTHORISED_NUMERIC_0x9F02.getTagNumber()), 101 Optional.ofNullable(data.getString(EMVStandardTagType.AMOUNT_OTHER_NUMERIC_0x9F03.getTagNumber())) 102 .orElse("000000000000"), 103 data.getString(EMVStandardTagType.TERMINAL_COUNTRY_CODE_0x9F1A.getTagNumber()), 104 data.getString(EMVStandardTagType.TERMINAL_VERIFICATION_RESULTS_0x95.getTagNumber()), 105 data.getString(EMVStandardTagType.TRANSACTION_CURRENCY_CODE_0x5F2A.getTagNumber()), 106 data.getString(EMVStandardTagType.TRANSACTION_DATE_0x9A.getTagNumber()), 107 data.getString(EMVStandardTagType.TRANSACTION_TYPE_0x9C.getTagNumber()), 108 data.getString(EMVStandardTagType.UNPREDICTABLE_NUMBER_0x9F37.getTagNumber()), 109 data.getString(EMVStandardTagType.APPLICATION_INTERCHANGE_PROFILE_0x82.getTagNumber()), 110 data.getString(EMVStandardTagType.APPLICATION_TRANSACTION_COUNTER_0x9F36.getTagNumber()) 111 ); 112 } 113 114 /** 115 * Method that returns default issuer response data (ARC or CSU) 116 * 117 * @param approved true if transaction was approved, otherwise false 118 * @return String representing default issuer response data that will be used to generate the ARPC 119 */ 120 String getDefaultARPCRequest(boolean approved); 121 122 /** 123 * Select necessary data elements and create the string used to generate the ARQC with no padding. 124 * 125 * @param data ICC data received 126 * @param iad Issuer application Data 127 * @return String used to generate the ARQC 128 */ 129 String buildARQCRequest(TLVList data, IssuerApplicationData iad); 130 131 /** 132 * Select necessary data elements and create the string used to generate the ARQC with padding. 133 * 134 * @param data ICC data received 135 * @param iad Issuer application Data 136 * @return String used to generate the ARQC 137 */ 138 default String buildARQCRequest_padded(TLVList data, IssuerApplicationData iad) { 139 return getPaddingMethod().apply(buildARQCRequest(data, iad)); 140 } 141 142 /** Defines how to pad the request data when generating the ARQC. 143 * @return PaddingMethod this builder uses 144 */ 145 PaddingMethod getPaddingMethod(); 146 147}