aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/applets/ECKeyGenerator.java179
-rw-r--r--src/applets/ECKeyTester.java180
-rw-r--r--src/applets/EC_Consts.java7
3 files changed, 363 insertions, 3 deletions
diff --git a/src/applets/ECKeyGenerator.java b/src/applets/ECKeyGenerator.java
new file mode 100644
index 0000000..ff2193c
--- /dev/null
+++ b/src/applets/ECKeyGenerator.java
@@ -0,0 +1,179 @@
+package applets;
+
+import javacard.framework.ISO7816;
+import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.ECPrivateKey;
+import javacard.security.ECPublicKey;
+import javacard.security.KeyPair;
+
+/**
+ *
+ */
+public class ECKeyGenerator {
+
+ private KeyPair ecKeyPair = null;
+ private ECPrivateKey ecPrivateKey = null;
+ private ECPublicKey ecPublicKey = null;
+
+ public static final byte PARAMETER_FP = 1;
+ public static final byte PARAMETER_F2M_ONE = 2;
+ public static final byte PARAMETER_F2M_THREE = 3;
+ public static final byte PARAMETER_A = 4;
+ public static final byte PARAMETER_B = 5;
+ public static final byte PARAMETER_G = 6;
+ public static final byte PARAMETER_R = 7;
+ public static final byte PARAMETER_K = 8;
+
+ private static final byte PARAMETER_S = 9; //private key
+ private static final byte PARAMETER_W = 10;//public key
+
+ public static final byte KEY_PUBLIC = 0x1;
+ public static final byte KEY_PRIVATE = 0x2;
+ public static final byte KEY_BOTH = KEY_PUBLIC & KEY_PRIVATE;
+
+ public short allocatePair(byte algorithm, short keyLength) {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecKeyPair = new KeyPair(algorithm, keyLength);
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public boolean isAlocated() {
+ return ecKeyPair != null && ecPrivateKey != null && ecPublicKey != null;
+ }
+
+ public short generatePair() {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecKeyPair.genKeyPair();
+ ecPrivateKey = (ECPrivateKey) ecKeyPair.getPrivate(); //TODO, do I want to keep private and pubkey separate from the keypair?
+ ecPublicKey = (ECPublicKey) ecKeyPair.getPublic();
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public short setCustomCurve(byte keyClass, short keyLength) {
+ //TODO
+ return 0;
+ }
+
+ public short setCustomCurve(byte curve) {
+ //TODO
+ return 0;
+ }
+
+ public short setExternalParameter(byte key, byte param, byte[] data, short offset, short length) {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ switch (param) {
+ case PARAMETER_FP:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldFP(data, offset, length);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldFP(data, offset, length);
+ break;
+ case PARAMETER_F2M_ONE:
+ if (length != 2) {
+ result = ISO7816.SW_UNKNOWN;
+ } else {
+ short i = Util.makeShort(data[offset], data[(short) (offset + 1)]);
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i);
+ }
+ break;
+ case PARAMETER_F2M_THREE:
+ if (length != 6) {
+ result = ISO7816.SW_UNKNOWN;
+ } else {
+ short i1 = Util.makeShort(data[offset], data[(short) (offset + 1)]);
+ short i2 = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]);
+ short i3 = Util.makeShort(data[(short) (offset + 4)], data[(short) (offset + 5)]);
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
+ }
+ break;
+ case PARAMETER_A:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setA(data, offset, length);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setA(data, offset, length);
+ break;
+ case PARAMETER_B:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setB(data, offset, length);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setB(data, offset, length);
+ break;
+ case PARAMETER_G:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setG(data, offset, length);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setG(data, offset, length);
+ break;
+ case PARAMETER_R:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setR(data, offset, length);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setR(data, offset, length);
+ break;
+ case PARAMETER_K:
+ if (length != 2) {
+ result = ISO7816.SW_UNKNOWN;
+ } else {
+ short k = Util.makeShort(data[offset], data[(short) (offset + 1)]);
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setK(k);
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setK(k);
+ }
+ break;
+ case PARAMETER_S:
+ if ((key & KEY_PRIVATE) != 0) ecPrivateKey.setS(data, offset, length);
+ break;
+ case PARAMETER_W:
+ if ((key & KEY_PUBLIC) != 0) ecPublicKey.setW(data, offset, length);
+ break;
+ default:
+ result = ISO7816.SW_UNKNOWN;
+ }
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public short exportParameter(byte key, byte param, byte[] outputBuffer, short outputOffset) {
+ if (key == KEY_BOTH) {
+ return ISO7816.SW_UNKNOWN;
+ }
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ switch(param){
+ case PARAMETER_FP:
+
+ break;
+
+ default:
+
+ }
+ } catch (CryptoException ce) {
+
+ } catch (Exception e) {
+
+ }
+ //TODO
+ return result;
+ }
+
+ public ECPrivateKey getPrivateKey() {
+ return ecPrivateKey;
+ }
+
+ public ECPublicKey getPublicKey() {
+ return ecPublicKey;
+ }
+
+ public KeyPair getKeyPair() {
+ return ecKeyPair;
+ }
+}
diff --git a/src/applets/ECKeyTester.java b/src/applets/ECKeyTester.java
new file mode 100644
index 0000000..91d7a8b
--- /dev/null
+++ b/src/applets/ECKeyTester.java
@@ -0,0 +1,180 @@
+package applets;
+
+
+import javacard.framework.ISO7816;
+import javacard.security.*;
+
+/**
+ * Class capable of testing ECDH/C and ECDSA.
+ * Note that ECDH and ECDHC output should equal, only the algorithm is different.
+ */
+public class ECKeyTester {
+ private KeyAgreement ecdhKeyAgreement = null;
+ private KeyAgreement ecdhcKeyAgreement = null;
+ private Signature ecdsaSignature = null;
+
+ public final static short SW_SIG_LENGTH_MISMATCH = (short) 0xee4;
+ public final static short SW_SIG_VERIFY_FAIL = (short) 0xee5;
+
+ public short allocateECDH() {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecdhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public short allocateECDHC() {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecdhcKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DHC, false);
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public short allocateECDSA() {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecdsaSignature = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ private short testDH(KeyAgreement ka, ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ka.init(privateKey);
+
+ short secretLength = ka.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ //TODO, figure out how to separate the return value of this method (short) error, and return the secretLenght..
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ private short testDH_validPoint(KeyAgreement ka, ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) {
+ return testDH(ka, privateKey, pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ }
+
+ private short testDH_invalidPoint(KeyAgreement ka, ECPrivateKey privateKey, byte[] pubkeyBuffer, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset) {
+ pubkeyBuffer[(short)(pubkeyLength - 2)] += 0xcc;
+ pubkeyBuffer[(short)(pubkeyLength - 3)] += 0xcc;
+ short result = testDH(ka, privateKey, pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset);
+ pubkeyBuffer[(short)(pubkeyLength - 2)] -= 0xcc;
+ pubkeyBuffer[(short)(pubkeyLength - 3)] -= 0xcc;
+ return result;
+ }
+
+ /**
+ * Tests ECDH secret generation with given {@code privateKey} and {@code publicKey}.
+ * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
+ * Output should equal with ECDHC output.
+ * @param privateKey
+ * @param publicKey
+ * @param pubkeyBuffer
+ * @param pubkeyOffset
+ * @param outputBuffer
+ * @param outputOffset
+ * @return ISO7816.SW_NO_ERROR on correct operation,
+ * exception reason otherwise
+ **/
+ public short testECDH_validPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
+ publicKey.getW(pubkeyBuffer, pubkeyOffset);
+ return testDH_validPoint(ecdhKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, (short) pubkeyBuffer.length, outputBuffer, outputOffset);
+ }
+
+ public short testECDH_invalidPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
+ publicKey.getW(pubkeyBuffer, pubkeyOffset);
+ return testDH_invalidPoint(ecdhKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, (short) pubkeyBuffer.length, outputBuffer, outputOffset);
+ }
+
+
+ /**
+ * Tests ECDHC secret generation with given {@code privateKey} and {@code publicKey}.
+ * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations.
+ * Output should equal to ECDH output.
+ * @param privateKey
+ * @param publicKey
+ * @param pubkeyBuffer
+ * @param pubkeyOffset
+ * @param outputBuffer
+ * @param outputOffset
+ * @return ISO7816.SW_NO_ERROR on correct operation,
+ * exception reason otherwise
+ */
+ public short testECDHC_validPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
+ publicKey.getW(pubkeyBuffer, pubkeyOffset);
+ return testDH_validPoint(ecdhcKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, (short) pubkeyBuffer.length, outputBuffer, outputOffset);
+ }
+
+ public short testECDHC_invalidPoint(ECPrivateKey privateKey, ECPublicKey publicKey, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset) {
+ publicKey.getW(pubkeyBuffer, pubkeyOffset);
+ return testDH_invalidPoint(ecdhcKeyAgreement, privateKey, pubkeyBuffer, pubkeyOffset, (short) pubkeyBuffer.length, outputBuffer, outputOffset);
+ }
+
+ /**
+ * Uses {@code signKey} to sign data from {@code inputBuffer} at {@code inputOffset} with {@code inputOffset}.
+ * Then checks for correct signature length.
+ * Then tries verifying the data with {@code verifyKey}.
+ * @param signKey
+ * @param verifyKey
+ * @param inputBuffer
+ * @param inputOffset
+ * @param inputLength
+ * @param sigBuffer
+ * @param sigOffset
+ * @return ISO7816.SW_NO_ERROR on correct operation,
+ * SW_SIG_VERIFY_FAIL,
+ * SW_SIG_LENGTH_MISMATCH
+ */
+ public short testECDSA(ECPrivateKey signKey, ECPublicKey verifyKey, byte[] inputBuffer, short inputOffset, short inputLength, byte[] sigBuffer, short sigOffset) {
+ short result = ISO7816.SW_NO_ERROR;
+ try {
+ ecdsaSignature.init(signKey, Signature.MODE_SIGN);
+
+ short sigLength = ecdsaSignature.sign(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset);
+ if (sigLength != 20) { // per javacard.security.Signature an ALG_ECDSA_SHA should be 20 bytes.
+ result = ECKeyTester.SW_SIG_LENGTH_MISMATCH;
+ } else {
+ ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
+ boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength);
+ if (!correct) {
+ result = ECKeyTester.SW_SIG_VERIFY_FAIL;
+ }
+ }
+ } catch (CryptoException ce) {
+ result = ce.getReason();
+ } catch (Exception e) {
+ result = ISO7816.SW_UNKNOWN;
+ }
+ return result;
+ }
+
+ public KeyAgreement getECDH() {
+ return ecdhKeyAgreement;
+ }
+
+ public KeyAgreement getECDHC() {
+ return ecdhcKeyAgreement;
+ }
+
+ public Signature getECDSA() {
+ return ecdsaSignature;
+ }
+
+}
diff --git a/src/applets/EC_Consts.java b/src/applets/EC_Consts.java
index b7128dc..3758f0b 100644
--- a/src/applets/EC_Consts.java
+++ b/src/applets/EC_Consts.java
@@ -485,14 +485,15 @@ public class EC_Consts {
(byte) 0x91, (byte) 0x38, (byte) 0x64, (byte) 0x09};
// cofactor of G
- public static final short EC521_FP_K = 1;
+ public static final short EC521_FP_K = 1;
+
+
public static final byte VALID_KEY = 1;
public static final byte INVALIDB_FIXED = 2;
public static final byte INVALIDB_RANDOM = 3;
-
-
+
public static void setValidECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, byte ecClass, short ecLength, byte[] auxBuffer) {
setECKeyParams(ecPubKey, ecPrivKey, ecClass, ecLength, auxBuffer, VALID_KEY);
}