
com.github.devnied.emvnfccard.parser.impl.GeldKarteParser Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2019 MILLAU Julien
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.devnied.emvnfccard.parser.impl;
import com.github.devnied.emvnfccard.enums.CommandEnum;
import com.github.devnied.emvnfccard.enums.EmvCardScheme;
import com.github.devnied.emvnfccard.exception.CommunicationException;
import com.github.devnied.emvnfccard.iso7816emv.EmvTags;
import com.github.devnied.emvnfccard.model.Application;
import com.github.devnied.emvnfccard.model.EmvTrack2;
import com.github.devnied.emvnfccard.model.EmvTransactionRecord;
import com.github.devnied.emvnfccard.model.enums.ApplicationStepEnum;
import com.github.devnied.emvnfccard.model.enums.CardStateEnum;
import com.github.devnied.emvnfccard.model.enums.CurrencyEnum;
import com.github.devnied.emvnfccard.model.enums.TransactionTypeEnum;
import com.github.devnied.emvnfccard.parser.EmvTemplate;
import com.github.devnied.emvnfccard.utils.CommandApdu;
import com.github.devnied.emvnfccard.utils.ResponseUtils;
import com.github.devnied.emvnfccard.utils.TlvUtil;
import fr.devnied.bitlib.BytesUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
/**
* GeldKarte parser
* Documentation:
* - ftp://ftp.ccc.de/documentation/cards/geldkarte.pdf
* - http://www.bensin.org/haxor/haxor_src/ic35/crap/stash/scinfo_khf%20-%20geldkarte%20ic35/doku/gk.log
* - http://ftp.chaos-darmstadt.de/docs/cards/geldkarte.pdf
* - https://code.google.com/p/android/issues/detail?id=62976
* - http://www.openscdp.org/scripts/geldkarte/jsdoc/symbols/src/dump_girogo.js.html
* - http://www.wrankl.de/UThings/Geldkarte.pdf
*
* @author MILLAU Julien
*
*/
public class GeldKarteParser extends AbstractParser {
/**
* Class Logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(GeldKarteParser.class);
/**
* Geldkarte pattern
*/
private static final Pattern PATTERN = Pattern.compile(StringUtils.deleteWhitespace(EmvCardScheme.GELDKARTE.getAid()[2]) + ".*");
public GeldKarteParser(EmvTemplate pTemplate) {
super(pTemplate);
}
@Override
public Pattern getId() {
return PATTERN;
}
@Override
public boolean parse(Application pApplication) throws CommunicationException {
boolean ret = false;
// Select AID
byte[] data = selectAID(pApplication.getAid());
// Check response
if (ResponseUtils.isSucceed(data)) {
pApplication.setReadingStep(ApplicationStepEnum.SELECTED);
// Get TLV log entry
byte[] logEntry = getLogEntry(data);
// Get AID
pApplication.setAid(TlvUtil.getValue(data, EmvTags.DEDICATED_FILE_NAME));
// Application label
pApplication.setApplicationLabel(extractApplicationLabel(data));
// Add type
template.get().getCard().setType(EmvCardScheme.getCardTypeByAid(BytesUtils.bytesToStringNoSpace(pApplication.getAid())));
// Extract Bank data
extractBankData(data);
// read Ef_ID
extractEF_ID(pApplication);
// Read EF_BETRAG
readEfBetrag(pApplication);
// Read EF_BLOG
readEF_BLOG(pApplication);
pApplication.setLeftPinTry(getLeftPinTry());
pApplication.setTransactionCounter(getTransactionCounter());
// TODO remove this
pApplication.getListTransactions().addAll(extractLogEntry(logEntry));
// Update ret
template.get().getCard().setState(CardStateEnum.ACTIVE);
ret = true;
}
return ret;
}
/**
* Read EF_BLOG
*
* @param pApplication emv application
* @throws CommunicationException communication error
*/
protected void readEF_BLOG(final Application pApplication) throws CommunicationException{
List list = new ArrayList();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// Read each records
for (int i = 1; i < 16 ; i++) {
byte[] data = template.get().getProvider().transceive(new CommandApdu(CommandEnum.READ_RECORD, i, 0xEC, 0).toBytes());
// Check response
if (ResponseUtils.isSucceed(data)) {
if (data.length < 35){
continue;
}
EmvTransactionRecord record = new EmvTransactionRecord();
record.setCurrency(CurrencyEnum.EUR);
record.setTransactionType(getType(data[0]));
record.setAmount(Float.parseFloat(BytesUtils.bytesToStringNoSpace(Arrays.copyOfRange(data, 21, 24))) / 100L);
try {
record.setDate(dateFormat.parse(String.format("%02x.%02x.%02x%02x", data[32], data[31], data[29], data[30])));
record.setTime(timeFormat.parse(String.format("%02x:%02x:%02x", data[33], data[34], data[35])));
} catch (ParseException e) {
LOGGER.error(e.getMessage(), e);
}
list.add(record);
} else {
break;
}
}
pApplication.setListTransactions(list);
}
/**
* Method used to get the transaction type
* @param logstate the log state
* @return the transaction type or null
*/
protected TransactionTypeEnum getType(byte logstate) {
switch ( (logstate & 0x60) >> 5) {
case 0: return TransactionTypeEnum.LOADED;
case 1: return TransactionTypeEnum.UNLOADED;
case 2: return TransactionTypeEnum.PURCHASE;
case 3: return TransactionTypeEnum.REFUND;
}
return null;
}
/**
* read EF_BETRAG
*
* @param pApplication EMV application
* @throws CommunicationException communication error
*/
protected void readEfBetrag(final Application pApplication) throws CommunicationException {
// 00 B2 01 C4 00
byte[] data = template.get().getProvider()
.transceive(new CommandApdu(CommandEnum.READ_RECORD, 0x01, 0xC4, 0).toBytes());
// Check response
if (ResponseUtils.isSucceed(data)) {
pApplication.setAmount(Float.parseFloat(String.format("%02x%02x%02x", data[0], data[1], data[2]))/100.0f);
}
}
/**
* Method used to extract Ef_iD record
*
* @param pApplication EMV application
*
* @throws CommunicationException communication error
*/
protected void extractEF_ID(final Application pApplication) throws CommunicationException {
// 00B201BC00
byte[] data = template.get().getProvider().transceive(new CommandApdu(CommandEnum.READ_RECORD, 0x01, 0xBC, 0).toBytes());
if (ResponseUtils.isSucceed(data)) {
pApplication.setReadingStep(ApplicationStepEnum.READ);
// Date
SimpleDateFormat format = new SimpleDateFormat("MM/yy",Locale.getDefault());
// Track 2
EmvTrack2 track2 = new EmvTrack2();
track2.setCardNumber(BytesUtils.bytesToStringNoSpace(Arrays.copyOfRange(data, 4, 9)));
try {
track2.setExpireDate(format.parse(String.format("%02x/%02x", data[11], data[10])));
} catch (ParseException e) {
LOGGER.error(e.getMessage(),e);
}
template.get().getCard().setTrack2(track2);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy