From 48c54c5520382b3d2bc4899b7e2197afba976a04 Mon Sep 17 00:00:00 2001 From: J08nY Date: Wed, 26 Oct 2016 01:12:07 +0200 Subject: refactoring ECTester: created ECKeyGenerator, ECKeyTester --- src/applets/ECKeyGenerator.java | 179 +++++++++++++++++++++++++++++++++++++++ src/applets/ECKeyTester.java | 180 ++++++++++++++++++++++++++++++++++++++++ src/applets/EC_Consts.java | 7 +- 3 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 src/applets/ECKeyGenerator.java create mode 100644 src/applets/ECKeyTester.java (limited to 'src') 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); } -- cgit v1.2.3-70-g09d2