ECTester

Build status Build status GitHub release license

Tests support and behavior of elliptic curve cryptography implementations on JavaCards (TYPE_EC_FP and TYPE_EC_F2M) and on selected software libraries. See our github for more info.


JavaCard Elliptic curve algorithm support#

The JavaCard API has support for basic Elliptic Curve Cryptography, such as ECDH and ECDSA. However not many cards actually support these algorithms. The table below displays support and performance obtained by ECTester for common curve sizes. For detailed support and implementation tests see test runs.

Legend

ECDH types
  1. ALG_EC_SVDP_DH
  2. ALG_EC_SVDP_DHC
  3. ALG_EC_SVDP_DH_PLAIN
  4. ALG_EC_SVDP_DHC_PLAIN
  5. ALG_EC_PACE_GM
  6. ALG_EC_SVDP_DH_PLAIN_XY
ECDSA types
  1. ALG_ECDSA_SHA
  2. ALG_ECDSA_SHA_224
  3. ALG_ECDSA_SHA_256
  4. ALG_ECDSA_SHA_384
  5. ALG_ECDSA_SHA_512
Colors

Card list

This page contains results for the following cards:

$ \mathbb{F}_p $ support

Card 192b 256b 384b 521b
ECDH ECDSA ECDH ECDSA ECDH ECDSA ECDH ECDSA
ACS ACOSJ 40K 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e
Athena IDProtect 1,2,3,4 a,b,c 1,2,3,4 a,b,c 1,2,3,4 a,b,c 1,2,3,4 a,b,c
Feitian A22CR
G&D SmartCafe 6.0 1,2,3,4 a,b,c,d,e 1,2,4,3 a,b,c,d,e
G&D SmartCafe 7.0 1,2,3,4 a,b,c,d,e 1,2,4,3 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e
Infineon CJTOP 80k 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e
Infineon SLE78 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e
NXP JCOP31 v2.4.1 1,2 a 1,2 a
NXP JCOP CJ2A081 1,2 a 1,2 a
NXP JCOP v2.4.2 R2 1,3 a,b,c 1,3 a,b,c
NXP JCOP v2.4.2 R3 1,3 a,b,c 1,3 a,b,c
TaiSYS SIMoME VAULT 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e 1,2,3,4 a,b,c,d,e

$ \mathbb{F}_p $ performance

The following table shows performance of tested cards in ECDH and ECDSA over popular $ \mathbb{F}_p $ curve sizes. Key generation performance is similar to ECDH performance. ECDSA timings are split for sign+verify operations. Times are in milliseconds.
Card Type 192b 256b 384b 521b
ECDH ECDSA ECDH ECDSA ECDH ECDSA ECDH ECDSA
ACS ACOSJ 40K
1a 172 254+257 209 311+315 360 503+536
2b 172 255+256 209 311+316 360 505+535
3c 172 254+257 209 311+315 360 505+537
4d 172 255+261 210 310+316 360 505+537
5e 255+260 311+315 505+538
6
Athena IDProtect
1a 147 110+163 209 148+228 448 279+473 937 537+970
2b 147 113+167 209 150+230 448 281+477 938 540+973
3c 148 114+165 209 150+231 448 281+475 937 540+972
4d 146 209 448 938
5e
6
Feitian A22CR
1a
2b
3c
4d
5e
6
G&D SmartCafe 6.0
1a 128 110+135 192 145+197
2b 128 122+147 193 158+210
3c 126 123+147 190 158+209
4d 126 127+152 191 162+214
5e 127+152 162+214
6
G&D SmartCafe 7.0
1a 67 69+80 94 85+108 161 123+176 254 174+273
2b 67 71+82 94 87+111 161 128+180 255 177+275
3c 66 71+83 93 88+110 160 126+180 253 175+275
4d 66 72+83 93 87+111 161 126+180 253 177+276
5e 72+83 88+111 126+180 178+276
6
Infineon CJTOP 80k
1a 138 144+113 167 175+138 240 254+202
2b 208 151+120 267 183+144 414 262+207
3c 207 151+121 263 182+145 408 261+207
4d 205 176+145 264 207+169 408 286+232
5e 175+145 208+171 287+233
6
Infineon SLE78
1a 83 170+201 109 226+275 177 367+467 315 650+806
2b 83 188+220 109 243+293 177 384+483 315 667+827
3c 79 188+219 105 243+293 173 384+482 308 667+826
4d 79 208+240 105 263+313 173 405+504 308 688+846
5e 208+241 264+314 405+503 688+847
6
NXP JCOP31 v2.4.1
1a 122 140+167 190 192+260
2b 123 191
3c
4d
5e
6
NXP JCOP CJ2A081
1a 76 93+107 124 129+168
2b 76 124
3c
4d
5e
6
NXP JCOP v2.4.2 R3
1a 101 111+111 154 151+172
2b 96 114+113 154+178
3c 114+114 154+176
4d
5e
6
TaiSYS SIMoME VAULT
1a 109 217+288 132 267+352 202 439+585 340 935+1220
2b 108 211+282 135 251+340 201 443+590 346 922+1201
3c 105 226+293 130 271+356 198 460+586 341 923+1202
4d 106 222+289 125 259+348 198 433+579 341 913+1202
5e 221+282 261+349 447+576 912+1200
6

$ \mathbb{F}_p $ default curves

The JavaCard API allows cards to specify default curves to be used when generating EC keys using the KeyPair class. Grey background shows that no default curve is present and one should be specified after creating the keypair, see the implementation guide.
Card112b128b160b192b224b256b384b521b
Athena IDProtect
Feitian A22 CRsecp112r1secp128r1secp160r1P-192
secp192r1
P-224
secp224r1
SMP256V1
FeitianFeitian A22
G&D Smartcafe 6.0
G&D Smartcafe 7.0
Infineon CJTOP 80kbrainpoolP160r1brainpoolP192rbrainpoolP224r1brainpoolP256r1
Infineon SLE78brainpoolP256r1
NXP JCOP31 v2.4.1secp128r1secp160r1P-192
secp192r1
NXP JCOP CJ2A081secp128r1secp160r1P-192
secp192r1
NXP JCOP v2.4.2 R2
NXP JCOP v2.4.2 R3
NXP JCOP v2.4.2 R3 J2E145G
TaiSYS SIMoME VAULTsecp112r1secp128r1secp160r1secp192r1secp224r1secp256r1

$ \mathbb{F}_{2^m} $

Support for binary field curves on cards is very weak, very little cards have any. For more information see JCAlgTest support table.

Implementation guide#

A basic example of EC KeyPair generation is visible below, for a more complete example see ECExample.java.
    
    // secp256r1 from http://www.secg.org/sec2-v2.pdf
    byte[] EC256_FP_P = new byte[]{
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
    byte[] EC256_FP_A = new byte[]{
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC};
    byte[] EC256_FP_B = new byte[]{
            (byte) 0x5A, (byte) 0xC6, (byte) 0x35, (byte) 0xD8, (byte) 0xAA, (byte) 0x3A, (byte) 0x93, (byte) 0xE7,
            (byte) 0xB3, (byte) 0xEB, (byte) 0xBD, (byte) 0x55, (byte) 0x76, (byte) 0x98, (byte) 0x86, (byte) 0xBC,
            (byte) 0x65, (byte) 0x1D, (byte) 0x06, (byte) 0xB0, (byte) 0xCC, (byte) 0x53, (byte) 0xB0, (byte) 0xF6,
            (byte) 0x3B, (byte) 0xCE, (byte) 0x3C, (byte) 0x3E, (byte) 0x27, (byte) 0xD2, (byte) 0x60, (byte) 0x4B};
    byte[] EC256_FP_G = new byte[]{
            (byte) 0x04,
            (byte) 0x6B, (byte) 0x17, (byte) 0xD1, (byte) 0xF2, (byte) 0xE1, (byte) 0x2C, (byte) 0x42, (byte) 0x47,
            (byte) 0xF8, (byte) 0xBC, (byte) 0xE6, (byte) 0xE5, (byte) 0x63, (byte) 0xA4, (byte) 0x40, (byte) 0xF2,
            (byte) 0x77, (byte) 0x03, (byte) 0x7D, (byte) 0x81, (byte) 0x2D, (byte) 0xEB, (byte) 0x33, (byte) 0xA0,
            (byte) 0xF4, (byte) 0xA1, (byte) 0x39, (byte) 0x45, (byte) 0xD8, (byte) 0x98, (byte) 0xC2, (byte) 0x96,
            (byte) 0x4F, (byte) 0xE3, (byte) 0x42, (byte) 0xE2, (byte) 0xFE, (byte) 0x1A, (byte) 0x7F, (byte) 0x9B,
            (byte) 0x8E, (byte) 0xE7, (byte) 0xEB, (byte) 0x4A, (byte) 0x7C, (byte) 0x0F, (byte) 0x9E, (byte) 0x16,
            (byte) 0x2B, (byte) 0xCE, (byte) 0x33, (byte) 0x57, (byte) 0x6B, (byte) 0x31, (byte) 0x5E, (byte) 0xCE,
            (byte) 0xCB, (byte) 0xB6, (byte) 0x40, (byte) 0x68, (byte) 0x37, (byte) 0xBF, (byte) 0x51, (byte) 0xF5};
    byte[] EC256_FP_R = new byte[]{
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
            (byte) 0xBC, (byte) 0xE6, (byte) 0xFA, (byte) 0xAD, (byte) 0xA7, (byte) 0x17, (byte) 0x9E, (byte) 0x84,
            (byte) 0xF3, (byte) 0xB9, (byte) 0xCA, (byte) 0xC2, (byte) 0xFC, (byte) 0x63, (byte) 0x25, (byte) 0x51};
    short EC256_FP_K = 1;

    // 1. Allocate the KeyPair object.
    // ! This should be done in the Applet constructor !
    KeyPair example = new KeyPair(KeyPair.ALG_EC_FP, (short) 256);

    // 2. If the key parts are not available, call genKeyPair.
    if (example.getPrivate() == null || example.getPublic() == null) {
        // Sometimes cards require this so we have the keyparts, to
        // set parameters on.
        try {
            example.genKeyPair();
        } catch (Exception ignored) {}
    }

    // 3. Get the key parts and set custom domain parameters on them.
    ECPrivateKey priv = (ECPrivateKey) example.getPrivate();
    ECPublicKey pub = (ECPublicKey) example.getPublic();

    priv.setFieldFP(EC256_FP_P, (short) 0, EC256_FP_P.length);
    pub.setFieldFP(EC256_FP_P, (short) 0, EC256_FP_P.length);

    priv.setA(EC256_FP_A, (short) 0, EC256_FP_A.length);
    pub.setA(EC256_FP_A, (short) 0, EC256_FP_A.length);

    priv.setB(EC256_FP_B, (short) 0, EC256_FP_B.length);
    pub.setB(EC256_FP_B, (short) 0, EC256_FP_B.length);

    priv.setG(EC256_FP_G, (short) 0, EC256_FP_G.length);
    pub.set(EC256_FP_G, (short) 0, EC256_FP_G.length);

    priv.setR(EC256_FP_R, (short) 0, EC256_FP_R.length);
    pub.setR(EC256_FP_R, (short) 0, EC256_FP_R.length);

    priv.setK(EC256_FP_K);
    pub.setK(EC256_FP_K);

    // 4. Generate the KeyPair over the custom set domain parameters.
    example.genKeyPair();
    // Now, the example keypair is ready for use.
    

Common JavaCard ECC usage pitfalls

The JavaCard ECC API is quite general in its requirements for implementations, which means different cards can behave differently and cause errors.

No curve is set by default

KeyPairs allocated with new KeyPair(type, size) might or might not have set some default domain parameters. Which means using keypair.genKeyPair() just after allocating a KeyPair object will probably result in an exception. Thus, it is always better to explicitly setup custom domain parameters, using a known/standard curve, before trying to generate the KeyPair.

genKeyPair() required to get key parts

On some cards a newly allocated KeyPair does not yet contain the individual key parts (the ECPublicKey and ECPrivateKey). Thus doing keypair.getPrivate() or keypair.getPublic() will return null. Which makes setting custom domain parameters on the key parts harder. This can usually be fixed by calling keypair.genKeyPair(), which however might throw an exception, and then setting the custom domain parameters on the now accessible key parts.

clearKey() behaviour

The keypair.clearKey() method might clear out the set domain parameters of the keypair as well as the key contents.

getK() behaviour

The ECKey.getK() method might throw an exception if the card does not support working with the cofactor value.

Test suite runs#

The results of various test suites, run on a set of cards are available below:
Card name
Default
Test vectors
Athena IDProtect
Feitian A22
Feitian A22CR
G&D Smartcafe 6.0
G&D Smartcafe 7.0
Infineon CJTOP
Infineon SLE78
JCardSim
NXP JCOP31 v2.4.1
NXP JCOP41 v2.3.1 72k
NXP JCOP CJ2A081
NXP JCOP v2.4.2 R2
NXP JCOP v2.4.2 R3
NXP JCOP v2.4.2 R3 J2E145G
TaiSYS SIMoME VAULT

Docs#