Skip to content

Commit

Permalink
Merge pull request #269 from crocs-muni/devel
Browse files Browse the repository at this point in the history
Version 1.8.2 release
  • Loading branch information
petrs authored Nov 25, 2024
2 parents 1bcd0cc + 65adb74 commit 991c048
Show file tree
Hide file tree
Showing 27 changed files with 584 additions and 404 deletions.
Binary file added AlgTest_JClient/libs/jcardsim-3.0.6.0.jar
Binary file not shown.
163 changes: 148 additions & 15 deletions AlgTest_JClient/src/algtestjclient/AlgTestJClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ may be distributed under the terms of the GNU General Public License (GPL),
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.PatternSyntaxException;
import java.util.HashMap;
import java.util.Map;
import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardException;
Expand All @@ -51,12 +53,24 @@ may be distributed under the terms of the GNU General Public License (GPL),
* @author petr
*/
public class AlgTestJClient {
/**
* Version 1.8.2 (17.11.2024)
* - Update to match applet version with delayed allocation by default
* - Add detailed info for submitting results at beginning
* - Add testing of ECC 640b keys
* - Fix display of help info
* - Add always send Le=256 to support certain cards (like Gemalto) expecting it
* - Add sanity check for returned algtest buffer
* - Improved used and fixed issues with CLI parameters
* - Fix missing JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT in results
*/
public final static String ALGTEST_JCLIENT_VERSION = "1.8.2";
/**
* Version 1.8.1 (27.10.2021)
* + Add better CLI control, interactive and non-interactive mode
* + Fixed incorrect names for measurements
*/
public final static String ALGTEST_JCLIENT_VERSION = "1.8.1";
//public final static String ALGTEST_JCLIENT_VERSION = "1.8.1";
/**
* Version 1.8.0 (19.12.2020)
* + testing of modular Cipher and Signature .getInstance variants
Expand Down Expand Up @@ -165,72 +179,115 @@ public class AlgTestJClient {
* + initial version of AlgTestJClient, clone of AlgTestCppClient
*/
//public final static String ALGTEST_JCLIENT_VERSION_1_0 = "1.0";



public final static int STAT_OK = 0;

// Unique start time in milisconds
static long m_appStartTime = 0;

static Map<String, Map<String, String>> allResultsMap = new HashMap<>();


/**
* @param args the command line arguments
*/

static DirtyLogger m_SystemOutLogger = null;
public static void main(String[] args) throws IOException, Exception {
Map<String, String> tempInfo = new HashMap<>();

Args cmdArgs = new Args();
if (args.length > 0) {
// cli version of tool
JCommander.newBuilder()
.addObject(cmdArgs)
.build()
.parse(args);

if (!cmdArgs.baseOutPath.isEmpty()) {
char lastChar = cmdArgs.baseOutPath.charAt(cmdArgs.baseOutPath.length() - 1);
if ((lastChar != '\\') && (lastChar != '/')) {
cmdArgs.baseOutPath = cmdArgs.baseOutPath + "/"; // adding '/' if not present
}
}
}
System.out.print("Command line arguments: ");
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + " ");
}
System.out.println();

String logFileName = String.format(cmdArgs.baseOutPath + "ALGTEST_log_%s.log", AlgTestJClient.getStartTime());
FileOutputStream systemOutLogger = new FileOutputStream(logFileName);
tempInfo.put("out_file_name", logFileName);
allResultsMap.put("main", tempInfo);
m_SystemOutLogger = new DirtyLogger(systemOutLogger, true);

m_SystemOutLogger.println("\n----------------------------------------------------------------------- ");
m_SystemOutLogger.println("JCAlgTest " + ALGTEST_JCLIENT_VERSION + " - comprehensive tool for JavaCard smart card testing.");
m_SystemOutLogger.println("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2021.");
m_SystemOutLogger.println("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2024.");
m_SystemOutLogger.println("Please check if you use the latest version at\n https://github.com/crocs-muni/JCAlgTest/releases/latest.");
m_SystemOutLogger.println("Type 'java -jar jcalgtestclient --help' to display help and available commands.");
m_SystemOutLogger.println("-----------------------------------------------------------------------\n");

CardTerminal selectedTerminal = null;
PerformanceTesting testingPerformance = new PerformanceTesting(m_SystemOutLogger);
m_SystemOutLogger.println("NOTE: JCAlgTest applet (AlgTest.cap) must be already installed on tested card.");
m_SystemOutLogger.println(" java -jar gp.jar --install AlgTest_***_jc***.cap");
m_SystemOutLogger.println("The results are stored in CSV files. Use JCAlgProcess for HTML conversion.");
m_SystemOutLogger.println();

if (cmdArgs.help) {
JCommander.newBuilder().addObject(cmdArgs).build().usage();
JCommander.newBuilder().addObject(cmdArgs).build().usage();
return;
}

if (args.length > 0) {
m_SystemOutLogger.println("Running in non-interactive mode. Run without any parameter to enter interactive mode. Run 'java -jar AlgTestJClient.jar -help' to obtain list of supported arguments.");

// If selftest is enabled, then prepare testing session with simulator, execute and check for results
if (cmdArgs.selftest) {
cmdArgs.simulator = true;
cmdArgs.fresh = true;
cmdArgs.cardName = Args.SELFTEST_CARD_NAME;
cmdArgs.operations.clear();
cmdArgs.operations.add(Args.OP_ALG_SUPPORT_EXTENDED);
cmdArgs.operations.add(Args.OP_ALG_ECC_PERFORMANCE);
cmdArgs.operations.add(Args.OP_ALG_FINGERPRINT);
cmdArgs.operations.add(Args.OP_ALG_PERFORMANCE_STATIC);
cmdArgs.operations.add(Args.OP_ALG_PERFORMANCE_VARIABLE);
}

printSendRequest();
if (cmdArgs.operations.size() > 0) {
m_SystemOutLogger.println("Running in non-interactive mode. Run without any parameter to enter interactive mode. Run 'java -jar AlgTestJClient.jar --help' to obtain list of supported arguments.");
for (String operation : cmdArgs.operations) {
if (operation.compareTo(Args.OP_ALG_SUPPORT_BASIC) == 0 ||
operation.compareTo(Args.OP_ALG_SUPPORT_EXTENDED) == 0) {
selectedTerminal = selectTargetReader(cmdArgs);
if (selectedTerminal != null) {
SingleModeTest singleTest = new SingleModeTest(m_SystemOutLogger);
singleTest.TestSingleAlg(operation, cmdArgs, selectedTerminal);
Map<String, String> testResults = singleTest.TestSingleAlg(operation, cmdArgs, selectedTerminal);
allResultsMap.put(operation, testResults);
}
}
else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 ||
operation.compareTo(Args.OP_ALG_PERFORMANCE_VARIABLE) == 0) {
selectedTerminal = selectTargetReader(cmdArgs);
if (selectedTerminal != null) {
testingPerformance.testPerformance(false, operation, selectedTerminal, cmdArgs);
Map<String, String> testResults = testingPerformance.testPerformance(false, operation, selectedTerminal, cmdArgs);
allResultsMap.put(operation, testResults);
}
}
else if (operation.compareTo(Args.OP_ALG_ECC_PERFORMANCE) == 0) {
selectedTerminal = selectTargetReader(cmdArgs);
if (selectedTerminal != null) {
Map<String, String> testResults = testingPerformance.testECCPerformance(args, true, selectedTerminal, cmdArgs);
allResultsMap.put(operation, testResults);
}
}
else if (operation.compareTo(Args.OP_ALG_FINGERPRINT) == 0) {
selectedTerminal = selectTargetReader(cmdArgs);
if (selectedTerminal != null) {
Map<String, String> testResults = testingPerformance.testPerformanceFingerprint(args, selectedTerminal, cmdArgs);
allResultsMap.put(operation, testResults);
}
}
else {
Expand All @@ -241,7 +298,7 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 ||
}
else {
// Interactive mode of tool
m_SystemOutLogger.println("Running in interactive mode. Run 'java -jar AlgTestJClient.jar -help' to obtain list of supported arguments.");
m_SystemOutLogger.println("Running in interactive mode. Run 'java -jar AlgTestJClient.jar --help' to obtain list of supported arguments.");
m_SystemOutLogger.println("CHOOSE test you want to run:");
m_SystemOutLogger.println("1 -> SUPPORTED ALGORITHMS\n List all supported JC API algorithms (2-10 minutes)\n" +
"2 -> PERFORMANCE TEST\n Test all JC API methods with 256B data length (1-3 hours)\n" +
Expand Down Expand Up @@ -297,6 +354,10 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 ||
}
}
printSendRequest();

if (cmdArgs.selftest) {
checkSelfTestResults(allResultsMap);
}
}

static long getStartTime() {
Expand All @@ -312,8 +373,9 @@ static void printSendRequest() {
System.out.println("available to all JavaCard enthusiasts at http://jcalgtest.org.");
System.out.println("The results are important even if a card of same type is already in database.");
System.out.println("Send *.log and *.csv files from the current directory to <petr@svenda.com>.");
System.out.println("Thank you very much!");
System.out.println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
System.out.println("ESPECIALLY if testing fails, please let us know so we can fix it for you and others.");
System.out.println("Thank you very much.");
System.out.println("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n");
}

static void performKeyHarvest(Args cmdArgs) throws CardException {
Expand Down Expand Up @@ -444,8 +506,10 @@ static CardTerminal selectTargetReader(Args cmdArgs) {
m_SystemOutLogger.println("\nAvailable readers:");
for (CardTerminal terminal : terminalList) {
Card card;
String protocol = System.getenv().getOrDefault("ALGTEST_PROTO", "*");
try {
card = terminal.connect("*");
card = terminal.connect(protocol);
//card = terminal.connect("*");
ATR atr = card.getATR();
m_SystemOutLogger.println(String.format("%d : [*] %s - %s", terminalIndex, terminal.getName(), CardMngr.bytesToHex(atr.getBytes())));
terminalIndex++;
Expand All @@ -470,4 +534,73 @@ static CardTerminal selectTargetReader(Args cmdArgs) {
}
}

private static boolean checkFileExistence(String fileName) {
File file = new File(fileName);
if (file.exists()) {
m_SystemOutLogger.println(String.format(" OK: the file '%s' exists.", fileName));
} else {
m_SystemOutLogger.println(String.format(" ERROR: the file '%s' does not exist.", fileName));
}
return file.exists();
}

private static boolean checkExpectedValue(Map<String, Map<String, String>> allResults, String op, String key, String expectedValue) {
if (allResults.get(op).get(key).equalsIgnoreCase(expectedValue)){
m_SystemOutLogger.println(String.format(" OK: %s->%s = %s matches.", op, key, expectedValue));
} else {
m_SystemOutLogger.println(String.format(" ERROR: %s->%s = %s mismatch (expected=%s).", op, key, allResults.get(op).get(key), expectedValue));
}
return allResults.get(op).get(key).equalsIgnoreCase(expectedValue);
}

public static boolean checkSelfTestResults(Map<String, Map<String, String>> allResults) {
boolean bSelftestSuccess = true;
// Print all collected info keys
m_SystemOutLogger.println("###### SELFTEST ####################################");
m_SystemOutLogger.println("All collected selftest results:");
for (String operation : allResults.keySet()) {
m_SystemOutLogger.println(String.format(" %s:", operation));
Map<String, String> oneOpResults = allResults.get(operation);
for (String key : oneOpResults.keySet()) {
m_SystemOutLogger.println(String.format(" %s = %s", key, oneOpResults.get(key)));
}
}

// Check existence of output files for separate operations
m_SystemOutLogger.println("\nSelftest tests finished, now checking results...");
for (String op : allResults.keySet()) {
m_SystemOutLogger.println(String.format(" Checking operation '%s':", op));
// Always check existence of output file
if (!checkFileExistence(allResults.get(op).get("out_file_name"))) { bSelftestSuccess = false; }
// Check selected values for selected results
if (op.equals(Args.OP_ALG_PERFORMANCE_STATIC)) {
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "290")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "204")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "66")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "errors_observed", "560")) { bSelftestSuccess = false; }
}
if (op.equals(Args.OP_ALG_PERFORMANCE_VARIABLE)) {
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "145")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "327")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "35")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "errors_observed", "507")) { bSelftestSuccess = false; }
}
if (op.equals(Args.OP_ALG_FINGERPRINT)) {
if (!checkExpectedValue(allResults, op, "NO_SUCH_ALGORITHM", "1")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "CANT_BE_MEASURED", "18")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "ILLEGAL_VALUE", "8")) { bSelftestSuccess = false; }
if (!checkExpectedValue(allResults, op, "errors_observed", "27")) { bSelftestSuccess = false; }
}
if (op.equals(Args.OP_ALG_ECC_PERFORMANCE)) {
if (!checkExpectedValue(allResults, op, "errors_observed", "0")) { bSelftestSuccess = false; }
}
}
if (!bSelftestSuccess) {
m_SystemOutLogger.println("ERROR: some test(s) failed");
}
m_SystemOutLogger.println("###### END SELFTEST ####################################");

return bSelftestSuccess;
}

}
11 changes: 10 additions & 1 deletion AlgTest_JClient/src/algtestjclient/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
* @author Petr Svenda
*/
public class Args {
// If extending, do not forget to add into @Parameter(names = below
public static final String OP_ALG_SUPPORT_BASIC = "ALG_SUPPORT_BASIC"; // Test of basic algorithmic support
public static final String OP_ALG_SUPPORT_EXTENDED = "ALG_SUPPORT_EXTENDED"; // Test of basic + extended algorithmic support
public static final String OP_ALG_PERFORMANCE_STATIC = "ALG_PERFORMANCE_STATIC"; // Test of performance on static data length
public static final String OP_ALG_PERFORMANCE_VARIABLE = "ALG_PERFORMANCE_VARIABLE"; // Test of performance with variable data lengths
public static final String OP_ALG_ECC_PERFORMANCE = "ALG_ECC_PERFORMANCE"; // Test of performance of ECC operations
public static final String OP_ALG_FINGERPRINT = "ALG_FINGERPRINT"; // Test only selected operations
public static final String SELFTEST_CARD_NAME = "simul-selftest"; // Name of the simulated card using during

@Parameter
public List<String> parameters = new ArrayList<>();

@Parameter(names = { "-op"}, description = "Operation(s) to execute (ALG_SUPPORT_SIMPLE | ALG_SUPPORT_ALL)")
@Parameter(names = { "-op"}, description = "Operation(s) to execute (" + OP_ALG_SUPPORT_BASIC + " | " + OP_ALG_SUPPORT_EXTENDED
+ " | " + OP_ALG_PERFORMANCE_STATIC + " | " + OP_ALG_PERFORMANCE_VARIABLE + ")")
public List<String> operations = new ArrayList<>();

@Parameter(names = "-cardname", description = "Name of the tested card")
Expand All @@ -34,4 +39,8 @@ public class Args {

@Parameter(names = "-fresh", description = "Force generating new complete measurements")
public boolean fresh = false;

@Parameter(names = "-selftest", description = "Executes selftesting using simulator as target.")
public boolean selftest = false;

}
Loading

0 comments on commit 991c048

Please sign in to comment.