Skip to content

Profiler for JavaCard code and a rewrite of OpenCryptoProject/JCProfiler with easier usage and much more!

License

Notifications You must be signed in to change notification settings

lzaoral/JCProfilerNext

Repository files navigation

JCProfilerNext

Java CI with Gradle

JCProfilerNext is a complete rewrite of OpenCryptoProject/JCProfiler that provides a completely automated preprocessing, compilation, installation and profiling of JavaCard code on JavaCard smart cards or in the jCardSim simulator.

Prerequisites

  • Install JDK 8 or newer.

  • Obtain a copy of the JavaCard Development Kit, e.g. from this GitHub archive maintained by Martin Paljak.

Table 1. Compatibility Matrix
JDK Supported JavaCard versions

8

2.2.1+

9-11

3.0.1+

12-19

3.1+

20+

none

Compilation

  1. Clone this repository.

  2. Run ./gradlew build on Unix-like systems or gradlew.bat build on Windows.

  3. Execute

    1. directly using Gradle: ./gradlew run --args='--help'.

    2. directly using built JAR: java -jar build/libs/JCProfilerNext-1.0-SNAPSHOT.jar --help.

    3. directly from distribution archives in build/distributions.

Execution modes

The tool can be executed in four different modes (select with --mode):

  • custom — Instrument the applet with user-provided code snippets. The user has to do the measurements on their own.

  • memory — Measure memory usage.

  • time (default) — Measure elapsed time.

  • stats — Collect API usage statistics.

Time Example

Consider the example method in the following class. The outer loop is clearly not constant since its iteration count depends on the input value. On the other hand, the inner loop is constant.

package example;

import javacard.framework.*;

public class Example extends Applet {
    public static final byte INS_EXAMPLE = (byte) 0xEE;

    Example() { }

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new Example().register();
    }

    @Override
    public void process(APDU apdu) throws ISOException {
        if (selectingApplet())
            return;

        switch (apdu.getBuffer()[ISO7816.OFFSET_INS]) {
            case INS_EXAMPLE:
                example(apdu);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    private void example(APDU apdu) {
        short count = Util.getShort(apdu.getBuffer(), ISO7816.OFFSET_CDATA);
        for (short i = 0; i < count; i++) {
            short tmp = 0;
            for (short k = 0; k < 50; k++) {
                tmp++;
            }
        }
    }
}

Run as:

$ ./gradlew run --args="--work-dir example --jckit jc222_kit --executable example --ins 0xEE --data-regex 00[0-9A-F]{2} --repeat-count 100"

JCProfilerNext will process all sources in the example directory and will also use this directory to store all intermediate results:

  • applet - contains the built applet with corresponding CAP, JAR and JCA files

  • measurements.csv - contains the profiled method signature, card ATR, elapsed time, input APDUs and corresponding raw measurements

  • measurements.html - contains a visualisation of the measurements

  • sources_instr - contains instrumented sources

  • sources_original - contains original unchanged sources

  • sources_perf - contains sources with inserted measurements as inline comments

If you open the corresponding measurements.html produced by JCProfilerNext, you will see that some parts of the code are indeed not constant, namely if you inspect the corresponding histograms of traps after the for loops.

Memory Example

Consider the following source code:

package example;

import javacard.framework.*;

public class Example extends Applet {

    private Example() {
        // Transient Deselect
        byte[] transientDeselect = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_DESELECT);

        // Transient Reset
        byte[] transientReset = JCSystem.makeTransientByteArray((short) 256, JCSystem.CLEAR_ON_RESET);

        // Persistent
        byte[] persistent = new byte[256];
    }

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new Example().register();
    }

    @Override
    public void process(APDU apdu) {}
}

Run as:

$ ./gradlew run --args="--work-dir example --jckit jc304_kit --mode memory"

JCProfilerNext will produce the same directory structure as in the time mode above. The --executable option is omitted because we want to measure memory usage in the entry point class constructor. Note that the allocation of transient deselect memory may also affect the amount of free transient memory and vice versa. See measurements.html for visualisation of the measurements.

Stats Example

Consider the following source code:

import javacard.security.KeyPair;

class Example {
    public Example() {
        KeyPair kp = new KeyPair(KeyPair.ALG_RSA, (short) 2048);
        kp.genKeyPair();
    }
}

Run as:

$ ./gradlew run --args="--work-dir example --jckit jc222_kit --mode stats"

JCProfilerNext will process all sources in the example directory and produce the APIstatistics.csv file. Note that if not all imports can be resolved, the results may not be precise, and the tool will issue an appropriate warning.

# package/outer type,type,member,frequency
javacard.security,KeyPair,,2
javacard.security,KeyPair,ALG_RSA,1
javacard.security,KeyPair,genKeyPair(),1
javacard.security,KeyPair,"KeyPair(byte,short)",1

Limitations

  • Cards that require special communication procedures (e.g. SecureChannel) are not supported.

  • It is not possible to use a different JDK to compile the JavaCard applets and run this project.

  • Connection to wireless card terminals may occasionally fail.

About

Profiler for JavaCard code and a rewrite of OpenCryptoProject/JCProfiler with easier usage and much more!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published