aboutsummaryrefslogtreecommitdiff
path: root/src/applets/SimpleECCApplet.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/applets/SimpleECCApplet.java')
-rw-r--r--src/applets/SimpleECCApplet.java394
1 files changed, 287 insertions, 107 deletions
diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java
index 325d834..ab6eede 100644
--- a/src/applets/SimpleECCApplet.java
+++ b/src/applets/SimpleECCApplet.java
@@ -16,9 +16,13 @@ public class SimpleECCApplet extends javacard.framework.Applet
// 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 byte INS_TESTECSUPPORTALL = (byte) 0x5e;
+
+
final static short ARRAY_LENGTH = (short) 0xff;
final static byte AES_BLOCK_LENGTH = (short) 0x16;
@@ -26,6 +30,16 @@ public class SimpleECCApplet extends javacard.framework.Applet
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 final static byte ECTEST_SEPARATOR = (byte) 0xff;
+ public final static byte ECTEST_ALLOCATE_KEYPAIR = (byte) 0xc1;
+ public final static byte ECTEST_GENERATE_KEYPAIR_DEFCURVE = (byte) 0xc2;
+ public final static byte ECTEST_SET_VALIDCURVE = (byte) 0xc3;
+ public final static byte ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE = (byte) 0xc4;
+ public final static byte ECTEST_SET_INVALIDCURVE = (byte) 0xc5;
+ public final static byte ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE = (byte) 0xc6;
+
+ public final static short SW_SKIPPED = (short) 0x0ee1;
/*
public static final byte[] EC192_FP_PUBLICW = new byte[]{
(byte) 0x04, (byte) 0xC9, (byte) 0xC0, (byte) 0xED, (byte) 0xFB, (byte) 0x27,
@@ -118,6 +132,9 @@ public class SimpleECCApplet extends javacard.framework.Applet
if (apduBuffer[ISO7816.OFFSET_CLA] == CLA_SIMPLEECCAPPLET) {
switch ( apduBuffer[ISO7816.OFFSET_INS] ) {
+ case INS_TESTECSUPPORTALL:
+ TestECSupportAllLengths(apdu);
+ break;
case INS_ALLOCATEKEYPAIR:
AllocateKeyPairReturnDefCourve(apdu);
break;
@@ -141,6 +158,274 @@ public class SimpleECCApplet extends javacard.framework.Applet
else ISOException.throwIt( ISO7816.SW_CLA_NOT_SUPPORTED);
}
+
+ 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.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, 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);
+ }
+ }
+
+
+
+ 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 (valid for for 192 only)
+ 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);
+ }
+
+ short TestECSupport(byte keyClass, short keyLen, byte[] buffer, short bufferOffset) {
+ short baseOffset = bufferOffset;
+
+ ecKeyPair = null;
+ ecPubKey = null;
+ ecPrivKey = null;
+
+ buffer[bufferOffset] = ECTEST_SEPARATOR; bufferOffset++;
+ buffer[bufferOffset] = keyClass; bufferOffset++;
+ Util.setShort(buffer, bufferOffset, keyLen); bufferOffset += 2;
+ //
+ // 1. Allocate KeyPair object
+ //
+ buffer[bufferOffset] = ECTEST_ALLOCATE_KEYPAIR; bufferOffset++;
+ try {
+ ecKeyPair = new KeyPair(keyClass, keyLen);
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); bufferOffset += 2;
+ }
+ catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason()); bufferOffset += 2;
+ }
+ catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+
+ //
+ // 2. Test keypair generation without explicit curve (=> default curve preset)
+ //
+ buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_DEFCURVE; bufferOffset++;
+ try {
+ ecKeyPair.genKeyPair();
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
+ bufferOffset += 2;
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ }
+ catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+
+ //
+ // 3. Set valid custom curve
+ //
+ buffer[bufferOffset] = ECTEST_SET_VALIDCURVE;
+ bufferOffset++;
+ boolean bGenerateKey = false;
+ try {
+ 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 intentionally nothing
+
+ // Initialize curve parameters
+ EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray);
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
+ bufferOffset += 2;
+
+ bGenerateKey = true;
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ }
+ catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+
+ //
+ // 4. Generate keypair with custom curve
+ //
+ buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE;
+ bufferOffset++;
+ if (bGenerateKey) {
+ try {
+ ecKeyPair.genKeyPair();
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
+ bufferOffset += 2;
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ } catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+ }
+ else {
+ Util.setShort(buffer, bufferOffset, SW_SKIPPED);
+ bufferOffset += 2;
+ }
+ //
+ // 5. Set invalid custom curve
+ //
+ buffer[bufferOffset] = ECTEST_SET_INVALIDCURVE;
+ bufferOffset++;
+ bGenerateKey = false;
+ try {
+ // Initialize curve parameters
+ EC_Consts.setInValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray);
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
+ bufferOffset += 2;
+ bGenerateKey = true;
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ } catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+
+ //
+ // 6. Generate keypair with invalid custom curve
+ //
+ buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE;
+ bufferOffset++;
+ if (bGenerateKey) {
+ try {
+ ecKeyPair.genKeyPair();
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR);
+ bufferOffset += 2;
+ } catch (CryptoException e) {
+ Util.setShort(buffer, bufferOffset, e.getReason());
+ bufferOffset += 2;
+ } catch (Exception e) {
+ Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN);
+ bufferOffset += 2;
+ }
+ } else {
+ Util.setShort(buffer, bufferOffset, SW_SKIPPED);
+ bufferOffset += 2;
+ }
+
+ return (short) (bufferOffset - baseOffset);
+ }
+ void TestECSupportAllLengths(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+ short len = apdu.setIncomingAndReceive();
+
+ short dataOffset = 0;
+ // FP -
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 128, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 160, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 192, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 224, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 256, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 384, apdubuf, dataOffset);
+ dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 521, apdubuf, dataOffset);
+
+ apdu.setOutgoingAndSend((short) 0, dataOffset);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
void AllocateKeyPair(byte algorithm, short bitLen) {
// Select proper attributes
switch (bitLen) {
@@ -185,7 +470,7 @@ public class SimpleECCApplet extends javacard.framework.Applet
ecPubKey = (ECPublicKey) ecKeyPair.getPublic();
ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate();
// Set required EC parameters
- EC_Consts.setECKeyParams(ecPubKey, ecPrivKey, bitLen, m_ramArray);
+ EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, bitLen, m_ramArray);
}
short TryAllocateKeyPair(byte algorithm, short bitLen, byte[] buffer, short offset) {
@@ -215,114 +500,9 @@ public class SimpleECCApplet extends javacard.framework.Applet
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) {