@@ -40,6 +40,8 @@ may be distributed under the terms of the GNU General Public License (GPL),
40
40
import java .util .logging .Level ;
41
41
import java .util .logging .Logger ;
42
42
import java .util .regex .PatternSyntaxException ;
43
+ import java .util .HashMap ;
44
+ import java .util .Map ;
43
45
import javax .smartcardio .ATR ;
44
46
import javax .smartcardio .Card ;
45
47
import javax .smartcardio .CardException ;
@@ -51,12 +53,24 @@ may be distributed under the terms of the GNU General Public License (GPL),
51
53
* @author petr
52
54
*/
53
55
public class AlgTestJClient {
56
+ /**
57
+ * Version 1.8.2 (17.11.2024)
58
+ * - Update to match applet version with delayed allocation by default
59
+ * - Add detailed info for submitting results at beginning
60
+ * - Add testing of ECC 640b keys
61
+ * - Fix display of help info
62
+ * - Add always send Le=256 to support certain cards (like Gemalto) expecting it
63
+ * - Add sanity check for returned algtest buffer
64
+ * - Improved used and fixed issues with CLI parameters
65
+ * - Fix missing JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT in results
66
+ */
67
+ public final static String ALGTEST_JCLIENT_VERSION = "1.8.2" ;
54
68
/**
55
69
* Version 1.8.1 (27.10.2021)
56
70
* + Add better CLI control, interactive and non-interactive mode
57
71
* + Fixed incorrect names for measurements
58
72
*/
59
- public final static String ALGTEST_JCLIENT_VERSION = "1.8.1" ;
73
+ // public final static String ALGTEST_JCLIENT_VERSION = "1.8.1";
60
74
/**
61
75
* Version 1.8.0 (19.12.2020)
62
76
* + testing of modular Cipher and Signature .getInstance variants
@@ -165,72 +179,115 @@ public class AlgTestJClient {
165
179
* + initial version of AlgTestJClient, clone of AlgTestCppClient
166
180
*/
167
181
//public final static String ALGTEST_JCLIENT_VERSION_1_0 = "1.0";
168
-
169
-
182
+
170
183
public final static int STAT_OK = 0 ;
171
184
172
185
// Unique start time in milisconds
173
186
static long m_appStartTime = 0 ;
187
+
188
+ static Map <String , Map <String , String >> allResultsMap = new HashMap <>();
189
+
174
190
175
191
/**
176
192
* @param args the command line arguments
177
193
*/
178
194
179
195
static DirtyLogger m_SystemOutLogger = null ;
180
196
public static void main (String [] args ) throws IOException , Exception {
197
+ Map <String , String > tempInfo = new HashMap <>();
198
+
181
199
Args cmdArgs = new Args ();
182
200
if (args .length > 0 ) {
183
201
// cli version of tool
184
202
JCommander .newBuilder ()
185
203
.addObject (cmdArgs )
186
204
.build ()
187
205
.parse (args );
188
-
206
+
189
207
if (!cmdArgs .baseOutPath .isEmpty ()) {
190
208
char lastChar = cmdArgs .baseOutPath .charAt (cmdArgs .baseOutPath .length () - 1 );
191
209
if ((lastChar != '\\' ) && (lastChar != '/' )) {
192
210
cmdArgs .baseOutPath = cmdArgs .baseOutPath + "/" ; // adding '/' if not present
193
211
}
194
212
}
195
213
}
214
+ System .out .print ("Command line arguments: " );
215
+ for (int i = 0 ; i < args .length ; i ++) {
216
+ System .out .print (args [i ] + " " );
217
+ }
218
+ System .out .println ();
196
219
197
220
String logFileName = String .format (cmdArgs .baseOutPath + "ALGTEST_log_%s.log" , AlgTestJClient .getStartTime ());
198
221
FileOutputStream systemOutLogger = new FileOutputStream (logFileName );
222
+ tempInfo .put ("out_file_name" , logFileName );
223
+ allResultsMap .put ("main" , tempInfo );
199
224
m_SystemOutLogger = new DirtyLogger (systemOutLogger , true );
200
225
201
226
m_SystemOutLogger .println ("\n ----------------------------------------------------------------------- " );
202
227
m_SystemOutLogger .println ("JCAlgTest " + ALGTEST_JCLIENT_VERSION + " - comprehensive tool for JavaCard smart card testing." );
203
- m_SystemOutLogger .println ("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2021 ." );
228
+ m_SystemOutLogger .println ("Visit jcalgtest.org for results from 100+ cards. CRoCS lab 2007-2024 ." );
204
229
m_SystemOutLogger .println ("Please check if you use the latest version at\n https://github.com/crocs-muni/JCAlgTest/releases/latest." );
205
230
m_SystemOutLogger .println ("Type 'java -jar jcalgtestclient --help' to display help and available commands." );
206
231
m_SystemOutLogger .println ("-----------------------------------------------------------------------\n " );
207
232
208
233
CardTerminal selectedTerminal = null ;
209
234
PerformanceTesting testingPerformance = new PerformanceTesting (m_SystemOutLogger );
210
235
m_SystemOutLogger .println ("NOTE: JCAlgTest applet (AlgTest.cap) must be already installed on tested card." );
236
+ m_SystemOutLogger .println (" java -jar gp.jar --install AlgTest_***_jc***.cap" );
211
237
m_SystemOutLogger .println ("The results are stored in CSV files. Use JCAlgProcess for HTML conversion." );
212
238
m_SystemOutLogger .println ();
213
239
214
240
if (cmdArgs .help ) {
215
- JCommander .newBuilder ().addObject (cmdArgs ).build ().usage ();
241
+ JCommander .newBuilder ().addObject (cmdArgs ).build ().usage ();
242
+ return ;
216
243
}
217
-
218
- if (args .length > 0 ) {
219
- 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." );
244
+
245
+ // If selftest is enabled, then prepare testing session with simulator, execute and check for results
246
+ if (cmdArgs .selftest ) {
247
+ cmdArgs .simulator = true ;
248
+ cmdArgs .fresh = true ;
249
+ cmdArgs .cardName = Args .SELFTEST_CARD_NAME ;
250
+ cmdArgs .operations .clear ();
251
+ cmdArgs .operations .add (Args .OP_ALG_SUPPORT_EXTENDED );
252
+ cmdArgs .operations .add (Args .OP_ALG_ECC_PERFORMANCE );
253
+ cmdArgs .operations .add (Args .OP_ALG_FINGERPRINT );
254
+ cmdArgs .operations .add (Args .OP_ALG_PERFORMANCE_STATIC );
255
+ cmdArgs .operations .add (Args .OP_ALG_PERFORMANCE_VARIABLE );
256
+ }
257
+
258
+ printSendRequest ();
259
+ if (cmdArgs .operations .size () > 0 ) {
260
+ 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." );
220
261
for (String operation : cmdArgs .operations ) {
221
262
if (operation .compareTo (Args .OP_ALG_SUPPORT_BASIC ) == 0 ||
222
263
operation .compareTo (Args .OP_ALG_SUPPORT_EXTENDED ) == 0 ) {
223
264
selectedTerminal = selectTargetReader (cmdArgs );
224
265
if (selectedTerminal != null ) {
225
266
SingleModeTest singleTest = new SingleModeTest (m_SystemOutLogger );
226
- singleTest .TestSingleAlg (operation , cmdArgs , selectedTerminal );
267
+ Map <String , String > testResults = singleTest .TestSingleAlg (operation , cmdArgs , selectedTerminal );
268
+ allResultsMap .put (operation , testResults );
227
269
}
228
270
}
229
271
else if (operation .compareTo (Args .OP_ALG_PERFORMANCE_STATIC ) == 0 ||
230
272
operation .compareTo (Args .OP_ALG_PERFORMANCE_VARIABLE ) == 0 ) {
231
273
selectedTerminal = selectTargetReader (cmdArgs );
232
274
if (selectedTerminal != null ) {
233
- testingPerformance .testPerformance (false , operation , selectedTerminal , cmdArgs );
275
+ Map <String , String > testResults = testingPerformance .testPerformance (false , operation , selectedTerminal , cmdArgs );
276
+ allResultsMap .put (operation , testResults );
277
+ }
278
+ }
279
+ else if (operation .compareTo (Args .OP_ALG_ECC_PERFORMANCE ) == 0 ) {
280
+ selectedTerminal = selectTargetReader (cmdArgs );
281
+ if (selectedTerminal != null ) {
282
+ Map <String , String > testResults = testingPerformance .testECCPerformance (args , true , selectedTerminal , cmdArgs );
283
+ allResultsMap .put (operation , testResults );
284
+ }
285
+ }
286
+ else if (operation .compareTo (Args .OP_ALG_FINGERPRINT ) == 0 ) {
287
+ selectedTerminal = selectTargetReader (cmdArgs );
288
+ if (selectedTerminal != null ) {
289
+ Map <String , String > testResults = testingPerformance .testPerformanceFingerprint (args , selectedTerminal , cmdArgs );
290
+ allResultsMap .put (operation , testResults );
234
291
}
235
292
}
236
293
else {
@@ -241,7 +298,7 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 ||
241
298
}
242
299
else {
243
300
// Interactive mode of tool
244
- m_SystemOutLogger .println ("Running in interactive mode. Run 'java -jar AlgTestJClient.jar -help' to obtain list of supported arguments." );
301
+ m_SystemOutLogger .println ("Running in interactive mode. Run 'java -jar AlgTestJClient.jar -- help' to obtain list of supported arguments." );
245
302
m_SystemOutLogger .println ("CHOOSE test you want to run:" );
246
303
m_SystemOutLogger .println ("1 -> SUPPORTED ALGORITHMS\n List all supported JC API algorithms (2-10 minutes)\n " +
247
304
"2 -> PERFORMANCE TEST\n Test all JC API methods with 256B data length (1-3 hours)\n " +
@@ -297,6 +354,10 @@ else if (operation.compareTo(Args.OP_ALG_PERFORMANCE_STATIC) == 0 ||
297
354
}
298
355
}
299
356
printSendRequest ();
357
+
358
+ if (cmdArgs .selftest ) {
359
+ checkSelfTestResults (allResultsMap );
360
+ }
300
361
}
301
362
302
363
static long getStartTime () {
@@ -312,8 +373,9 @@ static void printSendRequest() {
312
373
System .out .println ("available to all JavaCard enthusiasts at http://jcalgtest.org." );
313
374
System .out .println ("The results are important even if a card of same type is already in database." );
314
375
System .out .println ("Send *.log and *.csv files from the current directory to <petr@svenda.com>." );
315
- System .out .println ("Thank you very much!" );
316
- System .out .println ("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*" );
376
+ System .out .println ("ESPECIALLY if testing fails, please let us know so we can fix it for you and others." );
377
+ System .out .println ("Thank you very much." );
378
+ System .out .println ("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\n " );
317
379
}
318
380
319
381
static void performKeyHarvest (Args cmdArgs ) throws CardException {
@@ -444,8 +506,10 @@ static CardTerminal selectTargetReader(Args cmdArgs) {
444
506
m_SystemOutLogger .println ("\n Available readers:" );
445
507
for (CardTerminal terminal : terminalList ) {
446
508
Card card ;
509
+ String protocol = System .getenv ().getOrDefault ("ALGTEST_PROTO" , "*" );
447
510
try {
448
- card = terminal .connect ("*" );
511
+ card = terminal .connect (protocol );
512
+ //card = terminal.connect("*");
449
513
ATR atr = card .getATR ();
450
514
m_SystemOutLogger .println (String .format ("%d : [*] %s - %s" , terminalIndex , terminal .getName (), CardMngr .bytesToHex (atr .getBytes ())));
451
515
terminalIndex ++;
@@ -470,4 +534,73 @@ static CardTerminal selectTargetReader(Args cmdArgs) {
470
534
}
471
535
}
472
536
537
+ private static boolean checkFileExistence (String fileName ) {
538
+ File file = new File (fileName );
539
+ if (file .exists ()) {
540
+ m_SystemOutLogger .println (String .format (" OK: the file '%s' exists." , fileName ));
541
+ } else {
542
+ m_SystemOutLogger .println (String .format (" ERROR: the file '%s' does not exist." , fileName ));
543
+ }
544
+ return file .exists ();
545
+ }
546
+
547
+ private static boolean checkExpectedValue (Map <String , Map <String , String >> allResults , String op , String key , String expectedValue ) {
548
+ if (allResults .get (op ).get (key ).equalsIgnoreCase (expectedValue )){
549
+ m_SystemOutLogger .println (String .format (" OK: %s->%s = %s matches." , op , key , expectedValue ));
550
+ } else {
551
+ m_SystemOutLogger .println (String .format (" ERROR: %s->%s = %s mismatch (expected=%s)." , op , key , allResults .get (op ).get (key ), expectedValue ));
552
+ }
553
+ return allResults .get (op ).get (key ).equalsIgnoreCase (expectedValue );
554
+ }
555
+
556
+ public static boolean checkSelfTestResults (Map <String , Map <String , String >> allResults ) {
557
+ boolean bSelftestSuccess = true ;
558
+ // Print all collected info keys
559
+ m_SystemOutLogger .println ("###### SELFTEST ####################################" );
560
+ m_SystemOutLogger .println ("All collected selftest results:" );
561
+ for (String operation : allResults .keySet ()) {
562
+ m_SystemOutLogger .println (String .format (" %s:" , operation ));
563
+ Map <String , String > oneOpResults = allResults .get (operation );
564
+ for (String key : oneOpResults .keySet ()) {
565
+ m_SystemOutLogger .println (String .format (" %s = %s" , key , oneOpResults .get (key )));
566
+ }
567
+ }
568
+
569
+ // Check existence of output files for separate operations
570
+ m_SystemOutLogger .println ("\n Selftest tests finished, now checking results..." );
571
+ for (String op : allResults .keySet ()) {
572
+ m_SystemOutLogger .println (String .format (" Checking operation '%s':" , op ));
573
+ // Always check existence of output file
574
+ if (!checkFileExistence (allResults .get (op ).get ("out_file_name" ))) { bSelftestSuccess = false ; }
575
+ // Check selected values for selected results
576
+ if (op .equals (Args .OP_ALG_PERFORMANCE_STATIC )) {
577
+ if (!checkExpectedValue (allResults , op , "NO_SUCH_ALGORITHM" , "290" )) { bSelftestSuccess = false ; }
578
+ if (!checkExpectedValue (allResults , op , "CANT_BE_MEASURED" , "204" )) { bSelftestSuccess = false ; }
579
+ if (!checkExpectedValue (allResults , op , "ILLEGAL_VALUE" , "66" )) { bSelftestSuccess = false ; }
580
+ if (!checkExpectedValue (allResults , op , "errors_observed" , "560" )) { bSelftestSuccess = false ; }
581
+ }
582
+ if (op .equals (Args .OP_ALG_PERFORMANCE_VARIABLE )) {
583
+ if (!checkExpectedValue (allResults , op , "NO_SUCH_ALGORITHM" , "145" )) { bSelftestSuccess = false ; }
584
+ if (!checkExpectedValue (allResults , op , "CANT_BE_MEASURED" , "327" )) { bSelftestSuccess = false ; }
585
+ if (!checkExpectedValue (allResults , op , "ILLEGAL_VALUE" , "35" )) { bSelftestSuccess = false ; }
586
+ if (!checkExpectedValue (allResults , op , "errors_observed" , "507" )) { bSelftestSuccess = false ; }
587
+ }
588
+ if (op .equals (Args .OP_ALG_FINGERPRINT )) {
589
+ if (!checkExpectedValue (allResults , op , "NO_SUCH_ALGORITHM" , "1" )) { bSelftestSuccess = false ; }
590
+ if (!checkExpectedValue (allResults , op , "CANT_BE_MEASURED" , "18" )) { bSelftestSuccess = false ; }
591
+ if (!checkExpectedValue (allResults , op , "ILLEGAL_VALUE" , "8" )) { bSelftestSuccess = false ; }
592
+ if (!checkExpectedValue (allResults , op , "errors_observed" , "27" )) { bSelftestSuccess = false ; }
593
+ }
594
+ if (op .equals (Args .OP_ALG_ECC_PERFORMANCE )) {
595
+ if (!checkExpectedValue (allResults , op , "errors_observed" , "0" )) { bSelftestSuccess = false ; }
596
+ }
597
+ }
598
+ if (!bSelftestSuccess ) {
599
+ m_SystemOutLogger .println ("ERROR: some test(s) failed" );
600
+ }
601
+ m_SystemOutLogger .println ("###### END SELFTEST ####################################" );
602
+
603
+ return bSelftestSuccess ;
604
+ }
605
+
473
606
}
0 commit comments