aboutsummaryrefslogtreecommitdiff
path: root/src/applets
diff options
context:
space:
mode:
Diffstat (limited to 'src/applets')
-rw-r--r--src/applets/EC_Consts.java184
-rw-r--r--src/applets/SimpleECCApplet.java351
2 files changed, 535 insertions, 0 deletions
diff --git a/src/applets/EC_Consts.java b/src/applets/EC_Consts.java
new file mode 100644
index 0000000..7923c91
--- /dev/null
+++ b/src/applets/EC_Consts.java
@@ -0,0 +1,184 @@
+/**
+ *
+ */
+package applets;
+
+import javacard.framework.ISOException;
+import javacard.framework.Util;
+import javacard.security.ECPrivateKey;
+import javacard.security.ECPublicKey;
+import javacard.security.KeyBuilder;
+
+public class EC_Consts {
+ public static byte[] EC_FP_P = null;
+ public static byte[] EC_FP_A = null;
+ public static byte[] EC_FP_B = null;
+ public static byte[] EC_FP_G_X = null;
+ public static byte[] EC_FP_G_Y = null;
+ public static byte[] EC_FP_R = null;
+ public static short EC_FP_K = 1;
+
+ // secp192r1 from http://www.secg.org/sec2-v2.pdf
+ public static final byte[] EC192_FP_P = new byte[]{
+ (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) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
+ public static final byte[] EC192_FP_A = new byte[]{
+ (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) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC};
+ public static final byte[] EC192_FP_B = new byte[]{
+ (byte) 0x64, (byte) 0x21, (byte) 0x05, (byte) 0x19,
+ (byte) 0xE5, (byte) 0x9C, (byte) 0x80, (byte) 0xE7,
+ (byte) 0x0F, (byte) 0xA7, (byte) 0xE9, (byte) 0xAB,
+ (byte) 0x72, (byte) 0x24, (byte) 0x30, (byte) 0x49,
+ (byte) 0xFE, (byte) 0xB8, (byte) 0xDE, (byte) 0xEC,
+ (byte) 0xC1, (byte) 0x46, (byte) 0xB9, (byte) 0xB1};
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC192_FP_G_X = new byte[]{
+ (byte) 0x18, (byte) 0x8D, (byte) 0xA8, (byte) 0x0E,
+ (byte) 0xB0, (byte) 0x30, (byte) 0x90, (byte) 0xF6,
+ (byte) 0x7C, (byte) 0xBF, (byte) 0x20, (byte) 0xEB,
+ (byte) 0x43, (byte) 0xA1, (byte) 0x88, (byte) 0x00,
+ (byte) 0xF4, (byte) 0xFF, (byte) 0x0A, (byte) 0xFD,
+ (byte) 0x82, (byte) 0xFF, (byte) 0x10, (byte) 0x12};
+ // second part of G uncompressed
+ public static final byte[] EC192_FP_G_Y = new byte[]{
+ (byte) 0x07, (byte) 0x19, (byte) 0x2B, (byte) 0x95,
+ (byte) 0xFF, (byte) 0xC8, (byte) 0xDA, (byte) 0x78,
+ (byte) 0x63, (byte) 0x10, (byte) 0x11, (byte) 0xED,
+ (byte) 0x6B, (byte) 0x24, (byte) 0xCD, (byte) 0xD5,
+ (byte) 0x73, (byte) 0xF9, (byte) 0x77, (byte) 0xA1,
+ (byte) 0x1E, (byte) 0x79, (byte) 0x48, (byte) 0x11};
+ // Order of G
+ public static final byte[] EC192_FP_R = new byte[]{
+ (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) 0x99, (byte) 0xDE, (byte) 0xF8, (byte) 0x36,
+ (byte) 0x14, (byte) 0x6B, (byte) 0xC9, (byte) 0xB1,
+ (byte) 0xB4, (byte) 0xD2, (byte) 0x28, (byte) 0x31};
+ // cofactor of G
+ public static final short EC192_FP_K = 1;
+
+ // secp256r1 from http://www.secg.org/sec2-v2.pdf
+ public static final 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};
+ public static final 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};
+ public static final 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};
+ // G in compressed form / first part of ucompressed
+ public static final byte[] EC256_FP_G_X = new byte[]{
+ (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};
+ // second part of G uncompressed
+ public static final byte[] EC256_FP_G_Y = new byte[]{
+ (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};
+ // Order of G
+ public static final 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};
+ // cofactor of G
+ public static final short EC256_FP_K = 1;
+
+ // TODO: add parameters for longer lengths
+
+ public static void setECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, short ecLength, byte[] auxBuffer) {
+ // Select proper courve parameters
+ switch (ecLength) {
+ case (short) 192: {
+ EC_FP_P = EC192_FP_P;
+ EC_FP_A = EC192_FP_A;
+ EC_FP_B = EC192_FP_B;
+ EC_FP_G_X = EC192_FP_G_X;
+ EC_FP_G_Y = EC192_FP_G_Y;
+ EC_FP_R = EC192_FP_R;
+ EC_FP_K = EC192_FP_K;
+ break;
+ }
+ case (short) 256: {
+ EC_FP_P = EC256_FP_P;
+ EC_FP_A = EC256_FP_A;
+ EC_FP_B = EC256_FP_B;
+ EC_FP_G_X = EC256_FP_G_X;
+ EC_FP_G_Y = EC256_FP_G_Y;
+ EC_FP_R = EC256_FP_R;
+ EC_FP_K = EC256_FP_K;
+ break;
+ }
+ default: {
+ ISOException.throwIt((short) -1);
+ }
+ }
+ // prepare an ANSI X9.62 uncompressed EC point representation for G
+ short gSize = (short) 1;
+ gSize += (short) EC_FP_G_X.length;
+ gSize += (short) EC_FP_G_Y.length;
+ auxBuffer[0] = 0x04;
+ short off = 1;
+ off = Util.arrayCopy(EC_FP_G_X, (short) 0, auxBuffer, off, (short) EC_FP_G_X.length);
+ Util.arrayCopy(EC_FP_G_Y, (short) 0, auxBuffer, off, (short) EC_FP_G_Y.length);
+
+ // pre-set basic EC parameters:
+ ecPubKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length);
+ ecPubKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length);
+ ecPubKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length);
+ ecPubKey.setG(auxBuffer, (short) 0, gSize);
+ ecPubKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length);
+ ecPubKey.setK(EC_FP_K);
+
+ ecPrivKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length);
+ ecPrivKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length);
+ ecPrivKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length);
+ ecPrivKey.setG(auxBuffer, (short) 0, gSize);
+ ecPrivKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length);
+ ecPrivKey.setK(EC_FP_K);
+ }
+}
diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java
new file mode 100644
index 0000000..325d834
--- /dev/null
+++ b/src/applets/SimpleECCApplet.java
@@ -0,0 +1,351 @@
+/*
+ * PACKAGEID: 4C6162616B417070
+ * APPLETID: 4C6162616B4170706C6574
+ */
+package applets;
+
+import javacard.framework.*;
+import javacard.security.*;
+import javacardx.crypto.*;
+
+public class SimpleECCApplet extends javacard.framework.Applet
+{
+ // MAIN INSTRUCTION CLASS
+ final static byte CLA_SIMPLEECCAPPLET = (byte) 0xB0;
+
+ // INSTRUCTIONS
+ final static byte INS_GENERATEKEY = (byte) 0x5a;
+ final static byte INS_ALLOCATEKEYPAIRS = (byte) 0x5b;
+ final static byte INS_ALLOCATEKEYPAIR = (byte) 0x5c;
+ final static byte INS_DERIVEECDHSECRET = (byte) 0x5d;
+
+
+ final static short ARRAY_LENGTH = (short) 0xff;
+ final static byte AES_BLOCK_LENGTH = (short) 0x16;
+
+ final static short EC_LENGTH_BITS = KeyBuilder.LENGTH_EC_FP_192;
+ //final static short EC_LENGTH_BITS = KeyBuilder.LENGTH_EC_FP_160;
+ //final static short EC_LENGTH_BITS = (short) 256;
+/*
+ public static final byte[] EC192_FP_PUBLICW = new byte[]{
+ (byte) 0x04, (byte) 0xC9, (byte) 0xC0, (byte) 0xED, (byte) 0xFB, (byte) 0x27,
+ (byte) 0xB7, (byte) 0x1E, (byte) 0xBE, (byte) 0x30, (byte) 0x93, (byte) 0xFC,
+ (byte) 0x4F, (byte) 0x33, (byte) 0x76, (byte) 0x38, (byte) 0xCE, (byte) 0xE0,
+ (byte) 0x2F, (byte) 0x78, (byte) 0xF6, (byte) 0x3C, (byte) 0xEA, (byte) 0x90,
+ (byte) 0x22, (byte) 0x61, (byte) 0x32, (byte) 0x8E, (byte) 0x9F, (byte) 0x03,
+ (byte) 0x8A, (byte) 0xFD, (byte) 0x60, (byte) 0xA0, (byte) 0xCE, (byte) 0x01,
+ (byte) 0x9B, (byte) 0x76, (byte) 0x34, (byte) 0x59, (byte) 0x79, (byte) 0x64,
+ (byte) 0xD7, (byte) 0x79, (byte) 0x8E, (byte) 0x3B, (byte) 0x16, (byte) 0xD5,
+ (byte) 0x15};
+ */
+ public static final byte[] EC192_FP_PUBLICW = new byte[]{
+ (byte) 0x04,
+ (byte) 0x9d, (byte) 0x42, (byte) 0x76, (byte) 0x9d, (byte) 0xfd, (byte) 0xbe,
+ (byte) 0x11, (byte) 0x3a, (byte) 0x85, (byte) 0x1b, (byte) 0xb6, (byte) 0xb0,
+ (byte) 0x1b, (byte) 0x1a, (byte) 0x51, (byte) 0x5d, (byte) 0x89, (byte) 0x3b,
+ (byte) 0x5a, (byte) 0xdb, (byte) 0xc1, (byte) 0xf6, (byte) 0x13, (byte) 0x29,
+ (byte) 0x74, (byte) 0x74, (byte) 0x9a, (byte) 0xc0, (byte) 0x96, (byte) 0x7a,
+ (byte) 0x8f, (byte) 0xf4, (byte) 0xcc, (byte) 0x54, (byte) 0xd9, (byte) 0x31,
+ (byte) 0x87, (byte) 0x60, (byte) 0x2d, (byte) 0xd6, (byte) 0x7e, (byte) 0xb3,
+ (byte) 0xd2, (byte) 0x29, (byte) 0x70a, (byte) 0xca, (byte) 0x2ca};
+
+
+ private KeyPair ecKeyPair = null;
+ private KeyPair ecKeyPair128 = null;
+ private KeyPair ecKeyPair160 = null;
+ private KeyPair ecKeyPair192 = null;
+ private KeyPair ecKeyPair256 = null;
+ private ECPublicKey ecPubKey = null;
+ private ECPublicKey ecPubKey128 = null;
+ private ECPublicKey ecPubKey160 = null;
+ private ECPublicKey ecPubKey192 = null;
+ private ECPublicKey ecPubKey256 = null;
+ private ECPrivateKey ecPrivKey = null;
+ private ECPrivateKey ecPrivKey128 = null;
+ private ECPrivateKey ecPrivKey160 = null;
+ private ECPrivateKey ecPrivKey192 = null;
+ private ECPrivateKey ecPrivKey256 = null;
+
+ private KeyAgreement dhKeyAgreement = null;
+
+ // TEMPORARRY ARRAY IN RAM
+ private byte m_ramArray[] = null;
+ // PERSISTENT ARRAY IN EEPROM
+ private byte m_dataArray[] = null;
+
+ protected SimpleECCApplet(byte[] buffer, short offset, byte length) {
+ short dataOffset = offset;
+
+ if(length > 9) {
+ // shift to privilege offset
+ dataOffset += (short)( 1 + buffer[offset]);
+ // finally shift to Application specific offset
+ dataOffset += (short)( 1 + buffer[dataOffset]);
+ // go to proprietary data
+ dataOffset++;
+
+ m_ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET);
+ m_dataArray = new byte[ARRAY_LENGTH];
+ Util.arrayFillNonAtomic(m_dataArray, (short) 0, ARRAY_LENGTH, (byte) 0);
+
+ dhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
+ }
+
+ register();
+ }
+
+ public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException {
+ // applet instance creation
+ new SimpleECCApplet (bArray, bOffset, bLength);
+ }
+
+ public boolean select() {
+ return true;
+ }
+
+ public void deselect() {
+ return;
+ }
+
+ public void process(APDU apdu) throws ISOException
+ {
+ // get the APDU buffer
+ byte[] apduBuffer = apdu.getBuffer();
+
+ // ignore the applet select command dispached to the process
+ if (selectingApplet())
+ return;
+
+ if (apduBuffer[ISO7816.OFFSET_CLA] == CLA_SIMPLEECCAPPLET) {
+ switch ( apduBuffer[ISO7816.OFFSET_INS] ) {
+ case INS_ALLOCATEKEYPAIR:
+ AllocateKeyPairReturnDefCourve(apdu);
+ break;
+ case INS_ALLOCATEKEYPAIRS:
+ AllocateKeyPairs(apdu);
+ break;
+ case INS_GENERATEKEY:
+ GenerateKey(apdu);
+ break;
+ case INS_DERIVEECDHSECRET:
+ DeriveECDHSecret(apdu);
+ break;
+
+ default :
+ // The INS code is not supported by the dispatcher
+ ISOException.throwIt( ISO7816.SW_INS_NOT_SUPPORTED ) ;
+ break ;
+
+ }
+ }
+ else ISOException.throwIt( ISO7816.SW_CLA_NOT_SUPPORTED);
+ }
+
+ void AllocateKeyPair(byte algorithm, short bitLen) {
+ // Select proper attributes
+ switch (bitLen) {
+ case (short) 128: {
+ ecKeyPair = ecKeyPair128;
+ ecKeyPair = ecKeyPair128;
+ ecPrivKey = ecPrivKey128;
+ break;
+ }
+ case (short) 160: {
+ ecKeyPair = ecKeyPair160;
+ ecKeyPair = ecKeyPair160;
+ ecPrivKey = ecPrivKey160;
+ break;
+ }
+ case (short) 192: {
+ ecKeyPair = ecKeyPair192;
+ ecKeyPair = ecKeyPair192;
+ ecPrivKey = ecPrivKey192;
+ break;
+ }
+ case (short) 256: {
+ ecKeyPair = ecKeyPair256;
+ ecKeyPair = ecKeyPair256;
+ ecPrivKey = ecPrivKey256;
+ break;
+ }
+ default: {
+ ISOException.throwIt((short) -1);
+ }
+ }
+
+ // Allocate instance
+ ecKeyPair = new KeyPair(algorithm, bitLen);
+ ecKeyPair.genKeyPair();
+ ecPubKey = (ECPublicKey) ecKeyPair.getPublic();
+ // sometimes null is returned and previous one call to genKeyPair()
+ // is required before we can get public key
+ if (ecPubKey == null) {
+ ecKeyPair.genKeyPair();
+ }
+ ecPubKey = (ECPublicKey) ecKeyPair.getPublic();
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+ // Set required EC parameters
+ EC_Consts.setECKeyParams(ecPubKey, ecPrivKey, bitLen, m_ramArray);
+ }
+
+ short TryAllocateKeyPair(byte algorithm, short bitLen, byte[] buffer, short offset) {
+ // Try allocation, log result
+ try {
+ offset = Util.setShort(buffer, offset, bitLen);
+ AllocateKeyPair(KeyPair.ALG_EC_FP, bitLen);
+ buffer[offset] = 1;
+ offset++;
+ } catch (Exception e) {
+ buffer[offset] = 0;
+ offset++;
+ }
+ return offset;
+ }
+ void AllocateKeyPairs(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ apdu.setIncomingAndReceive();
+
+ short offset = 0;
+
+ //offset = TryAllocateKeyPair(KeyPair.ALG_EC_FP, (short) 128, apdubuf, offset);
+ //offset = TryAllocateKeyPair(KeyPair.ALG_EC_FP, (short) 160, apdubuf, offset);
+ //offset = TryAllocateKeyPair(KeyPair.ALG_EC_FP, (short) 192, apdubuf, offset);
+ //offset = TryAllocateKeyPair(KeyPair.ALG_EC_FP, (short) 256, apdubuf, offset);
+
+ apdu.setOutgoingAndSend((short) 0, offset);
+ }
+
+ void AllocateKeyPairReturnDefCourve(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ apdu.setIncomingAndReceive();
+
+ short bitLen = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA);
+
+ // Note: all locations shoudl happen in constructor. But here it is intentional
+ // as we like to test for result of allocation
+ ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, bitLen);
+
+ // If required, generate also new key pair
+ if (apdubuf[ISO7816.OFFSET_P1] == (byte) 1) {
+ ecPubKey = (ECPublicKey) ecKeyPair.getPublic();
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+ // Some implementation wil not return valid pub key until ecKeyPair.genKeyPair() is called
+ // Other implementation will fail with exception if same is called => try catch
+ try {
+ if (ecPubKey == null) {ecKeyPair.genKeyPair();}
+ }
+ catch (Exception e) {} // do nothing
+
+
+ // If required, initialize curve parameters first
+ if (apdubuf[ISO7816.OFFSET_P2] == (byte) 2) {
+ EC_Consts.setECKeyParams(ecPubKey, ecPrivKey, bitLen, m_ramArray);
+ }
+
+ // Now generate new keypair with either default or custom curve
+ ecKeyPair.genKeyPair();
+ ecPubKey = (ECPublicKey) ecKeyPair.getPublic();
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+
+ short len = 0;
+ short offset = 0;
+
+ // Export curve public parameters
+ offset += 2; // reserve space for length
+ len = ecPubKey.getField(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+ offset += 2; // reserve space for length
+ len = ecPubKey.getA(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+
+ offset += 2; // reserve space for length
+ len = ecPubKey.getB(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+ offset += 2; // reserve space for length
+ len = ecPubKey.getR(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+/*
+ offset += 2; // reserve space for length
+ len = ecPubKey.getW(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+*/
+ apdu.setOutgoingAndSend((short) 0, offset);
+ }
+ }
+
+/**
+ For a first quick test, this would be the workflow:
+ *
+ * 1. Import a given ECC public key (i.e. a point that is not on the curve)
+ *
+ * 2. Generate a fresh ECC keypair
+ *
+ * 3. Perform a ECDH key-derivation with the keys from steps 1 and 2
+ *
+ * 4. Repeat steps 2 & 3 a couple of times and record the generated secrets
+ *
+ *
+ *
+ * If the card is vulnerable, then the generated secrets will repeat. For
+ * example, we have points of order 5. With such a point and a vulnerable
+ * card, there are only 5 (or even less) different possible values for the
+ * generated secrets. This is pretty obvious, if you do a couple of (e.g.
+ * +-10) key-derivations ;)
+ * @param apdu
+ */
+ void DeriveECDHSecret(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ short len = apdu.setIncomingAndReceive();
+
+ // Assumption: proper EC keyPair is already allocated
+
+ // If public key point is provided, then use it
+ if (len == 0) {
+ // if not provided, use build-in one
+ Util.arrayCopyNonAtomic(EC192_FP_PUBLICW, (short) 0, apdubuf, ISO7816.OFFSET_CDATA, (short) EC192_FP_PUBLICW.length);
+ len = (short) EC192_FP_PUBLICW.length;
+ }
+
+ // Generate fresh EC keypair
+ ecKeyPair.genKeyPair();
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+
+ dhKeyAgreement.init(ecPrivKey);
+ short secretLen = 0;
+ // Generate and export secret
+ secretLen = dhKeyAgreement.generateSecret(apdubuf, ISO7816.OFFSET_CDATA, len, m_ramArray, (short) 0);
+ Util.arrayCopyNonAtomic(m_ramArray, (short) 0, apdubuf, (short) 0, secretLen);
+
+ apdu.setOutgoingAndSend((short) 0, secretLen);
+ }
+
+
+ void GenerateKey(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ apdu.setIncomingAndReceive();
+
+ // Assumption: proper EC keyPair is already allocated and initialized
+
+ ecKeyPair.genKeyPair();
+ ecPubKey = (ECPublicKey) ecKeyPair.getPrivate();
+ ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
+
+ short offset = 0;
+ offset += 2; // reserve space for length
+ short len = ecPubKey.getW(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+ offset += 2; // reserve space for length
+ len = ecPrivKey.getS(apdubuf, offset);
+ Util.setShort(apdubuf, (short) (offset - 2), len);
+ offset += len;
+
+ apdu.setOutgoingAndSend((short) 0, offset);
+ }
+}
+