diff options
Diffstat (limited to 'src/applets')
| -rw-r--r-- | src/applets/EC_Consts.java | 184 | ||||
| -rw-r--r-- | src/applets/SimpleECCApplet.java | 351 |
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); + } +} + |
