Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfehr committed Mar 26, 2023
1 parent ced4f0d commit 02c40f8
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .idea/deploymentTargetDropDown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ public void onTagDiscovered(Tag tag) {

printStepHeader(0, "our journey begins");

writeToUiAppend("increase IsoDep timeout for long reading");
writeToUiAppend("timeout old: " + nfc.getTimeout() + " ms");
nfc.setTimeout(10000);
writeToUiAppend("timeout new: " + nfc.getTimeout() + " ms");


/**
* step 1 code start
Expand Down Expand Up @@ -269,6 +274,7 @@ public void onTagDiscovered(Tag tag) {
writeToUiAppend("### processing the VisaCard and GiroCard path ###");
writeToUiAppend("");
byte[] pdolValue = tag9f38.getBytesValue();
/*
writeToUiAppend("found tag 0x9F38 in the selectAid with this length: " + pdolValue.length + " data: " + bytesToHexNpe(pdolValue));
// using modified code from DOL.java sasc999
Expand All @@ -292,7 +298,13 @@ public void onTagDiscovered(Tag tag) {
gpoRequestCommand = getGpoFromPdol(pdolValue);
//gpoRequestCommand = getGetProcessingOptionsFromPdol(pdolValue); // not working for DKB Visa

*/
writeToUiAppend("found tag 0x9F38 (PDOL) in the selectAid with this length: " + pdolValue.length + " data: " + bytesToHexNpe(pdolValue));
byte[][] gpoRequestCommandArray = getGpoFromPdolExtended(pdolValue, 0);
gpoRequestCommand = gpoRequestCommandArray[0];
String pdolRequestString = new String(gpoRequestCommandArray[1], StandardCharsets.UTF_8);
writeToUiAppend("");
writeToUiAppend(pdolRequestString);
} else { // if (tag9f38 != null) {
/**
* MasterCard code
Expand All @@ -302,7 +314,12 @@ public void onTagDiscovered(Tag tag) {
writeToUiAppend("");

writeToUiAppend("No PDOL found in the selectAid response, generating a 'null' PDOL");
gpoRequestCommand = getGpoFromPdol(new byte[0]); // empty PDOL
//gpoRequestCommand = getGpoFromPdol(new byte[0]); // empty PDOL
byte[][] gpoRequestCommandArray = getGpoFromPdolExtended(new byte[0], 0);
gpoRequestCommand = gpoRequestCommandArray[0];
String pdolRequestString = new String(gpoRequestCommandArray[1], StandardCharsets.UTF_8);
writeToUiAppend("");
writeToUiAppend(pdolRequestString);
}

writeToUiAppend("");
Expand Down Expand Up @@ -498,12 +515,13 @@ public void onTagDiscovered(Tag tag) {
writeToUiAppend("07 get PAN and Expiration date from tags 0x5a and 0x5f24");
writeToUiAppend("data for AID " + bytesToHexNpe(aidSelected));
writeToUiAppend("PAN: " + readRecordPanString);
// todo yymmdd or yymm depending on length
writeToUiAppend("Expiration date (YYMM): " + readRecordExpirationDateString);
writeToUiAppend("");
}
} catch (RuntimeException e) {
//System.out.println("Runtime Exception: " + e.getMessage());
startEndSequence(nfc);
System.out.println("Runtime Exception: " + e.getMessage());
//startEndSequence(nfc);
}
} else {
writeToUiAppend("readRecord response was NULL");
Expand Down Expand Up @@ -638,6 +656,109 @@ private byte[] getGetProcessingOptionsFromPdol(final byte[] pPdol) throws Commun
//return template.get().getProvider().transceive(new CommandApdu(CommandEnum.GPO, out.toByteArray(), 0).toBytes());
}

/**
* construct the getProcessingOptions command using the provided pdol
* the default ttq is null, but another ttq can used if default ttq gives no result for later sending
* @param pdol
* @param ttq
* @return a byte[][] array
* [0] = getProcessingOptions command
* [1] = text table with requested tags from pdol with length and value
*/
private byte[][] getGpoFromPdolExtended(@NonNull byte[] pdol, int ttq) {

// todo implement alternative ttq

byte[][] result = new byte[2][];

// get the tags in a list
List<com.github.devnied.emvnfccard.iso7816emv.TagAndLength> tagAndLength = TlvUtil.parseTagAndLength(pdol);
int tagAndLengthSize = tagAndLength.size();
StringBuilder returnString = new StringBuilder();
returnString.append("The card is requesting " + tagAndLengthSize + (tagAndLengthSize == 1 ? " tag" : " tags")).append(" in the PDOL").append("\n");
returnString.append("\n");
returnString.append("Tag Tag Name Length Value").append("\n");
returnString.append("-----------------------------------------------------").append("\n");
if (tagAndLengthSize < 1) {
returnString.append(" no PDOL provided, returning an empty command").append("\n");
returnString.append("-----------------------------------------------------");
// there are no pdols in the list
//Log.e(TAG, "there are no PDOLs in the pdol array, aborted");
//return null;
// returning an empty PDOL
String tagLength2d = "00"; // length value
String tagLength2dAnd2 = "02"; // length value + 2
String constructedGpoCommandString = "80A80000" + tagLength2dAnd2 + "83" + tagLength2d + "" + "00";
result[0] = hexToBytes(constructedGpoCommandString);
result[1] = returnString.toString().getBytes(StandardCharsets.UTF_8);
return result;
//return hexToBytes(constructedGpoCommandString);
}
int valueOfTagSum = 0; // total length
StringBuilder sb = new StringBuilder(); // takes the default values of the tags
DolValues dolValues = new DolValues();
for (int i = 0; i < tagAndLengthSize; i++) {
// get a single tag
com.github.devnied.emvnfccard.iso7816emv.TagAndLength tal = tagAndLength.get(i); // eg 9f3704
byte[] tagToSearch = tal.getTag().getTagBytes(); // gives the tag 9f37
int lengthOfTag = tal.getLength(); // 4
String nameOfTag = tal.getTag().getName();
valueOfTagSum += tal.getLength(); // add it to the sum
// now we are trying to find a default value
byte[] defaultValue = dolValues.getDolValue(tagToSearch);
byte[] usedValue = new byte[0];
if (defaultValue != null) {
if (defaultValue.length > lengthOfTag) {
// cut it to correct length
usedValue = Arrays.copyOfRange(defaultValue, 0, lengthOfTag);
Log.i(TAG, "asked for tag: " + bytesToHexNpe(tal.getTag().getTagBytes()) + " default is too long, cut to: " + bytesToHexNpe(usedValue));
} else if (defaultValue.length < lengthOfTag) {
// increase length
usedValue = new byte[lengthOfTag];
System.arraycopy(defaultValue, 0, usedValue, 0, defaultValue.length);
Log.i(TAG, "asked for tag: " + bytesToHexNpe(tal.getTag().getTagBytes()) + " default is too short, increased to: " + bytesToHexNpe(usedValue));
} else {
// correct length
usedValue = defaultValue.clone();
Log.i(TAG, "asked for tag: " + bytesToHexNpe(tal.getTag().getTagBytes()) + " default found: " + bytesToHexNpe(usedValue));
}
} else {
// defaultValue is null means the tag was not found in our tags database for default values
usedValue = new byte[lengthOfTag];
Log.i(TAG, "asked for tag: " + bytesToHexNpe(tal.getTag().getTagBytes()) + " NO default found, generate zeroed: " + bytesToHexNpe(usedValue));
}
// now usedValue does have the correct length
sb.append(bytesToHexNpe(usedValue));
returnString.append(trimStringRight(bytesToHexNpe(tagToSearch),5)).append(trimStringRight(nameOfTag, 36)).append(trimStringRight(String.valueOf(lengthOfTag), 3)).append(bytesToHexBlankNpe(usedValue)).append("\n");
}
returnString.append("-----------------------------------------------------").append("\n");
String constructedGpoString = sb.toString();
String tagLength2d = bytesToHexNpe(intToByteArray(valueOfTagSum)); // length value
String tagLength2dAnd2 = bytesToHexNpe(intToByteArray(valueOfTagSum + 2)); // length value + 2
String constructedGpoCommandString = "80A80000" + tagLength2dAnd2 + "83" + tagLength2d + constructedGpoString + "00";
result[0] = hexToBytes(constructedGpoCommandString);
result[1] = returnString.toString().getBytes(StandardCharsets.UTF_8);
return result;
//return hexToBytes(constructedGpoCommandString);
}

/**
* add blanks to a string on right side up to a length of len
* if the data.length >= len one character is deleted to get minimum one blank
* @param data
* @param len
* @return
*/
private String trimStringRight(String data, int len) {
if (data.length() >= len) {
data = data.substring(0, (len - 1));
}
while (data.length() < len) {
data = data + " ";
}
return data;
}

/**
* step 5 code start
*/
Expand Down Expand Up @@ -691,7 +812,6 @@ private String removeTrailingF(String input) {
* overview: https://github.com/sasc999/javaemvreader/blob/master/src/main/java/sasc/emv/EMVAPDUCommands.java
*/

// Get the data of ATC(Application Transaction Counter, tag '9F36')), template 77 or 80
private byte[] getChallenge(IsoDep nfc) {
byte[] cmd = new byte[]{(byte) 0x80, (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x00};
byte[] result = new byte[0];
Expand Down Expand Up @@ -829,27 +949,32 @@ private byte[] getTagValueFromResult(byte[] data, byte... search) {
private String dumpSingleData(byte[] applicationTransactionCounter, byte[] pinTryCounter, byte[] lastOnlineATCRegister, byte[] logFormat) {
StringBuilder sb = new StringBuilder();
sb.append("single data retrieved from card").append("\n");
sb.append("-----------------------------------------------------").append("\n");
if (applicationTransactionCounter != null) {
//sb.append("applicationTransactionCounter: ").append(bytesToHexNpe(applicationTransactionCounter)).append(" (hex), ").append(BinaryUtils.intFromByteArrayV4(applicationTransactionCounter)).append(" (dec)").append("\n");
sb.append("applicationTransactionCounter: ").append(bytesToHexNpe(applicationTransactionCounter)).append(" (hex), ").append(intFromByteArray(applicationTransactionCounter)).append(" (dec)").append("\n");
} else {
sb.append("applicationTransactionCounter: NULL").append("\n");
}
sb.append("-----------------------------------------------------").append("\n");
if (pinTryCounter != null) {
sb.append("pinTryCounter: ").append(bytesToHexNpe(pinTryCounter)).append("\n");
} else {
sb.append("pinTryCounter: NULL").append("\n");
}
sb.append("-----------------------------------------------------").append("\n");
if (lastOnlineATCRegister != null) {
sb.append("lastOnlineATCRegister: ").append(bytesToHexNpe(lastOnlineATCRegister)).append("\n");
} else {
sb.append("lastOnlineATCRegister: NULL").append("\n");
}
sb.append("-----------------------------------------------------").append("\n");
if (logFormat != null) {
sb.append("logFormat: ").append(bytesToHexNpe(logFormat)).append("\n");
} else {
sb.append("logFormat: NULL").append("\n");
}
sb.append("-----------------------------------------------------").append("\n");
return sb.toString();
}

Expand Down Expand Up @@ -983,6 +1108,19 @@ public static String bytesToHexNpe(byte[] bytes) {
}
}

/**
* converts a byte array to a hex encoded string
* This method is Null Pointer Exception (NPE) safe
* @param bytes
* @return hex encoded string with a blank after each value
*/
public static String bytesToHexBlankNpe(byte[] bytes) {
if (bytes == null) return "";
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1)).append(" ");
return result.toString();
}

/**
* converts a hex encoded string to a byte array
*
Expand Down Expand Up @@ -1213,6 +1351,7 @@ private void clearData(final TextView textView) {
}

private void writeToUiAppend(String message) {
System.out.println(message);
outputString = outputString + message + "\n";
}

Expand Down

0 comments on commit 02c40f8

Please sign in to comment.