aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJ08nY2018-11-28 01:04:31 +0100
committerJ08nY2018-11-28 01:04:31 +0100
commitebe40e2fdd5e28cdabe05250422f3149e188641a (patch)
treefbf29423e8053c6a7267d600d1630fefb1bf1a1b /src
parent7e9917742785a9fd532a52231e95ddad5775555f (diff)
parent12845c8c41eff5f598dc8e843920f5bb4638775d (diff)
downloadECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.gz
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.tar.zst
ECTester-ebe40e2fdd5e28cdabe05250422f3149e188641a.zip
Diffstat (limited to 'src')
-rw-r--r--src/cz/crcs/ectester/applet/AppletBase.java886
-rw-r--r--src/cz/crcs/ectester/applet/AppletUtil.java29
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyGenerator.java9
-rw-r--r--src/cz/crcs/ectester/applet/ECKeyTester.java4
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java811
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterAppletExtended.java61
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_Category.java63
-rw-r--r--src/cz/crcs/ectester/common/ec/EC_SigResult.java2
-rw-r--r--src/cz/crcs/ectester/common/output/BaseTextTestWriter.java3
-rw-r--r--src/cz/crcs/ectester/common/util/CardUtil.java63
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java8
-rw-r--r--src/cz/crcs/ectester/data/EC_Store.java18
-rw-r--r--src/cz/crcs/ectester/data/bn/curves.xml16
-rw-r--r--src/cz/crcs/ectester/data/categories.xml12
-rw-r--r--src/cz/crcs/ectester/data/misc/keys.xml50
-rw-r--r--src/cz/crcs/ectester/data/misc/results.xml (renamed from src/cz/crcs/ectester/data/other/results.xml)0
-rw-r--r--src/cz/crcs/ectester/data/mnt/curves.xml74
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt1.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt2_1.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt2_2.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt3_1.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt3_2.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt3_3.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt4.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt5_1.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt5_2.csv1
-rw-r--r--src/cz/crcs/ectester/data/mnt/mnt5_3.csv1
-rw-r--r--src/cz/crcs/ectester/data/other/keys.xml14
-rw-r--r--src/cz/crcs/ectester/data/wrong/results.xml36
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java2
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java46
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java50
-rw-r--r--src/cz/crcs/ectester/reader/output/TextTestWriter.java10
-rw-r--r--src/cz/crcs/ectester/reader/output/XMLTestWriter.java32
-rw-r--r--src/cz/crcs/ectester/reader/output/YAMLTestWriter.java20
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java80
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCofactorSuite.java6
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeSuite.java18
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompressionSuite.java39
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java1
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java14
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidSuite.java4
-rw-r--r--src/cz/crcs/ectester/reader/test/CardMiscSuite.java63
-rw-r--r--src/cz/crcs/ectester/reader/test/CardSignatureSuite.java6
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java103
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistSuite.java4
-rw-r--r--src/cz/crcs/ectester/standalone/ECTesterStandalone.java335
-rw-r--r--src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java23
-rw-r--r--src/cz/crcs/ectester/standalone/consts/SignatureIdent.java29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BoringsslLib.java28
-rw-r--r--src/cz/crcs/ectester/standalone/libs/BotanLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/CryptoppLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/GcryptLib.java29
-rw-r--r--src/cz/crcs/ectester/standalone/libs/MscngLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java91
-rw-r--r--src/cz/crcs/ectester/standalone/libs/OpensslLib.java9
-rw-r--r--src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/TomcryptLib.java10
-rw-r--r--src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java18
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/Makefile91
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java43
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java36
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java20
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java112
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/boringssl.c528
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/botan.cpp70
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_timing.c57
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_timing.h38
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.c107
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/c_utils.h11
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp39
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c635
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/mscng.c12
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/native.h530
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/openssl.c66
-rw-r--r--src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c57
-rw-r--r--src/cz/crcs/ectester/standalone/output/TextTestWriter.java5
80 files changed, 4503 insertions, 1260 deletions
diff --git a/src/cz/crcs/ectester/applet/AppletBase.java b/src/cz/crcs/ectester/applet/AppletBase.java
new file mode 100644
index 0000000..4e488b5
--- /dev/null
+++ b/src/cz/crcs/ectester/applet/AppletBase.java
@@ -0,0 +1,886 @@
+package cz.crcs.ectester.applet;
+
+import javacard.framework.*;
+import javacard.security.*;
+
+public abstract class AppletBase extends Applet {
+
+ // MAIN INSTRUCTION CLASS
+ public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0;
+
+ // INSTRUCTIONS
+ public static final byte INS_ALLOCATE = (byte) 0x5a;
+ public static final byte INS_CLEAR = (byte) 0x5b;
+ public static final byte INS_SET = (byte) 0x5c;
+ public static final byte INS_TRANSFORM = (byte) 0x5d;
+ public static final byte INS_GENERATE = (byte) 0x5e;
+ public static final byte INS_EXPORT = (byte) 0x5f;
+ public static final byte INS_ECDH = (byte) 0x70;
+ public static final byte INS_ECDH_DIRECT = (byte) 0x71;
+ public static final byte INS_ECDSA = (byte) 0x72;
+ public static final byte INS_ECDSA_SIGN = (byte) 0x73;
+ public static final byte INS_ECDSA_VERIFY = (byte) 0x74;
+ public static final byte INS_CLEANUP = (byte) 0x75;
+ public static final byte INS_ALLOCATE_KA = (byte) 0x76;
+ public static final byte INS_ALLOCATE_SIG = (byte) 0x77;
+ public static final byte INS_GET_INFO = (byte) 0x78;
+
+ // PARAMETERS for P1 and P2
+ public static final byte KEYPAIR_LOCAL = (byte) 0x01;
+ public static final byte KEYPAIR_REMOTE = (byte) 0x02;
+ public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE;
+ public static final byte EXPORT_TRUE = (byte) 0xff;
+ public static final byte EXPORT_FALSE = (byte) 0x00;
+
+ // STATUS WORDS
+ public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1;
+ public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2;
+ public static final short SW_KEYPAIR_NULL = (short) 0x0ee3;
+ public static final short SW_KA_NULL = (short) 0x0ee4;
+ public static final short SW_SIGNATURE_NULL = (short) 0x0ee5;
+ public static final short SW_OBJECT_NULL = (short) 0x0ee6;
+ public static final short SW_Exception = (short) 0xff01;
+ public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02;
+ public static final short SW_ArithmeticException = (short) 0xff03;
+ public static final short SW_ArrayStoreException = (short) 0xff04;
+ public static final short SW_NullPointerException = (short) 0xff05;
+ public static final short SW_NegativeArraySizeException = (short) 0xff06;
+ public static final short SW_CryptoException_prefix = (short) 0xf100;
+ public static final short SW_SystemException_prefix = (short) 0xf200;
+ public static final short SW_PINException_prefix = (short) 0xf300;
+ public static final short SW_TransactionException_prefix = (short) 0xf400;
+ public static final short SW_CardRuntimeException_prefix = (short) 0xf500;
+
+ //
+ public static final short BASE_221 = (short) 0x0221;
+ public static final short BASE_222 = (short) 0x0222;
+
+ //
+ public static final byte[] VERSION = {'v', '0', '.', '3', '.', '0'};
+
+ public static final short ARRAY_LENGTH = 0x100;
+ public static final short APDU_MAX_LENGTH = 1024;
+
+ // TEMPORARRY ARRAY IN RAM
+ byte[] ramArray = null;
+ byte[] ramArray2 = null;
+ byte[] apduArray = null;
+
+ RandomData randomData = null;
+
+ ECKeyTester keyTester = null;
+ ECKeyGenerator keyGenerator = null;
+ KeyPair localKeypair = null;
+ KeyPair remoteKeypair = null;
+
+ protected AppletBase(byte[] buffer, short offset, byte length) {
+ if (length > 9) {
+ /*
+ short dataOffset = offset;
+ // 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++;
+ */
+
+ ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET);
+ ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET);
+ apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, JCSystem.CLEAR_ON_RESET);
+
+ randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
+ EC_Consts.randomData = randomData;
+
+ keyGenerator = new ECKeyGenerator();
+ keyTester = new ECKeyTester();
+ }
+ }
+
+ public void process(APDU apdu) throws ISOException {
+ // get the APDU buffer
+ byte[] apduBuffer = apdu.getBuffer();
+ byte cla = apduBuffer[ISO7816.OFFSET_CLA];
+ byte ins = apduBuffer[ISO7816.OFFSET_INS];
+
+ // ignore the applet select command dispatched to the process
+ if (selectingApplet()) {
+ return;
+ }
+
+ if (cla == CLA_ECTESTERAPPLET) {
+ try {
+ readAPDU(apdu, apduArray, APDU_MAX_LENGTH);
+
+ short length = 0;
+ switch (ins) {
+ case INS_ALLOCATE_KA:
+ length = insAllocateKA(apdu);
+ break;
+ case INS_ALLOCATE_SIG:
+ length = insAllocateSig(apdu);
+ break;
+ case INS_ALLOCATE:
+ length = insAllocate(apdu);
+ break;
+ case INS_CLEAR:
+ length = insClear(apdu);
+ break;
+ case INS_SET:
+ length = insSet(apdu);
+ break;
+ case INS_TRANSFORM:
+ length = insTransform(apdu);
+ break;
+ case INS_GENERATE:
+ length = insGenerate(apdu);
+ break;
+ case INS_EXPORT:
+ length = insExport(apdu);
+ break;
+ case INS_ECDH:
+ length = insECDH(apdu);
+ break;
+ case INS_ECDH_DIRECT:
+ length = insECDH_direct(apdu);
+ break;
+ case INS_ECDSA:
+ length = insECDSA(apdu);
+ break;
+ case INS_ECDSA_SIGN:
+ length = insECDSA_sign(apdu);
+ break;
+ case INS_ECDSA_VERIFY:
+ length = insECDSA_verify(apdu);
+ break;
+ case INS_CLEANUP:
+ length = insCleanup(apdu);
+ break;
+ case INS_GET_INFO:
+ length = insGetInfo(apdu);
+ break;
+ default:
+ // The INS code is not supported by the dispatcher
+ ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
+ break;
+ }
+ apdu.setOutgoingAndSend((short) 0, length);
+
+ } catch (ISOException e) {
+ throw e; // Our exception from code, just re-emit
+ } catch (ArrayIndexOutOfBoundsException e) {
+ ISOException.throwIt(SW_ArrayIndexOutOfBoundsException);
+ } catch (ArithmeticException e) {
+ ISOException.throwIt(SW_ArithmeticException);
+ } catch (ArrayStoreException e) {
+ ISOException.throwIt(SW_ArrayStoreException);
+ } catch (NullPointerException e) {
+ ISOException.throwIt(SW_NullPointerException);
+ } catch (NegativeArraySizeException e) {
+ ISOException.throwIt(SW_NegativeArraySizeException);
+ } catch (CryptoException e) {
+ ISOException.throwIt((short) (SW_CryptoException_prefix | e.getReason()));
+ } catch (SystemException e) {
+ ISOException.throwIt((short) (SW_SystemException_prefix | e.getReason()));
+ } catch (PINException e) {
+ ISOException.throwIt((short) (SW_PINException_prefix | e.getReason()));
+ } catch (TransactionException e) {
+ ISOException.throwIt((short) (SW_TransactionException_prefix | e.getReason()));
+ } catch (CardRuntimeException e) {
+ ISOException.throwIt((short) (SW_CardRuntimeException_prefix | e.getReason()));
+ } catch (Exception e) {
+ ISOException.throwIt(SW_Exception);
+ }
+
+ } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
+ }
+
+ private void readAPDU(APDU apdu, byte[] buffer, short length) {
+ short read = apdu.setIncomingAndReceive();
+ read += getOffsetCdata(apdu);
+ short total = getIncomingLength(apdu);
+ if (total > length) {
+ return;
+ }
+
+ byte[] apduBuffer = apdu.getBuffer();
+ short sum = 0;
+
+ do {
+ Util.arrayCopyNonAtomic(apduBuffer, (short) 0, buffer, sum, read);
+ sum += read;
+ read = apdu.receiveBytes((short) 0);
+ } while (sum < total);
+ }
+
+ abstract short getOffsetCdata(APDU apdu);
+
+ abstract short getIncomingLength(APDU apdu);
+
+ abstract short getBase();
+
+ /**
+ * Allocates KeyAgreement object, returns allocate SW.
+ *
+ * @param apdu DATA = byte KeyAgreementType
+ * @return length of response
+ */
+ private short insAllocateKA(APDU apdu) {
+ short cdata = getOffsetCdata(apdu);
+ byte kaType = apduArray[cdata];
+ short sw = keyTester.allocateKA(kaType);
+ Util.setShort(apdu.getBuffer(), (short) 0, sw);
+ return 2;
+ }
+
+ /**
+ * Allocates a Signature object, returns allocate SW.
+ *
+ * @param apdu DATA = byte SignatureType
+ * @return length of response
+ */
+ private short insAllocateSig(APDU apdu) {
+ short cdata = getOffsetCdata(apdu);
+ byte sigType = apduArray[cdata];
+ short sw = keyTester.allocateSig(sigType);
+ Util.setShort(apdu.getBuffer(), (short) 0, sw);
+ return 2;
+ }
+
+ /**
+ * Allocates local and remote keyPairs.
+ * returns allocate SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 =
+ * DATA = short keyLength
+ * byte keyClass
+ * @return length of response
+ */
+ private short insAllocate(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ short cdata = getOffsetCdata(apdu);
+ short keyLength = Util.getShort(apduArray, cdata);
+ byte keyClass = apduArray[(short) (cdata + 2)];
+
+ return allocate(keyPair, keyLength, keyClass, apdu.getBuffer(), (short) 0);
+ }
+
+ /**
+ * Clears local and remote keyPair's keys {@code .clearKey()}.
+ * returns clearKey SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 =
+ * @return length of response
+ */
+ private short insClear(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += clear(localKeypair, apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += clear(remoteKeypair, apdu.getBuffer(), len);
+ }
+
+ return len;
+ }
+
+ /**
+ * Sets curve parameters on local and remote keyPairs.
+ * returns setCurve SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 = byte curve (EC_Consts.CURVE_*)
+ * DATA = short params (EC_Consts.PARAMETER_* | ...)
+ * <p>
+ * if curveID = CURVE_EXTERNAL:
+ * [short paramLength, byte[] param],
+ * for all params in params,
+ * in order: field,a,b,g,r,k,w,s
+ * @return length of response
+ */
+ private short insSet(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte curve = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ short params = Util.getShort(apduArray, cdata);
+
+ short len = 0;
+
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += set(localKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += set(remoteKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), len);
+ }
+
+ return len;
+ }
+
+ /**
+ * Transforms curve paramaters of local and remote keyPairs.
+ * returns transformCurve SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 = byte key (EC_Consts.KEY_* | ...)
+ * DATA = short params (EC_Consts.PARAMETER_* | ...)
+ * short transformation (EC_Consts.TRANSFORMATION_* || ...)
+ * @return length of response
+ */
+ private short insTransform(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte key = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ short params = Util.getShort(apduArray, cdata);
+ short transformation = Util.getShort(apduArray, (short) (cdata + 2));
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += transform(localKeypair, key, params, transformation, apdu.getBuffer(), (short) 0);
+ }
+
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += transform(remoteKeypair, key, params, transformation, apdu.getBuffer(), len);
+ }
+
+ return len;
+ }
+
+ /**
+ * Generates the local and remote keyPairs.
+ * returns generate SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 =
+ * @return length of response
+ */
+ private short insGenerate(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += generate(localKeypair, apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += generate(remoteKeypair, apdu.getBuffer(), len);
+ }
+
+ return len;
+ }
+
+ /**
+ * Exports selected key and domain parameters from the selected keyPair and key.
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 = byte key (EC_Consts.KEY_* | ...)
+ * DATA = short params
+ * @return length of response
+ */
+ private short insExport(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte key = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ short params = Util.getShort(apduArray, cdata);
+
+ short swOffset = 0;
+ short len = (short) (keyPair == KEYPAIR_BOTH ? 4 : 2);
+
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += export(localKeypair, key, params, apdu.getBuffer(), swOffset, len);
+ swOffset += 2;
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += export(remoteKeypair, key, params, apdu.getBuffer(), swOffset, len);
+ }
+
+ return len;
+ }
+
+ /**
+ * Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote).
+ * returns deriveSecret SW, {@code if(export == EXPORT_TRUE)} => short secretlen, byte[] secret
+ *
+ * @param apdu P1 = byte pubkey (KEYPAIR_*)
+ * P2 = byte privkey (KEYPAIR_*)
+ * DATA = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * short transformation (EC_Consts.TRANSFORMATION_* | ...)
+ * byte type (EC_Consts.KA_* | ...)
+ * @return length of response
+ */
+ private short insECDH(APDU apdu) {
+ byte pubkey = apduArray[ISO7816.OFFSET_P1];
+ byte privkey = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ byte export = apduArray[cdata];
+ short transformation = Util.getShort(apduArray, (short) (cdata + 1));
+ byte type = apduArray[(short) (cdata + 3)];
+
+ return ecdh(pubkey, privkey, export, transformation, type, apdu.getBuffer(), (short) 0);
+ }
+
+ /**
+ * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data
+ *
+ * @param apdu P1 = byte privkey (KEYPAIR_*)
+ * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * DATA = short transformation (EC_Consts.TRANSFORMATION_* | ...)
+ * byte type (EC_Consts.KA_* | ...)
+ * short length
+ * byte[] pubkey
+ * @return length of response
+ */
+ private short insECDH_direct(APDU apdu) {
+ byte privkey = apduArray[ISO7816.OFFSET_P1];
+ byte export = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ short transformation = Util.getShort(apduArray, cdata);
+ byte type = apduArray[(short) (cdata + 2)];
+ short length = Util.getShort(apduArray, (short) (cdata + 3));
+
+ return ecdh_direct(privkey, export, transformation, type, (short) (cdata + 5), length, apdu.getBuffer(), (short) 0);
+ }
+
+ /**
+ * Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote).
+ * returns ecdsa SW, {@code if(export == EXPORT_TRUE)} => short signature_length, byte[] signature
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_*)
+ * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * DATA = byte sigType
+ * short dataLength (00 = random data generated, !00 = data length)
+ * byte[] data
+ * @return length of response
+ */
+ private short insECDSA(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte export = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ byte sigType = apduArray[cdata];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len);
+ }
+
+ return len;
+ }
+
+ /**
+ * @param apdu P1 = byte keyPair (KEYPAIR_*)
+ * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * DATA = byte sigType
+ * short dataLength (00 = random data generated, !00 = data length)
+ * byte[] data
+ * @return length of response
+ */
+ private short insECDSA_sign(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte export = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+ byte sigType = apduArray[cdata];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += ecdsa_sign(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += ecdsa_sign(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len);
+ }
+ return len;
+ }
+
+ /**
+ * @param apdu P1 = byte keyPair (KEYPAIR_*)
+ * P2 = byte sigType
+ * DATA = short dataLength (00 = random data generated, !00 = data length)
+ * byte[] data
+ * short sigLength
+ * byte[] signature
+ * @return length of response
+ */
+ private short insECDSA_verify(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte sigType = apduArray[ISO7816.OFFSET_P2];
+ short cdata = getOffsetCdata(apdu);
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += ecdsa_verify(localKeypair, sigType, apduArray, cdata, apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += ecdsa_verify(remoteKeypair, sigType, apduArray, cdata, apdu.getBuffer(), len);
+ }
+ return len;
+ }
+
+
+ /**
+ * Performs card memory cleanup via JCSystem.requestObjectDeletion()
+ *
+ * @param apdu no data
+ * @return length of response
+ */
+ private short insCleanup(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+
+ return cleanup(apdubuf, (short) 0);
+ }
+
+ /**
+ * Gathers info about the applet and the card environment.
+ *
+ * @param apdu no data
+ * @return length of response
+ */
+ private short insGetInfo(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+
+ return getInfo(apdubuf, (short) 0);
+ }
+
+ /**
+ * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
+ * @param keyLength key length to set
+ * @param keyClass key class to allocate
+ * @param outBuffer buffer to write sw to
+ * @param outOffset offset into buffer
+ * @return length of data written to the buffer
+ */
+ private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] outBuffer, short outOffset) {
+ short length = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ localKeypair = keyGenerator.allocatePair(keyClass, keyLength);
+ Util.setShort(outBuffer, outOffset, keyGenerator.getSW());
+ length += 2;
+ }
+
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ remoteKeypair = keyGenerator.allocatePair(keyClass, keyLength);
+ Util.setShort(outBuffer, (short) (outOffset + length), keyGenerator.getSW());
+ length += 2;
+ }
+
+ return length;
+ }
+
+ /**
+ * @param keyPair KeyPair to clear
+ * @param outBuffer buffer to write sw to
+ * @param outOffset offset into buffer
+ * @return length of data written to the buffer
+ */
+ private short clear(KeyPair keyPair, byte[] outBuffer, short outOffset) {
+ short sw = keyGenerator.clearPair(keyPair, EC_Consts.KEY_BOTH);
+ Util.setShort(outBuffer, outOffset, sw);
+
+ return 2;
+ }
+
+ /**
+ * @param keyPair KeyPair to set params on
+ * @param curve curve to set (EC_Consts.CURVE_*)
+ * @param params parameters to set (EC_Consts.PARAMETER_* | ...)
+ * @param inBuffer buffer to read params from
+ * @param inOffset input offset in buffer
+ * @param outBuffer buffer to write sw to
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short set(KeyPair keyPair, byte curve, short params, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
+ short sw = ISO7816.SW_NO_ERROR;
+
+ switch (curve) {
+ case EC_Consts.CURVE_default:
+ //default, dont set anything
+ break;
+ case EC_Consts.CURVE_external:
+ //external
+ sw = keyGenerator.setExternalCurve(keyPair, params, inBuffer, inOffset);
+ break;
+ default:
+ //custom
+ sw = keyGenerator.setCurve(keyPair, curve, params, ramArray, (short) 0);
+ break;
+ }
+
+ Util.setShort(outBuffer, outOffset, sw);
+ return 2;
+ }
+
+ /**
+ * @param keyPair KeyPair to transform
+ * @param key key to transform (EC_Consts.KEY_* | ...)
+ * @param params parameters to transform (EC_Consts.PARAMETER_* | ...)
+ * @param transformation transformation type (EC_Consts.TRANSFORMATION_*)
+ * @param outBuffer buffer to output sw to
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short transform(KeyPair keyPair, byte key, short params, short transformation, byte[] outBuffer, short outOffset) {
+ short sw = keyGenerator.transformCurve(keyPair, key, params, transformation, ramArray, (short) 0);
+ Util.setShort(outBuffer, outOffset, sw);
+ return 2;
+ }
+
+ /**
+ * @param keyPair KeyPair to generate
+ * @param outBuffer buffer to output sw to
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short generate(KeyPair keyPair, byte[] outBuffer, short outOffset) {
+ short sw = keyGenerator.generatePair(keyPair);
+ Util.setShort(outBuffer, outOffset, sw);
+
+ return 2;
+ }
+
+ /**
+ * @param keyPair KeyPair to export from
+ * @param key which key to export from (EC_Consts.KEY_PUBLIC | EC_Consts.KEY_PRIVATE)
+ * @param params which params to export (EC_Consts.PARAMETER_* | ...)
+ * @param outBuffer buffer to export params to
+ * @param swOffset offset to output sw to buffer
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short export(KeyPair keyPair, byte key, short params, byte[] outBuffer, short swOffset, short outOffset) {
+ short length = 0;
+
+ short sw = ISO7816.SW_NO_ERROR;
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) {
+ //export params from public
+ length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, outBuffer, outOffset);
+ sw = keyGenerator.getSW();
+ }
+ if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) {
+ //export params from private
+ length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, outBuffer, (short) (outOffset + length));
+ sw = keyGenerator.getSW();
+ }
+ Util.setShort(outBuffer, swOffset, sw);
+
+ return length;
+ }
+
+ /**
+ * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
+ * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
+ * @param export whether to export ECDH secret
+ * @param transformation whether to transform the pubkey before ECDH
+ * @param type KeyAgreement type to test
+ * @param outBuffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)}
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short ecdh(byte pubkey, byte privkey, byte export, short transformation, byte type, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ KeyPair pub = ((pubkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
+ KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
+
+ short secretLength = 0;
+ if (keyTester.getKaType() == type) {
+ secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation);
+ } else {
+ short allocateSW = keyTester.allocateKA(type);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation);
+ }
+ }
+ Util.setShort(outBuffer, outOffset, keyTester.getSW());
+ length += 2;
+
+ if ((export == EXPORT_TRUE)) {
+ Util.setShort(outBuffer, (short) (outOffset + length), secretLength);
+ length += 2;
+ Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength);
+ length += secretLength;
+ }
+
+ return length;
+ }
+
+ private short ecdh_direct(byte privkey, byte export, short transformation, byte type, short keyOffset, short keyLength, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
+
+ short secretLength = 0;
+ if (keyTester.getKaType() == type) {
+ secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation);
+ } else {
+ short allocateSW = keyTester.allocateKA(type);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation);
+ }
+ }
+
+ Util.setShort(outBuffer, outOffset, keyTester.getSW());
+ length += 2;
+
+ if ((export == EXPORT_TRUE)) {
+ Util.setShort(outBuffer, (short) (outOffset + length), secretLength);
+ length += 2;
+ Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength);
+ length += secretLength;
+ }
+ return length;
+ }
+
+ /**
+ * @param sign keyPair to use for signing and verification
+ * @param sigType Signature type to use
+ * @param export whether to export ECDSA signature
+ * @param inBuffer buffer to read dataLength and data to sign from
+ * @param inOffset input offset in buffer
+ * @param outBuffer buffer to write sw to, and export ECDSA signature {@code if(export == EXPORT_TRUE)}
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short ecdsa(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ short dataLength = Util.getShort(inBuffer, inOffset);
+ if (dataLength == 0) { //no data to sign
+ //generate random
+ dataLength = 64;
+ randomData.generateData(ramArray, (short) 0, dataLength);
+ } else {
+ Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
+ }
+
+ short signatureLength = 0;
+ if (keyTester.getSigType() == sigType) {
+ signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ } else {
+ short allocateSW = keyTester.allocateSig(sigType);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ }
+ }
+ Util.setShort(outBuffer, outOffset, keyTester.getSW());
+ length += 2;
+
+ if (export == EXPORT_TRUE) {
+ Util.setShort(outBuffer, (short) (outOffset + length), signatureLength);
+ length += 2;
+
+ Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength);
+ length += signatureLength;
+ }
+
+ return length;
+ }
+
+ private short ecdsa_sign(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ short dataLength = Util.getShort(inBuffer, inOffset);
+ if (dataLength == 0) { //no data to sign
+ //generate random
+ dataLength = 64;
+ randomData.generateData(ramArray, (short) 0, dataLength);
+ } else {
+ Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
+ }
+
+ short signatureLength = 0;
+ if (keyTester.getSigType() == sigType) {
+ signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ } else {
+ short allocateSW = keyTester.allocateSig(sigType);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
+ }
+ }
+ Util.setShort(outBuffer, outOffset, keyTester.getSW());
+ length += 2;
+
+ if (export == EXPORT_TRUE) {
+ Util.setShort(outBuffer, (short) (outOffset + length), signatureLength);
+ length += 2;
+
+ Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength);
+ length += signatureLength;
+ }
+
+ return length;
+ }
+
+ private short ecdsa_verify(KeyPair verify, byte sigType, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ short dataLength = Util.getShort(inBuffer, inOffset);
+ short dataOffset = (short) (inOffset + 2);
+ short sigLength = Util.getShort(inBuffer, (short) (dataOffset + dataLength));
+ short sigOffset = (short) (dataOffset + dataLength + 2);
+
+ if (keyTester.getSigType() == sigType) {
+ keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength);
+ } else {
+ short allocateSW = keyTester.allocateSig(sigType);
+ if (allocateSW == ISO7816.SW_NO_ERROR) {
+ keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength);
+ }
+ }
+ Util.setShort(outBuffer, outOffset, keyTester.getSW());
+ length += 2;
+
+ return length;
+ }
+
+ /**
+ * @param buffer buffer to write sw to
+ * @param offset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short cleanup(byte[] buffer, short offset) {
+ short sw = ISO7816.SW_NO_ERROR;
+ try {
+ if (JCSystem.isObjectDeletionSupported())
+ JCSystem.requestObjectDeletion();
+ } catch (CardRuntimeException crex) {
+ sw = crex.getReason();
+ }
+
+ Util.setShort(buffer, offset, sw);
+ return 2;
+ }
+
+ /**
+ * @param buffer buffer to write sw to
+ * @param offset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short getInfo(byte[] buffer, short offset) {
+ short length = 0;
+ Util.setShort(buffer, (short) (offset + length), ISO7816.SW_NO_ERROR);
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) VERSION.length);
+ length += 2;
+ Util.arrayCopyNonAtomic(VERSION, (short) 0, buffer, (short) (offset + length), (short) (VERSION.length));
+ length += VERSION.length;
+ Util.setShort(buffer, (short) (offset + length), getBase());
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), JCSystem.getVersion());
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) (JCSystem.isObjectDeletionSupported() ? 1 : 0));
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) buffer.length);
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) ramArray.length);
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) ramArray2.length);
+ length += 2;
+ Util.setShort(buffer, (short) (offset + length), (short) apduArray.length);
+ length += 2;
+ return length;
+ }
+}
diff --git a/src/cz/crcs/ectester/applet/AppletUtil.java b/src/cz/crcs/ectester/applet/AppletUtil.java
index 532b44e..9869aa4 100644
--- a/src/cz/crcs/ectester/applet/AppletUtil.java
+++ b/src/cz/crcs/ectester/applet/AppletUtil.java
@@ -1,9 +1,7 @@
package cz.crcs.ectester.applet;
-import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
-import javacard.framework.Util;
import javacard.security.KeyAgreement;
import javacard.security.KeyPair;
import javacard.security.Signature;
@@ -20,37 +18,18 @@ public class AppletUtil {
}
public static short objCheck(Object obj) {
- return nullCheck(obj, ECTesterApplet.SW_OBJECT_NULL);
+ return nullCheck(obj, AppletBase.SW_OBJECT_NULL);
}
public static short keypairCheck(KeyPair keyPair) {
- return nullCheck(keyPair, ECTesterApplet.SW_KEYPAIR_NULL);
+ return nullCheck(keyPair, AppletBase.SW_KEYPAIR_NULL);
}
public static short kaCheck(KeyAgreement keyAgreement) {
- return nullCheck(keyAgreement, ECTesterApplet.SW_KA_NULL);
+ return nullCheck(keyAgreement, AppletBase.SW_KA_NULL);
}
public static short signCheck(Signature signature) {
- return nullCheck(signature, ECTesterApplet.SW_SIGNATURE_NULL);
- }
-
- public static short readAPDU(APDU apdu, byte[] buffer, short length) {
- short read = apdu.setIncomingAndReceive();
- read += apdu.getOffsetCdata();
- short total = apdu.getIncomingLength();
- if (total > length) {
- return 0;
- }
- byte[] apduBuffer = apdu.getBuffer();
-
- short sum = 0;
-
- do {
- Util.arrayCopyNonAtomic(apduBuffer, (short) 0, buffer, sum, read);
- sum += read;
- read = apdu.receiveBytes((short) 0);
- } while (sum < total);
- return 0;
+ return nullCheck(signature, AppletBase.SW_SIGNATURE_NULL);
}
}
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
index 7c52e8f..4326752 100644
--- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java
+++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java
@@ -204,11 +204,10 @@ public class ECKeyGenerator {
short i1 = Util.getShort(data, (short) (offset + 2));
short i2 = Util.getShort(data, (short) (offset + 4));
short i3 = Util.getShort(data, (short) (offset + 6));
-// if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
-// if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
- // TODO: fix this, ^^ fails on jcardsim, but is up to spec
- if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i3, i2, i1);
- if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i3, i2, i1);
+ if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3);
+ if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3);
+ // if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i3, i2, i1);
+ // if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i3, i2, i1);
} else {
sw = ISO7816.SW_UNKNOWN;
}
diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java
index 6b5aa6b..0e46971 100644
--- a/src/cz/crcs/ectester/applet/ECKeyTester.java
+++ b/src/cz/crcs/ectester/applet/ECKeyTester.java
@@ -122,7 +122,7 @@ public class ECKeyTester {
ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, length);
if (!correct) {
- sw = ECTesterApplet.SW_SIG_VERIFY_FAIL;
+ sw = AppletBase.SW_SIG_VERIFY_FAIL;
}
} catch (CardRuntimeException ce) {
sw = ce.getReason();
@@ -170,7 +170,7 @@ public class ECKeyTester {
ecdsaSignature.init(verifyKey, Signature.MODE_VERIFY);
boolean correct = ecdsaSignature.verify(inputBuffer, inputOffset, inputLength, sigBuffer, sigOffset, sigLength);
if (!correct) {
- sw = ECTesterApplet.SW_SIG_VERIFY_FAIL;
+ sw = AppletBase.SW_SIG_VERIFY_FAIL;
}
} catch (CardRuntimeException ce) {
sw = ce.getReason();
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index 17c8faf..41bee9b 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -26,9 +26,9 @@
*/
package cz.crcs.ectester.applet;
-import javacard.framework.*;
-import javacard.security.*;
-import javacardx.apdu.ExtendedLength;
+import javacard.framework.APDU;
+import javacard.framework.ISO7816;
+import javacard.framework.ISOException;
/**
* Applet part of ECTester, a tool for testing Elliptic curve support on javacards.
@@ -36,90 +36,9 @@ import javacardx.apdu.ExtendedLength;
* @author Petr Svenda petr@svenda.com
* @author Jan Jancar johny@neuromancer.sk
*/
-public class ECTesterApplet extends Applet implements ExtendedLength {
-
- // MAIN INSTRUCTION CLASS
- public static final byte CLA_ECTESTERAPPLET = (byte) 0xB0;
-
- // INSTRUCTIONS
- public static final byte INS_ALLOCATE = (byte) 0x5a;
- public static final byte INS_CLEAR = (byte) 0x5b;
- public static final byte INS_SET = (byte) 0x5c;
- public static final byte INS_TRANSFORM = (byte) 0x5d;
- public static final byte INS_GENERATE = (byte) 0x5e;
- public static final byte INS_EXPORT = (byte) 0x5f;
- public static final byte INS_ECDH = (byte) 0x70;
- public static final byte INS_ECDH_DIRECT = (byte) 0x71;
- public static final byte INS_ECDSA = (byte) 0x72;
- public static final byte INS_ECDSA_SIGN = (byte) 0x73;
- public static final byte INS_ECDSA_VERIFY = (byte) 0x74;
- public static final byte INS_CLEANUP = (byte) 0x75;
- public static final byte INS_ALLOCATE_KA = (byte) 0x76;
- public static final byte INS_ALLOCATE_SIG = (byte) 0x77;
-
-
- // PARAMETERS for P1 and P2
- public static final byte KEYPAIR_LOCAL = (byte) 0x01;
- public static final byte KEYPAIR_REMOTE = (byte) 0x02;
- public static final byte KEYPAIR_BOTH = KEYPAIR_LOCAL | KEYPAIR_REMOTE;
- public static final byte EXPORT_TRUE = (byte) 0xff;
- public static final byte EXPORT_FALSE = (byte) 0x00;
-
- // STATUS WORDS
- public static final short SW_SIG_VERIFY_FAIL = (short) 0x0ee1;
- public static final short SW_DH_DHC_MISMATCH = (short) 0x0ee2;
- public static final short SW_KEYPAIR_NULL = (short) 0x0ee3;
- public static final short SW_KA_NULL = (short) 0x0ee4;
- public static final short SW_SIGNATURE_NULL = (short) 0x0ee5;
- public static final short SW_OBJECT_NULL = (short) 0x0ee6;
- public static final short SW_Exception = (short) 0xff01;
- public static final short SW_ArrayIndexOutOfBoundsException = (short) 0xff02;
- public static final short SW_ArithmeticException = (short) 0xff03;
- public static final short SW_ArrayStoreException = (short) 0xff04;
- public static final short SW_NullPointerException = (short) 0xff05;
- public static final short SW_NegativeArraySizeException = (short) 0xff06;
- public static final short SW_CryptoException_prefix = (short) 0xf100;
- public static final short SW_SystemException_prefix = (short) 0xf200;
- public static final short SW_PINException_prefix = (short) 0xf300;
- public static final short SW_TransactionException_prefix = (short) 0xf400;
- public static final short SW_CardRuntimeException_prefix = (short) 0xf500;
-
- private static final short ARRAY_LENGTH = (short) 0xff;
- private static final short APDU_MAX_LENGTH = (short) 1024;
- // TEMPORARRY ARRAY IN RAM
- private byte[] ramArray = null;
- private byte[] ramArray2 = null;
- private byte[] apduArray = null;
-
- private RandomData randomData = null;
-
- private ECKeyTester keyTester = null;
- private ECKeyGenerator keyGenerator = null;
- private KeyPair localKeypair = null;
- private KeyPair remoteKeypair = null;
-
+public class ECTesterApplet extends AppletBase {
protected ECTesterApplet(byte[] buffer, short offset, byte length) {
- if (length > 9) {
- /*
- short dataOffset = offset;
- // 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++;
- */
-
- ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET);
- ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET);
- apduArray = JCSystem.makeTransientByteArray(APDU_MAX_LENGTH, JCSystem.CLEAR_ON_RESET);
-
- randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
- EC_Consts.randomData = randomData;
-
- keyGenerator = new ECKeyGenerator();
- keyTester = new ECKeyTester();
- }
+ super(buffer, offset, length);
register();
}
@@ -128,722 +47,16 @@ public class ECTesterApplet extends Applet implements ExtendedLength {
new ECTesterApplet(bArray, bOffset, bLength);
}
- public void process(APDU apdu) throws ISOException {
- // get the APDU buffer
- byte[] apduBuffer = apdu.getBuffer();
- byte cla = apduBuffer[ISO7816.OFFSET_CLA];
- byte ins = apduBuffer[ISO7816.OFFSET_INS];
-
- // ignore the applet select command dispached to the process
- if (selectingApplet()) {
- return;
- }
-
- if (cla == CLA_ECTESTERAPPLET) {
- try {
-
- AppletUtil.readAPDU(apdu, apduArray, APDU_MAX_LENGTH);
-
- short length = 0;
- switch (ins) {
- case INS_ALLOCATE_KA:
- length = insAllocateKA(apdu);
- break;
- case INS_ALLOCATE_SIG:
- length = insAllocateSig(apdu);
- break;
- case INS_ALLOCATE:
- length = insAllocate(apdu);
- break;
- case INS_CLEAR:
- length = insClear(apdu);
- break;
- case INS_SET:
- length = insSet(apdu);
- break;
- case INS_TRANSFORM:
- length = insTransform(apdu);
- break;
- case INS_GENERATE:
- length = insGenerate(apdu);
- break;
- case INS_EXPORT:
- length = insExport(apdu);
- break;
- case INS_ECDH:
- length = insECDH(apdu);
- break;
- case INS_ECDH_DIRECT:
- length = insECDH_direct(apdu);
- break;
- case INS_ECDSA:
- length = insECDSA(apdu);
- break;
- case INS_ECDSA_SIGN:
- length = insECDSA_sign(apdu);
- break;
- case INS_ECDSA_VERIFY:
- length = insECDSA_verify(apdu);
- break;
- case INS_CLEANUP:
- length = insCleanup(apdu);
- break;
- default:
- // The INS code is not supported by the dispatcher
- ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
- break;
- }
- apdu.setOutgoingAndSend((short) 0, length);
-
- } catch (ISOException e) {
- throw e; // Our exception from code, just re-emit
- } catch (ArrayIndexOutOfBoundsException e) {
- ISOException.throwIt(SW_ArrayIndexOutOfBoundsException);
- } catch (ArithmeticException e) {
- ISOException.throwIt(SW_ArithmeticException);
- } catch (ArrayStoreException e) {
- ISOException.throwIt(SW_ArrayStoreException);
- } catch (NullPointerException e) {
- ISOException.throwIt(SW_NullPointerException);
- } catch (NegativeArraySizeException e) {
- ISOException.throwIt(SW_NegativeArraySizeException);
- } catch (CryptoException e) {
- ISOException.throwIt((short) (SW_CryptoException_prefix | e.getReason()));
- } catch (SystemException e) {
- ISOException.throwIt((short) (SW_SystemException_prefix | e.getReason()));
- } catch (PINException e) {
- ISOException.throwIt((short) (SW_PINException_prefix | e.getReason()));
- } catch (TransactionException e) {
- ISOException.throwIt((short) (SW_TransactionException_prefix | e.getReason()));
- } catch (CardRuntimeException e) {
- ISOException.throwIt((short) (SW_CardRuntimeException_prefix | e.getReason()));
- } catch (Exception e) {
- ISOException.throwIt(SW_Exception);
- }
-
- } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
- }
-
- /**
- * Allocates KeyAgreement object, returns allocate SW.
- *
- * @param apdu DATA = byte KeyAgreementType
- * @return length of response
- */
- private short insAllocateKA(APDU apdu) {
- short cdata = apdu.getOffsetCdata();
- byte kaType = apduArray[cdata];
- short sw = keyTester.allocateKA(kaType);
- Util.setShort(apdu.getBuffer(), (short) 0, sw);
- return 2;
- }
-
- /**
- * Allocates a Signature object, returns allocate SW.
- *
- * @param apdu DATA = byte SignatureType
- * @return length of response
- */
- private short insAllocateSig(APDU apdu) {
- short cdata = apdu.getOffsetCdata();
- byte sigType = apduArray[cdata];
- short sw = keyTester.allocateSig(sigType);
- Util.setShort(apdu.getBuffer(), (short) 0, sw);
- return 2;
- }
-
- /**
- * Allocates local and remote keyPairs.
- * returns allocate SWs
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 =
- * DATA = short keyLength
- * byte keyClass
- * @return length of response
- */
- private short insAllocate(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- short cdata = apdu.getOffsetCdata();
- short keyLength = Util.getShort(apduArray, cdata);
- byte keyClass = apduArray[(short) (cdata + 2)];
-
- return allocate(keyPair, keyLength, keyClass, apdu.getBuffer(), (short) 0);
- }
-
- /**
- * Clears local and remote keyPair's keys {@code .clearKey()}.
- * returns clearKey SWs
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 =
- * @return length of response
- */
- private short insClear(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += clear(localKeypair, apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += clear(remoteKeypair, apdu.getBuffer(), len);
- }
-
- return len;
- }
-
- /**
- * Sets curve parameters on local and remote keyPairs.
- * returns setCurve SWs
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 = byte curve (EC_Consts.CURVE_*)
- * DATA = short params (EC_Consts.PARAMETER_* | ...)
- * <p>
- * if curveID = CURVE_EXTERNAL:
- * [short paramLength, byte[] param],
- * for all params in params,
- * in order: field,a,b,g,r,k,w,s
- * @return length of response
- */
- private short insSet(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte curve = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- short params = Util.getShort(apduArray, cdata);
-
- short len = 0;
-
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += set(localKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += set(remoteKeypair, curve, params, apduArray, (short) (cdata + 2), apdu.getBuffer(), len);
- }
-
- return len;
- }
-
- /**
- * Transforms curve paramaters of local and remote keyPairs.
- * returns transformCurve SWs
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 = byte key (EC_Consts.KEY_* | ...)
- * DATA = short params (EC_Consts.PARAMETER_* | ...)
- * short transformation (EC_Consts.TRANSFORMATION_* || ...)
- * @return length of response
- */
- private short insTransform(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte key = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- short params = Util.getShort(apduArray, cdata);
- short transformation = Util.getShort(apduArray, (short) (cdata + 2));
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += transform(localKeypair, key, params, transformation, apdu.getBuffer(), (short) 0);
- }
-
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += transform(remoteKeypair, key, params, transformation, apdu.getBuffer(), len);
- }
-
- return len;
- }
-
- /**
- * Generates the local and remote keyPairs.
- * returns generate SWs
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 =
- * @return length of response
- */
- private short insGenerate(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += generate(localKeypair, apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += generate(remoteKeypair, apdu.getBuffer(), len);
- }
-
- return len;
- }
-
- /**
- * Exports selected key and domain parameters from the selected keyPair and key.
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
- * P2 = byte key (EC_Consts.KEY_* | ...)
- * DATA = short params
- * @return length of response
- */
- private short insExport(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte key = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- short params = Util.getShort(apduArray, cdata);
-
- short swOffset = 0;
- short len = (short) (keyPair == KEYPAIR_BOTH ? 4 : 2);
-
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += export(localKeypair, key, params, apdu.getBuffer(), swOffset, len);
- swOffset += 2;
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += export(remoteKeypair, key, params, apdu.getBuffer(), swOffset, len);
- }
-
- return len;
- }
-
- /**
- * Performs ECDH, between the pubkey specified in P1(local/remote) and the privkey specified in P2(local/remote).
- * returns deriveSecret SW, {@code if(export == EXPORT_TRUE)} => short secretlen, byte[] secret
- *
- * @param apdu P1 = byte pubkey (KEYPAIR_*)
- * P2 = byte privkey (KEYPAIR_*)
- * DATA = byte export (EXPORT_TRUE || EXPORT_FALSE)
- * short transformation (EC_Consts.TRANSFORMATION_* | ...)
- * byte type (EC_Consts.KA_* | ...)
- * @return length of response
- */
- private short insECDH(APDU apdu) {
- byte pubkey = apduArray[ISO7816.OFFSET_P1];
- byte privkey = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- byte export = apduArray[cdata];
- short transformation = Util.getShort(apduArray, (short) (cdata + 1));
- byte type = apduArray[(short) (cdata + 3)];
-
- return ecdh(pubkey, privkey, export, transformation, type, apdu.getBuffer(), (short) 0);
- }
-
- /**
- * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data
- *
- * @param apdu P1 = byte privkey (KEYPAIR_*)
- * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
- * DATA = short transformation (EC_Consts.TRANSFORMATION_* | ...)
- * byte type (EC_Consts.KA_* | ...)
- * short length
- * byte[] pubkey
- * @return length of response
- */
- private short insECDH_direct(APDU apdu) {
- byte privkey = apduArray[ISO7816.OFFSET_P1];
- byte export = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- short transformation = Util.getShort(apduArray, cdata);
- byte type = apduArray[(short) (cdata + 2)];
- short length = Util.getShort(apduArray, (short) (cdata + 3));
-
- return ecdh_direct(privkey, export, transformation, type, (short) (cdata + 5), length, apdu.getBuffer(), (short) 0);
- }
-
- /**
- * Performs ECDSA signature and verification on data provided or random, using the keyPair in P1(local/remote).
- * returns ecdsa SW, {@code if(export == EXPORT_TRUE)} => short signature_length, byte[] signature
- *
- * @param apdu P1 = byte keyPair (KEYPAIR_*)
- * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
- * DATA = byte sigType
- * short dataLength (00 = random data generated, !00 = data length)
- * byte[] data
- * @return length of response
- */
- private short insECDSA(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte export = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- byte sigType = apduArray[cdata];
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len);
- }
-
- return len;
- }
-
- /**
- * @param apdu P1 = byte keyPair (KEYPAIR_*)
- * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
- * DATA = byte sigType
- * short dataLength (00 = random data generated, !00 = data length)
- * byte[] data
- * @return length of response
- */
- private short insECDSA_sign(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte export = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
- byte sigType = apduArray[cdata];
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += ecdsa_sign(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += ecdsa_sign(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len);
- }
- return len;
- }
-
- /**
- * @param apdu P1 = byte keyPair (KEYPAIR_*)
- * P2 = byte sigType
- * DATA = short dataLength (00 = random data generated, !00 = data length)
- * byte[] data
- * short sigLength
- * byte[] signature
- * @return length of response
- */
- private short insECDSA_verify(APDU apdu) {
- byte keyPair = apduArray[ISO7816.OFFSET_P1];
- byte sigType = apduArray[ISO7816.OFFSET_P2];
- short cdata = apdu.getOffsetCdata();
-
- short len = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += ecdsa_verify(localKeypair, sigType, apduArray, cdata, apdu.getBuffer(), (short) 0);
- }
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += ecdsa_verify(remoteKeypair, sigType, apduArray, cdata, apdu.getBuffer(), len);
- }
- return len;
- }
-
-
- /**
- * Performs card memory cleanup via JCSystem.requestObjectDeletion()
- *
- * @param apdu no data
- * @return length of response
- */
- private short insCleanup(APDU apdu) {
- byte[] apdubuf = apdu.getBuffer();
-
- return cleanup(apdubuf, (short) 0);
- }
-
- /**
- * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
- * @param keyLength key length to set
- * @param keyClass key class to allocate
- * @param outBuffer buffer to write sw to
- * @param outOffset offset into buffer
- * @return length of data written to the buffer
- */
- private short allocate(byte keyPair, short keyLength, byte keyClass, byte[] outBuffer, short outOffset) {
- short length = 0;
- if ((keyPair & KEYPAIR_LOCAL) != 0) {
- localKeypair = keyGenerator.allocatePair(keyClass, keyLength);
- Util.setShort(outBuffer, outOffset, keyGenerator.getSW());
- length += 2;
- }
-
- if ((keyPair & KEYPAIR_REMOTE) != 0) {
- remoteKeypair = keyGenerator.allocatePair(keyClass, keyLength);
- Util.setShort(outBuffer, (short) (outOffset + length), keyGenerator.getSW());
- length += 2;
- }
-
- return length;
- }
-
- /**
- * @param keyPair KeyPair to clear
- * @param outBuffer buffer to write sw to
- * @param outOffset offset into buffer
- * @return length of data written to the buffer
- */
- private short clear(KeyPair keyPair, byte[] outBuffer, short outOffset) {
- short sw = keyGenerator.clearPair(keyPair, EC_Consts.KEY_BOTH);
- Util.setShort(outBuffer, outOffset, sw);
-
- return 2;
- }
-
- /**
- * @param keyPair KeyPair to set params on
- * @param curve curve to set (EC_Consts.CURVE_*)
- * @param params parameters to set (EC_Consts.PARAMETER_* | ...)
- * @param inBuffer buffer to read params from
- * @param inOffset input offset in buffer
- * @param outBuffer buffer to write sw to
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short set(KeyPair keyPair, byte curve, short params, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
- short sw = ISO7816.SW_NO_ERROR;
-
- switch (curve) {
- case EC_Consts.CURVE_default:
- //default, dont set anything
- break;
- case EC_Consts.CURVE_external:
- //external
- sw = keyGenerator.setExternalCurve(keyPair, params, inBuffer, inOffset);
- break;
- default:
- //custom
- sw = keyGenerator.setCurve(keyPair, curve, params, ramArray, (short) 0);
- break;
- }
-
- Util.setShort(outBuffer, outOffset, sw);
- return 2;
- }
-
- /**
- * @param keyPair KeyPair to transform
- * @param key key to transform (EC_Consts.KEY_* | ...)
- * @param params parameters to transform (EC_Consts.PARAMETER_* | ...)
- * @param transformation transformation type (EC_Consts.TRANSFORMATION_*)
- * @param outBuffer buffer to output sw to
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short transform(KeyPair keyPair, byte key, short params, short transformation, byte[] outBuffer, short outOffset) {
- short sw = keyGenerator.transformCurve(keyPair, key, params, transformation, ramArray, (short) 0);
- Util.setShort(outBuffer, outOffset, sw);
- return 2;
- }
-
- /**
- * @param keyPair KeyPair to generate
- * @param outBuffer buffer to output sw to
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short generate(KeyPair keyPair, byte[] outBuffer, short outOffset) {
- short sw = keyGenerator.generatePair(keyPair);
- Util.setShort(outBuffer, outOffset, sw);
-
- return 2;
- }
-
- /**
- * @param keyPair KeyPair to export from
- * @param key which key to export from (EC_Consts.KEY_PUBLIC | EC_Consts.KEY_PRIVATE)
- * @param params which params to export (EC_Consts.PARAMETER_* | ...)
- * @param outBuffer buffer to export params to
- * @param swOffset offset to output sw to buffer
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short export(KeyPair keyPair, byte key, short params, byte[] outBuffer, short swOffset, short outOffset) {
- short length = 0;
-
- short sw = ISO7816.SW_NO_ERROR;
- if ((key & EC_Consts.KEY_PUBLIC) != 0) {
- //export params from public
- length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PUBLIC, params, outBuffer, outOffset);
- sw = keyGenerator.getSW();
- }
- if ((key & EC_Consts.KEY_PRIVATE) != 0 && sw == ISO7816.SW_NO_ERROR) {
- //export params from private
- length += keyGenerator.exportParameters(keyPair, EC_Consts.KEY_PRIVATE, params, outBuffer, (short) (outOffset + length));
- sw = keyGenerator.getSW();
- }
- Util.setShort(outBuffer, swOffset, sw);
-
- return length;
- }
-
- /**
- * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param export whether to export ECDH secret
- * @param transformation whether to transform the pubkey before ECDH
- * @param type KeyAgreement type to test
- * @param outBuffer buffer to write sw to, and export ECDH secret {@code if(export == EXPORT_TRUE)}
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short ecdh(byte pubkey, byte privkey, byte export, short transformation, byte type, byte[] outBuffer, short outOffset) {
- short length = 0;
-
- KeyPair pub = ((pubkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
- KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
-
- short secretLength = 0;
- if (keyTester.getKaType() == type) {
- secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation);
- } else {
- short allocateSW = keyTester.allocateKA(type);
- if (allocateSW == ISO7816.SW_NO_ERROR) {
- secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, transformation);
- }
- }
- Util.setShort(outBuffer, outOffset, keyTester.getSW());
- length += 2;
-
- if ((export == EXPORT_TRUE)) {
- Util.setShort(outBuffer, (short) (outOffset + length), secretLength);
- length += 2;
- Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength);
- length += secretLength;
- }
-
- return length;
- }
-
- private short ecdh_direct(byte privkey, byte export, short transformation, byte type, short keyOffset, short keyLength, byte[] outBuffer, short outOffset) {
- short length = 0;
-
- KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
-
- short secretLength = 0;
- if (keyTester.getKaType() == type) {
- secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation);
- } else {
- short allocateSW = keyTester.allocateKA(type);
- if (allocateSW == ISO7816.SW_NO_ERROR) {
- secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, transformation);
- }
- }
-
- Util.setShort(outBuffer, outOffset, keyTester.getSW());
- length += 2;
-
- if ((export == EXPORT_TRUE)) {
- Util.setShort(outBuffer, (short) (outOffset + length), secretLength);
- length += 2;
- Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), secretLength);
- length += secretLength;
- }
- return length;
- }
-
- /**
- * @param sign keyPair to use for signing and verification
- * @param sigType Signature type to use
- * @param export whether to export ECDSA signature
- * @param inBuffer buffer to read dataLength and data to sign from
- * @param inOffset input offset in buffer
- * @param outBuffer buffer to write sw to, and export ECDSA signature {@code if(export == EXPORT_TRUE)}
- * @param outOffset output offset in buffer
- * @return length of data written to the buffer
- */
- private short ecdsa(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
- short length = 0;
-
- short dataLength = Util.getShort(inBuffer, inOffset);
- if (dataLength == 0) { //no data to sign
- //generate random
- dataLength = 64;
- randomData.generateData(ramArray, (short) 0, dataLength);
- } else {
- Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
- }
-
- short signatureLength = 0;
- if (keyTester.getSigType() == sigType) {
- signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
- } else {
- short allocateSW = keyTester.allocateSig(sigType);
- if (allocateSW == ISO7816.SW_NO_ERROR) {
- signatureLength = keyTester.testECDSA((ECPrivateKey) sign.getPrivate(), (ECPublicKey) sign.getPublic(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
- }
- }
- Util.setShort(outBuffer, outOffset, keyTester.getSW());
- length += 2;
-
- if (export == EXPORT_TRUE) {
- Util.setShort(outBuffer, (short) (outOffset + length), signatureLength);
- length += 2;
-
- Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength);
- length += signatureLength;
- }
-
- return length;
- }
-
- private short ecdsa_sign(KeyPair sign, byte sigType, byte export, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
- short length = 0;
-
- short dataLength = Util.getShort(inBuffer, inOffset);
- if (dataLength == 0) { //no data to sign
- //generate random
- dataLength = 64;
- randomData.generateData(ramArray, (short) 0, dataLength);
- } else {
- Util.arrayCopyNonAtomic(inBuffer, (short) (inOffset + 2), ramArray, (short) 0, dataLength);
- }
-
- short signatureLength = 0;
- if (keyTester.getSigType() == sigType) {
- signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
- } else {
- short allocateSW = keyTester.allocateSig(sigType);
- if (allocateSW == ISO7816.SW_NO_ERROR) {
- signatureLength = keyTester.testECDSA_sign((ECPrivateKey) sign.getPrivate(), ramArray, (short) 0, dataLength, ramArray2, (short) 0);
- }
- }
- Util.setShort(outBuffer, outOffset, keyTester.getSW());
- length += 2;
-
- if (export == EXPORT_TRUE) {
- Util.setShort(outBuffer, (short) (outOffset + length), signatureLength);
- length += 2;
-
- Util.arrayCopyNonAtomic(ramArray2, (short) 0, outBuffer, (short) (outOffset + length), signatureLength);
- length += signatureLength;
- }
-
- return length;
+ short getOffsetCdata(APDU apdu) {
+ return ISO7816.OFFSET_CDATA;
}
- private short ecdsa_verify(KeyPair verify, byte sigType, byte[] inBuffer, short inOffset, byte[] outBuffer, short outOffset) {
- short length = 0;
-
- short dataLength = Util.getShort(inBuffer, inOffset);
- short dataOffset = (short) (inOffset + 2);
- short sigLength = Util.getShort(inBuffer, (short) (dataOffset + dataLength));
- short sigOffset = (short) (dataOffset + dataLength + 2);
-
- if (keyTester.getSigType() == sigType) {
- keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength);
- } else {
- short allocateSW = keyTester.allocateSig(sigType);
- if (allocateSW == ISO7816.SW_NO_ERROR) {
- keyTester.testECDSA_verify((ECPublicKey) verify.getPublic(), inBuffer, dataOffset, dataLength, inBuffer, sigOffset, sigLength);
- }
- }
- Util.setShort(outBuffer, outOffset, keyTester.getSW());
- length += 2;
-
- return length;
+ short getIncomingLength(APDU apdu) {
+ byte[] apduBuffer = apdu.getBuffer();
+ return apduBuffer[ISO7816.OFFSET_LC];
}
- /**
- * @param buffer buffer to write sw to
- * @param offset output offset in buffer
- * @return length of data written to the buffer
- */
- private short cleanup(byte[] buffer, short offset) {
- short sw = ISO7816.SW_NO_ERROR;
- try {
- if (JCSystem.isObjectDeletionSupported())
- JCSystem.requestObjectDeletion();
- } catch (CardRuntimeException crex) {
- sw = crex.getReason();
- }
-
- Util.setShort(buffer, offset, sw);
- return 2;
+ short getBase() {
+ return AppletBase.BASE_221;
}
}
diff --git a/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java
new file mode 100644
index 0000000..83e0851
--- /dev/null
+++ b/src/cz/crcs/ectester/applet/ECTesterAppletExtended.java
@@ -0,0 +1,61 @@
+/*
+ * ECTester, tool for testing Elliptic curve cryptography implementations.
+ * Copyright (c) 2016-2018 Petr Svenda <petr@svenda.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/*
+ * PACKAGEID: 4543546573746572
+ * APPLETID: 45435465737465723031
+ */
+package cz.crcs.ectester.applet;
+
+import javacard.framework.APDU;
+import javacard.framework.ISOException;
+import javacardx.apdu.ExtendedLength;
+
+/**
+ * Applet part of ECTester, a tool for testing Elliptic curve support on javacards.
+ *
+ * @author Petr Svenda petr@svenda.com
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class ECTesterAppletExtended extends AppletBase implements ExtendedLength {
+ protected ECTesterAppletExtended(byte[] buffer, short offset, byte length) {
+ super(buffer, offset, length);
+ register();
+ }
+
+ public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException {
+ // applet instance creation
+ new ECTesterAppletExtended(bArray, bOffset, bLength);
+ }
+
+ short getOffsetCdata(APDU apdu) {
+ return apdu.getOffsetCdata();
+ }
+
+ short getIncomingLength(APDU apdu) {
+ return apdu.getIncomingLength();
+ }
+
+ short getBase() {
+ return AppletBase.BASE_222;
+ }
+}
diff --git a/src/cz/crcs/ectester/common/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java
index 8af308c..05c910c 100644
--- a/src/cz/crcs/ectester/common/ec/EC_Category.java
+++ b/src/cz/crcs/ectester/common/ec/EC_Category.java
@@ -91,56 +91,21 @@ public class EC_Category {
out.append(System.lineSeparator());
}
- Map<String, EC_Key> keys = getObjects(EC_Key.class);
- size = keys.size();
- if (size > 0) {
- out.append(Colors.bold("\t\tKeys: "));
- for (Map.Entry<String, EC_Key> key : keys.entrySet()) {
- out.append(key.getKey());
- size--;
- if (size > 0)
- out.append(", ");
+ String[] headers = new String[]{"Public keys", "Private keys", "KeyPairs", "Results(KA)", "Results(SIG)"};
+ Class[] classes = new Class[]{EC_Key.Public.class, EC_Key.Private.class, EC_Keypair.class, EC_KAResult.class, EC_SigResult.class};
+ for (int i = 0; i < headers.length; ++i) {
+ Map<String, EC_Data> data = getObjects(classes[i]);
+ size = data.size();
+ if (size > 0) {
+ out.append(Colors.bold(String.format("\t\t%s: ", headers[i])));
+ for (Map.Entry<String, EC_Data> key : data.entrySet()) {
+ out.append(key.getKey());
+ size--;
+ if (size > 0)
+ out.append(", ");
+ }
+ out.append(System.lineSeparator());
}
- out.append(System.lineSeparator());
- }
-
- Map<String, EC_Keypair> keypairs = getObjects(EC_Keypair.class);
- size = keypairs.size();
- if (size > 0) {
- out.append(Colors.bold("\t\tKeypairs: "));
- for (Map.Entry<String, EC_Keypair> key : keypairs.entrySet()) {
- out.append(key.getKey());
- size--;
- if (size > 0)
- out.append(", ");
- }
- out.append(System.lineSeparator());
- }
-
- Map<String, EC_KAResult> kaResults = getObjects(EC_KAResult.class);
- size = kaResults.size();
- if (size > 0) {
- out.append(Colors.bold("\t\tResults(KA): "));
- for (Map.Entry<String, EC_KAResult> result : kaResults.entrySet()) {
- out.append(result.getKey());
- size--;
- if (size > 0)
- out.append(", ");
- }
- out.append(System.lineSeparator());
- }
-
- Map<String, EC_SigResult> sigResults = getObjects(EC_SigResult.class);
- size = sigResults.size();
- if (size > 0) {
- out.append(Colors.bold("\t\tResults(SIG): "));
- for (Map.Entry<String, EC_SigResult> result : sigResults.entrySet()) {
- out.append(result.getKey());
- size--;
- if (size > 0)
- out.append(", ");
- }
- out.append(System.lineSeparator());
}
return out.toString();
}
diff --git a/src/cz/crcs/ectester/common/ec/EC_SigResult.java b/src/cz/crcs/ectester/common/ec/EC_SigResult.java
index f1ab0f5..d97ced1 100644
--- a/src/cz/crcs/ectester/common/ec/EC_SigResult.java
+++ b/src/cz/crcs/ectester/common/ec/EC_SigResult.java
@@ -69,7 +69,7 @@ public class EC_SigResult extends EC_Data {
@Override
public String toString() {
- return "<" + getId() + "> " + sig + " result over " + curve + ", " + signKey + " + " + verifyKey + (data == null ? "" : " of data \"" + data + "\"") + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
+ return "<" + getId() + "> " + sig + " result over " + curve + ", " + signKey + " + " + verifyKey + (data == null ? "" : " of data \"" + data + "\"") + (desc == null ? "" : ": " + desc) + System.lineSeparator() + super.toString();
}
}
diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
index f60f8bb..85b32a4 100644
--- a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
+++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java
@@ -106,6 +106,9 @@ public abstract class BaseTextTestWriter implements TestWriter {
} else {
SimpleTest<? extends BaseTestable> test = (SimpleTest<? extends BaseTestable>) t;
out.append(testableString(test.getTestable()));
+ if (t.getResult().getCause() != null) {
+ out.append(" ┃ ").append(t.getResult().getCause().toString());
+ }
}
return line + out.toString();
}
diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java
index e7b370c..7483c32 100644
--- a/src/cz/crcs/ectester/common/util/CardUtil.java
+++ b/src/cz/crcs/ectester/common/util/CardUtil.java
@@ -327,16 +327,22 @@ public class CardUtil {
public static byte getKAType(String kaTypeString) {
switch (kaTypeString) {
+ case "DH":
case "ALG_EC_SVDP_DH":
return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
+ case "DH_PLAIN":
case "ALG_EC_SVDP_DH_PLAIN":
return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN;
+ case "PACE_GM":
case "ALG_EC_PACE_GM":
return EC_Consts.KeyAgreement_ALG_EC_PACE_GM;
+ case "DH_PLAIN_XY":
case "ALG_EC_SVDP_DH_PLAIN_XY":
return EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY;
+ case "DHC":
case "ALG_EC_SVDP_DHC":
return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC;
+ case "DHC_PLAIN":
case "ALG_EC_SVDP_DHC_PLAIN":
return EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN;
default:
@@ -373,14 +379,19 @@ public class CardUtil {
public static byte getSigType(String sigTypeString) {
switch (sigTypeString) {
+ case "ECDSA_SHA":
case "ALG_ECDSA_SHA":
return EC_Consts.Signature_ALG_ECDSA_SHA;
+ case "ECDSA_SHA_224":
case "ALG_ECDSA_SHA_224":
return EC_Consts.Signature_ALG_ECDSA_SHA_224;
+ case "ECDSA_SHA_256":
case "ALG_ECDSA_SHA_256":
return EC_Consts.Signature_ALG_ECDSA_SHA_256;
+ case "ECDSA_SHA_384":
case "ALG_ECDSA_SHA_384":
return EC_Consts.Signature_ALG_ECDSA_SHA_384;
+ case "ECDSA_SHA_512":
case "ALG_ECDSA_SHA_512":
return EC_Consts.Signature_ALG_ECDSA_SHA_512;
default:
@@ -409,6 +420,58 @@ public class CardUtil {
}
}
+ public static String getCurveName(byte curve) {
+ String result = "";
+ switch (curve) {
+ case EC_Consts.CURVE_default:
+ result = "default";
+ break;
+ case EC_Consts.CURVE_external:
+ result = "external";
+ break;
+ case EC_Consts.CURVE_secp112r1:
+ result = "secp112r1";
+ break;
+ case EC_Consts.CURVE_secp128r1:
+ result = "secp128r1";
+ break;
+ case EC_Consts.CURVE_secp160r1:
+ result = "secp160r1";
+ break;
+ case EC_Consts.CURVE_secp192r1:
+ result = "secp192r1";
+ break;
+ case EC_Consts.CURVE_secp224r1:
+ result = "secp224r1";
+ break;
+ case EC_Consts.CURVE_secp256r1:
+ result = "secp256r1";
+ break;
+ case EC_Consts.CURVE_secp384r1:
+ result = "secp384r1";
+ break;
+ case EC_Consts.CURVE_secp521r1:
+ result = "secp521r1";
+ break;
+ case EC_Consts.CURVE_sect163r1:
+ result = "sect163r1";
+ break;
+ case EC_Consts.CURVE_sect233r1:
+ result = "sect233r1";
+ break;
+ case EC_Consts.CURVE_sect283r1:
+ result = "sect283r1";
+ break;
+ case EC_Consts.CURVE_sect409r1:
+ result = "sect409r1";
+ break;
+ case EC_Consts.CURVE_sect571r1:
+ result = "sect571r1";
+ break;
+ }
+ return result;
+ }
+
public static String getParameterString(short params) {
String what = "";
if (params == EC_Consts.PARAMETERS_DOMAIN_F2M || params == EC_Consts.PARAMETERS_DOMAIN_FP) {
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java
index 6c3ad58..1706ca0 100644
--- a/src/cz/crcs/ectester/common/util/ECUtil.java
+++ b/src/cz/crcs/ectester/common/util/ECUtil.java
@@ -31,6 +31,14 @@ public class ECUtil {
return raw;
}
+ public static byte[] toX962Compressed(byte[][] point) {
+ if (point.length != 2) {
+ return null;
+ }
+ byte ybit = (byte) (point[1][point[1].length - 1] % 2);
+ return ByteUtil.concatenate(new byte[]{(byte) (0x02 | ybit)}, point[0]);
+ }
+
public static byte[] toX962Compressed(ECPoint point, int bits) {
if (point.equals(ECPoint.POINT_INFINITY)) {
return new byte[]{0};
diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java
index f1d4260..d104fa4 100644
--- a/src/cz/crcs/ectester/data/EC_Store.java
+++ b/src/cz/crcs/ectester/data/EC_Store.java
@@ -350,7 +350,7 @@ public class EC_Store {
return getObject(objClass, query.substring(0, split), query.substring(split + 1));
}
- private static <T extends EC_Data> List<Map.Entry<EC_Curve, List<T>>> mapKeyToCurve(Collection<T> data, Function<T, String> getter) {
+ private static <T extends EC_Data> Map<EC_Curve, List<T>> mapKeyToCurve(Collection<T> data, Function<T, String> getter) {
Map<EC_Curve, List<T>> curves = new TreeMap<>();
for (T item : data) {
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, getter.apply(item));
@@ -361,21 +361,18 @@ public class EC_Store {
for (List<T> keyList : curves.values()) {
Collections.sort(keyList);
}
- List<Map.Entry<EC_Curve, List<T>>> curveList = new LinkedList<>();
- curveList.addAll(curves.entrySet());
- Comparator<Map.Entry<EC_Curve, List<T>>> c = Comparator.comparing(Map.Entry::getKey);
- return curveList;
+ return curves;
}
- public static <T extends EC_Key> List<Map.Entry<EC_Curve, List<T>>> mapKeyToCurve(Collection<T> keys) {
+ public static <T extends EC_Key> Map<EC_Curve, List<T>> mapKeyToCurve(Collection<T> keys) {
return mapKeyToCurve(keys, EC_Key::getCurve);
}
- public static List<Map.Entry<EC_Curve, List<EC_KAResult>>> mapResultToCurve(Collection<EC_KAResult> results) {
+ public static Map<EC_Curve, List<EC_KAResult>> mapResultToCurve(Collection<EC_KAResult> results) {
return mapKeyToCurve(results, EC_KAResult::getCurve);
}
- public static <T extends EC_Data> List<Map.Entry<String, List<T>>> mapToPrefix(Collection<T> data) {
+ public static <T extends EC_Data> Map<String, List<T>> mapToPrefix(Collection<T> data) {
Map<String, List<T>> groups = new TreeMap<>();
for (T item : data) {
String prefix = item.getId().split("/")[0];
@@ -386,10 +383,7 @@ public class EC_Store {
for (List<T> itemList : groups.values()) {
Collections.sort(itemList);
}
- List<Map.Entry<String, List<T>>> result = new LinkedList<>();
- result.addAll(groups.entrySet());
- result.sort(Comparator.comparing(Map.Entry::getKey));
- return result;
+ return groups;
}
public static EC_Store getInstance() {
diff --git a/src/cz/crcs/ectester/data/bn/curves.xml b/src/cz/crcs/ectester/data/bn/curves.xml
index ddf2263..c5ca22f 100644
--- a/src/cz/crcs/ectester/data/bn/curves.xml
+++ b/src/cz/crcs/ectester/data/bn/curves.xml
@@ -6,95 +6,111 @@
<bits>158</bits>
<field>prime</field>
<file>bn158.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn190</id>
<bits>190</bits>
<field>prime</field>
<file>bn190.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn222</id>
<bits>222</bits>
<field>prime</field>
<file>bn222.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn254</id>
<bits>254</bits>
<field>prime</field>
<file>bn254.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn286</id>
<bits>286</bits>
<field>prime</field>
<file>bn286.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn318</id>
<bits>318</bits>
<field>prime</field>
<file>bn318.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn350</id>
<bits>350</bits>
<field>prime</field>
<file>bn350.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn382</id>
<bits>382</bits>
<field>prime</field>
<file>bn382.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn414</id>
<bits>414</bits>
<field>prime</field>
<file>bn414.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn446</id>
<bits>446</bits>
<field>prime</field>
<file>bn446.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn478</id>
<bits>478</bits>
<field>prime</field>
<file>bn478.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn510</id>
<bits>510</bits>
<field>prime</field>
<file>bn510.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn542</id>
<bits>542</bits>
<field>prime</field>
<file>bn542.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn574</id>
<bits>574</bits>
<field>prime</field>
<file>bn574.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn606</id>
<bits>606</bits>
<field>prime</field>
<file>bn606.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
<curve>
<id>bn638</id>
<bits>638</bits>
<field>prime</field>
<file>bn638.csv</file>
+ <desc>Barreto-Naehrig curve from eprint 2010/429.</desc>
</curve>
</curves> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml
index 082f92c..0776b99 100644
--- a/src/cz/crcs/ectester/data/categories.xml
+++ b/src/cz/crcs/ectester/data/categories.xml
@@ -5,7 +5,7 @@
<category>
<name>anomalous</name>
<directory>anomalous</directory>
- <desc>These prime field curves have the same order as the field order, and are susceptible to attacks reducing ECDLP over a multiplicative group of the curve, to DLP over an additive group of the underlying field, which is easy (linear time).</desc>
+ <desc>These prime field curves have the same order as the field order. Some are from https://dspace.jaist.ac.jp/dspace/bitstream/10119/4464/1/73-61.pdf.</desc>
</category>
<category>
<name>brainpool</name>
@@ -43,6 +43,11 @@
<desc>Barreto-Naehrig curves from: A Family of Implementation-Friendly BN Elliptic Curves - https://eprint.iacr.org/2010/429.pdf.</desc>
</category>
<category>
+ <name>MNT</name>
+ <directory>mnt</directory>
+ <desc>MNT (Miyaji, Nakabayashi, and Takano) example curves from: New explicit conditions of elliptic curve traces for FR-reduction - https://dspace.jaist.ac.jp/dspace/bitstream/10119/4432/1/73-48.pdf.</desc>
+ </category>
+ <category>
<name>other</name>
<directory>other</directory>
<desc>An assortment of some other curves.</desc>
@@ -94,4 +99,9 @@
<directory>supersingular</directory>
<desc>Some supersingular curves, over F_p with order equal to p + 1.</desc>
</category>
+ <category>
+ <name>misc</name>
+ <directory>misc</directory>
+ <desc>Miscellaneous data.</desc>
+ </category>
</categories> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/misc/keys.xml b/src/cz/crcs/ectester/data/misc/keys.xml
new file mode 100644
index 0000000..e17b45b
--- /dev/null
+++ b/src/cz/crcs/ectester/data/misc/keys.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
+ <privkey>
+ <id>openssl-bug/skey</id>
+ <inline>0x4543A4D2C9DDD5516FD16D5498034C76D4EAB340276B6BAD8FF57756F4ECA8E6</inline>
+ <curve>secg/secp256r1</curve>
+ </privkey>
+ <pubkey>
+ <id>openssl-bug/pkey</id>
+ <inline>0x296D416994A4801B9A48E8C67C98E0C05DE1C0E85D4DC676F32FEACDC4998F0E,0xA91F9BE06C1D50EEB0295A35CA0F130F17EA647147626318E28AEC97F0653749</inline>
+ <curve>secg/secp256r1</curve>
+ </pubkey>
+
+ <pubkey>
+ <id>compression/128/non-residue</id>
+ <inline>0xb6707fa8afeddf79b9579e8dda4eaf51,0x000000000000000000000000000000</inline>
+ <curve>secg/secp128r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/160/non-residue</id>
+ <inline>0xb1cb90992ff28689c6f160dcfb51b9525492e3d9,0x0000000000000000000000000000000000000000</inline>
+ <curve>secg/secp160r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/192/non-residue</id>
+ <inline>0x8910baef94195e069c142b129e97507bfc2e19b53b707441,0x000000000000000000000000000000000000000000000000</inline>
+ <curve>secg/secp192r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/224/non-residue</id>
+ <inline>0xafd44b41555e8bea506518b35405d4f5be78355d6342e7f5287bd748,0x00000000000000000000000000000000000000000000000000000000</inline>
+ <curve>secg/secp224r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/256/non-residue</id>
+ <inline>0xeb7a88c476ede6ecae7909aa19631d9918762e851c38a3ea00fe50b7b2e2e656,0x0000000000000000000000000000000000000000000000000000000000000000</inline>
+ <curve>secg/secp256r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/384/non-residue</id>
+ <inline>0x45d50b222c11c0f20946133382a988caf2d4f64e669340ba60a5ab3151a6bf3883e7e77a6d358fd07db411bc8ad0f375,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</inline>
+ <curve>secg/secp384r1</curve>
+ </pubkey>
+ <pubkey>
+ <id>compression/521/non-residue</id>
+ <inline>0x1d7b127de8415bbf498c26f7a17c9e39dcd866b68359bc8e139f401f8ee8489419fb6166850c98cce7e1fdc620902961656d72f9b42703f06ccb9fe6e218e7e3fe3,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</inline>
+ <curve>secg/secp521r1</curve>
+ </pubkey>
+</keys>
diff --git a/src/cz/crcs/ectester/data/other/results.xml b/src/cz/crcs/ectester/data/misc/results.xml
index ba8c83c..ba8c83c 100644
--- a/src/cz/crcs/ectester/data/other/results.xml
+++ b/src/cz/crcs/ectester/data/misc/results.xml
diff --git a/src/cz/crcs/ectester/data/mnt/curves.xml b/src/cz/crcs/ectester/data/mnt/curves.xml
new file mode 100644
index 0000000..0087a5a
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/curves.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
+ <curve>
+ <id>mnt1</id>
+ <bits>170</bits>
+ <field>prime</field>
+ <file>mnt1.csv</file>
+ <desc>Example 1</desc>
+ </curve>
+ <curve>
+ <id>mnt2/1</id>
+ <bits>159</bits>
+ <field>prime</field>
+ <file>mnt2_1.csv</file>
+ <desc>Example 2/1</desc>
+ </curve>
+ <curve>
+ <id>mnt2/2</id>
+ <bits>159</bits>
+ <field>prime</field>
+ <file>mnt2_2.csv</file>
+ <desc>Example 2/2</desc>
+ </curve>
+ <curve>
+ <id>mnt3/1</id>
+ <bits>160</bits>
+ <field>prime</field>
+ <file>mnt3_1.csv</file>
+ <desc>Example 3/1</desc>
+ </curve>
+ <curve>
+ <id>mnt3/2</id>
+ <bits>160</bits>
+ <field>prime</field>
+ <file>mnt3_2.csv</file>
+ <desc>Example 3/2</desc>
+ </curve>
+ <curve>
+ <id>mnt3/3</id>
+ <bits>160</bits>
+ <field>prime</field>
+ <file>mnt3_3.csv</file>
+ <desc>Example 3/3</desc>
+ </curve>
+ <curve>
+ <id>mnt4</id>
+ <bits>240</bits>
+ <field>prime</field>
+ <file>mnt4.csv</file>
+ <desc>Example 4</desc>
+ </curve>
+ <curve>
+ <id>mnt5/1</id>
+ <bits>240</bits>
+ <field>prime</field>
+ <file>mnt5_1.csv</file>
+ <desc>Example 5/1</desc>
+ </curve>
+ <curve>
+ <id>mnt5/2</id>
+ <bits>240</bits>
+ <field>prime</field>
+ <file>mnt5_2.csv</file>
+ <desc>Example 5/2</desc>
+ </curve>
+ <curve>
+ <id>mnt5/3</id>
+ <bits>240</bits>
+ <field>prime</field>
+ <file>mnt5_3.csv</file>
+ <desc>Example 5/3</desc>
+ </curve>
+</curves> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt1.csv b/src/cz/crcs/ectester/data/mnt/mnt1.csv
new file mode 100644
index 0000000..7ff5784
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt1.csv
@@ -0,0 +1 @@
+0x26dccacc5041939206cf2b7dec50950e3c9fa4827af,0x22ffbb20cc052993fa27dc507800b624c650e4ff3d2,0x1c7be6fa8da953b5624efc72406af7fa77499803d08,0x25a3ae778f7ef6586abae5acde21e54b6c64edf33d0,0x05b4ace33aa53c670ce35535d6c273698a182da557d,0x0000a60fd646ad409b3312c3b23ba64e082ad7b354d,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt2_1.csv b/src/cz/crcs/ectester/data/mnt/mnt2_1.csv
new file mode 100644
index 0000000..a53376f
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt2_1.csv
@@ -0,0 +1 @@
+0x5affffffffffff4b46081000000059bb1bf600b7,0x3dd24a7e5c0bdfaccc215e22760469c73ee9d879,0x478c31a992b294e19f6e4416f958646dddede5e3,0x2725af3d7dea98cb9242ac6ddb9bd89bdcf38898,0x480b4184ed2c50c0230b4c73ca939c1b6b7f1103,0x5affffffffffff4b46081000000059bb1bf600b5,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt2_2.csv b/src/cz/crcs/ectester/data/mnt/mnt2_2.csv
new file mode 100644
index 0000000..20dd8f4
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt2_2.csv
@@ -0,0 +1 @@
+0x5affffffffffff4b46081000000059bb1bf600b7,0x07b29491c1a02cd87844f5098d0381f6c45d6523,0x41cc630bd66ac817d43358b108ad3d214037993c,0x0d76b3e1f1ed76a282fa99575d29ff2e587049e9,0x36e1557ed145ad409f924420e12f74a900fab054,0x5affffffffffff4b46081000000059bb1bf600b5,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt3_1.csv b/src/cz/crcs/ectester/data/mnt/mnt3_1.csv
new file mode 100644
index 0000000..d00719d
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt3_1.csv
@@ -0,0 +1 @@
+0x8afffffffffffeeb0fa77000000089f0dd49fac7,0x6d01fd0a017c62075ae999977379867e07f2a6d4,0x7701535c00fd965341d38bba4cfbdcf9a4651825,0x1781998103c3ca14ea76b9d3a700a53e1c784789,0x53352dde04447c25c9bb332a3c7634d3b8801f34,0x8afffffffffffeeb0fa77000000089f0dd49fac5,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt3_2.csv b/src/cz/crcs/ectester/data/mnt/mnt3_2.csv
new file mode 100644
index 0000000..86d8191
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt3_2.csv
@@ -0,0 +1 @@
+0x8afffffffffffeeb0fa77000000089f0dd49fac7,0x5fbe0085bd2b23afcd5b9c7704aeed2bfdbe89e4,0x3fd4005928c76d1fde3d12fa031f48c7fe7f0698,0x494e297179d42c761701ab03b2e5bca98a24dfe7,0x3274201d6596252a780390a222e3763bbecfe5f1,0x8afffffffffffeeb0fa77000000089f0dd49fac5,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt3_3.csv b/src/cz/crcs/ectester/data/mnt/mnt3_3.csv
new file mode 100644
index 0000000..348b30d
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt3_3.csv
@@ -0,0 +1 @@
+0x8afffffffffffeeb0fa77000000089f0dd49fac7,0x2ddf23acb05a91bda6ba9c20d7a584aa25075ce0,0x1f8125c46a31e79fd6cc25298b23ab130cd22b5a,0x3f710d05b65b5e16ae1b946d3fc582b16a927432,0x4a30945c64fd7f85e148ba816005468447616b1f,0x8afffffffffffeeb0fa77000000089f0dd49fac5,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt4.csv b/src/cz/crcs/ectester/data/mnt/mnt4.csv
new file mode 100644
index 0000000..ea5eaa1
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt4.csv
@@ -0,0 +1 @@
+0xa2ffffffffffffffffffffffffc298b00000000000000000000005c866cf,0x4be28760aa064734852cb4ff51ef2928a7a3cd75087c35cb1433714f7407,0x329704eb1c042f7858c878aa369f70c5c517de4e05a823dcb8224b8a4d5a,0x82556d57811807a0d7675674b3d57222cfbf9a2a2a2cd146572d7b67627e,0x73afacea28dc870baa1d5b0bd4300ddd975e2eefc7c2db508fc2e92a8345,0xa2ffffffffffffffffffffffffc298b00000000000000000000005c866cd,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt5_1.csv b/src/cz/crcs/ectester/data/mnt/mnt5_1.csv
new file mode 100644
index 0000000..2fd1622
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt5_1.csv
@@ -0,0 +1 @@
+0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271007,0xd149265d4687dcab1f2046e0947e51ac5e8e7f25916d35539d4df2e9017a,0x489e7783a1f584712bd4f6d48cf2d1ca2c975678936e639083991c5fc369,0x1d871a744f1e02ed15d7d84abd95e80476e6307085f12dba27092ff06d60,0x5c0c8bae9661303107b0077949dee16a7f6dde4982657b9196de23d9f9d0,0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271005,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt5_2.csv b/src/cz/crcs/ectester/data/mnt/mnt5_2.csv
new file mode 100644
index 0000000..18ec3a5
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt5_2.csv
@@ -0,0 +1 @@
+0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271007,0x26caaced434c5a4c2c9c1b09e0ddc167548a95516e7c81b20702485c9809,0x6031c89e2cdd91881dbd675beac3f3df8db1b8e0f45301215a01baf56ab3,0x16e55a2ef696238a7aaf19e51b6a81e1582f28b4bcb6575ab4e0331e569b,0x38de9844643fc9db3c568ec528983da16a177d56145a1d4bf88a2340d839,0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271005,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/mnt/mnt5_3.csv b/src/cz/crcs/ectester/data/mnt/mnt5_3.csv
new file mode 100644
index 0000000..73fce1d
--- /dev/null
+++ b/src/cz/crcs/ectester/data/mnt/mnt5_3.csv
@@ -0,0 +1 @@
+0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271007,0x44cfc0f3bc92ec82f818b443b564cf25dee3ebae7902e370f9e80283d3bd,0x2ddfd5f7d30c9daca565cd8278eddf6e9497f27450ac97a0a69aac57e27e,0xb071579c8cc322dc7fdce378e5b539b4b7580823aba3cfdd6637cbfa0bbb,0x15d1b75795732b1e2db1efa55cdbb19357e0aa0422cc03b442809339cf02,0xd2fffffffffffffffffffffffe9058d000000000000000000000a0271005,0x01 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/other/keys.xml b/src/cz/crcs/ectester/data/other/keys.xml
deleted file mode 100644
index d06de81..0000000
--- a/src/cz/crcs/ectester/data/other/keys.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="../schema.xsd">
- <privkey>
- <id>openssl-bug/skey</id>
- <inline>0x4543A4D2C9DDD5516FD16D5498034C76D4EAB340276B6BAD8FF57756F4ECA8E6</inline>
- <curve>secg/secp256r1</curve>
- </privkey>
- <pubkey>
- <id>openssl-bug/pkey</id>
- <inline>0x296D416994A4801B9A48E8C67C98E0C05DE1C0E85D4DC676F32FEACDC4998F0E,0xA91F9BE06C1D50EEB0295A35CA0F130F17EA647147626318E28AEC97F0653749</inline>
- <curve>secg/secp256r1</curve>
- </pubkey>
-</keys> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/wrong/results.xml b/src/cz/crcs/ectester/data/wrong/results.xml
index 92f43df..e3f0967 100644
--- a/src/cz/crcs/ectester/data/wrong/results.xml
+++ b/src/cz/crcs/ectester/data/wrong/results.xml
@@ -121,6 +121,42 @@
<desc>Well-formed invalid signature with s = 2 * p.</desc>
</sigResult>
<sigResult>
+ <id>nok/length_overflow16</id>
+ <sig>SHA1</sig>
+ <inline>0x3083ff000002203988322ab9f52c7f11d5d1aa92a2ac0b00275bcad8e934682257323fda672482022052231597382268e8f3b82b99e386ebb7c7db1a8b4a8bdacd496190314e4c5bad</inline>
+ <curve>secg/secp256r1</curve>
+ <signkey>wrong/default_priv</signkey>
+ <verifykey>wrong/default_pub</verifykey>
+ <desc>Invalid signature, that is shorter than specified in its ASN.1 SEQUENCE length header and its length overflows 16bits.</desc>
+ </sigResult>
+ <sigResult>
+ <id>nok/length_overflow32</id>
+ <sig>SHA1</sig>
+ <inline>0x3085ff0000000002203988322ab9f52c7f11d5d1aa92a2ac0b00275bcad8e934682257323fda672482022052231597382268e8f3b82b99e386ebb7c7db1a8b4a8bdacd496190314e4c5bad</inline>
+ <curve>secg/secp256r1</curve>
+ <signkey>wrong/default_priv</signkey>
+ <verifykey>wrong/default_pub</verifykey>
+ <desc>Invalid signature, that is shorter than specified in its ASN.1 SEQUENCE length header and its length overflows 32bits.</desc>
+ </sigResult>
+ <sigResult>
+ <id>nok/length_overflow64</id>
+ <sig>SHA1</sig>
+ <inline>0x3089ff000000000000000002203988322ab9f52c7f11d5d1aa92a2ac0b00275bcad8e934682257323fda672482022052231597382268e8f3b82b99e386ebb7c7db1a8b4a8bdacd496190314e4c5bad</inline>
+ <curve>secg/secp256r1</curve>
+ <signkey>wrong/default_priv</signkey>
+ <verifykey>wrong/default_pub</verifykey>
+ <desc>Invalid signature, that is shorter than specified in its ASN.1 SEQUENCE length header and its length overflows 64bits.</desc>
+ </sigResult>
+ <sigResult>
+ <id>nok/length_indefinite</id>
+ <sig>SHA1</sig>
+ <inline>0x308002203988322ab9f52c7f11d5d1aa92a2ac0b00275bcad8e934682257323fda672482022052231597382268e8f3b82b99e386ebb7c7db1a8b4a8bdacd496190314e4c5bad</inline>
+ <curve>secg/secp256r1</curve>
+ <signkey>wrong/default_priv</signkey>
+ <verifykey>wrong/default_pub</verifykey>
+ <desc>Invalid signature, with indefinite length.</desc>
+ </sigResult>
+ <sigResult>
<id>nok/long</id>
<sig>SHA1</sig>
<inline>0x30420220e641671e6415629dc8398e35ae1362cb647f293a92553b1594d57fff58df302c02206baafface035e3758eea0dd9ef734976c70b6dd06f4d81d33f5e28bfb8730624</inline>
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
index 921a9c8..e6835dd 100644
--- a/src/cz/crcs/ectester/reader/CardMngr.java
+++ b/src/cz/crcs/ectester/reader/CardMngr.java
@@ -331,7 +331,7 @@ public class CardMngr {
if (responseAPDU.getSW1() == (byte) 0x61) {
CommandAPDU apduToSend = new CommandAPDU((byte) 0x00,
(byte) 0xC0, (byte) 0x00, (byte) 0x00,
- responseAPDU.getSW1());
+ responseAPDU.getSW2());
responseAPDU = channel.transmit(apduToSend);
if (verbose)
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
index 0c04453..abc7264 100644
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ b/src/cz/crcs/ectester/reader/ECTesterReader.java
@@ -37,15 +37,19 @@ import cz.crcs.ectester.reader.output.FileTestWriter;
import cz.crcs.ectester.reader.output.ResponseWriter;
import cz.crcs.ectester.reader.response.Response;
import cz.crcs.ectester.reader.test.*;
+import javacard.framework.ISO7816;
import javacard.security.KeyPair;
import org.apache.commons.cli.*;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.smartcardio.CardException;
+import javax.smartcardio.ResponseAPDU;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
+import java.security.Security;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -141,14 +145,24 @@ public class ECTesterReader {
System.err.println(Colors.error("Failed to connect to card."));
System.exit(1);
}
- cardManager.send(SELECT_ECTESTERAPPLET);
+ ResponseAPDU selectResp = cardManager.send(SELECT_ECTESTERAPPLET);
+ if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) {
+ System.err.println(Colors.error("Failed to select ECTester applet, is it installed?"));
+ cardManager.disconnectFromCard();
+ System.exit(1);
+ }
}
- // Setup logger, testWriter and respWriter
+ // Setup logger and respWriter
logger = new OutputLogger(true, cfg.log);
-
respWriter = new ResponseWriter(logger.getPrintStream());
+ // Try adding the BouncyCastleProvider, which might be used in some parts of ECTester.
+ try {
+ Security.addProvider(new BouncyCastleProvider());
+ } catch (SecurityException | NoClassDefFoundError ignored) {
+ }
+
//do action
if (cli.hasOption("export")) {
export();
@@ -160,6 +174,8 @@ public class ECTesterReader {
ecdh();
} else if (cli.hasOption("ecdsa")) {
ecdsa();
+ } else if (cli.hasOption("info")) {
+ info();
}
//disconnect
@@ -232,6 +248,8 @@ public class ECTesterReader {
* -dh / --ecdh [count]]
* -dsa / --ecdsa [count]
* -ln / --list-named [obj]
+ * -ls / --list-suites
+ * -nfo / --info
*
* Options:
* -b / --bit-size <b> // -a / --all
@@ -272,12 +290,13 @@ public class ECTesterReader {
actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build());
+ actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").build());
actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build());
actions.addOption(Option.builder("g").longOpt("generate").desc("Generate <amount> of EC keys.").hasArg().argName("amount").optionalArg(true).build());
actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. Optionally specify a test number to run only a part of a test suite. <test_suite>:\n- default:\n- compression:\n- invalid:\n- twist:\n- degenerate:\n- cofactor:\n- wrong:\n- signature:\n- composite:\n- test-vectors:\n- edge-cases:\n- miscellaneous:").hasArg().argName("test_suite[:from[:to]]").optionalArg(true).build());
actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build());
actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build());
- actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").build());
+ actions.addOption(Option.builder("nf").longOpt("info").desc("Get applet info.").build());
opts.addOptionGroup(actions);
@@ -347,6 +366,15 @@ public class ECTesterReader {
}
}
+ private void info() throws CardException {
+ Response.GetInfo info = new Command.GetInfo(cardManager).send();
+ System.out.println(String.format("ECTester applet version: %s", info.getVersion()));
+ System.out.println(String.format("ECTester applet APDU support: %s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length"));
+ System.out.println(String.format("JavaCard API version: %.1f", info.getJavaCardVersion()));
+ System.out.println(String.format("JavaCard supports system cleanup: %s", info.getCleanupSupport()));
+ System.out.println(String.format("Array sizes (apduBuf, ram, ram2, apduArr): %d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
+ }
+
/**
* Exports default card/simulation EC domain parameters to output file.
*
@@ -405,13 +433,13 @@ public class ECTesterReader {
*/
private void generate() throws CardException, IOException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass).send();
respWriter.outputResponse(allocate);
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs);
- keysFile.write("index;time;pubW;privS\n");
+ keysFile.write("index;genTime;exportTime;pubW;privS\n");
int generated = 0;
int retry = 0;
@@ -423,10 +451,10 @@ public class ECTesterReader {
Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
Response.Generate response = generate.send();
- long elapsed = response.getDuration();
respWriter.outputResponse(response);
Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
+ respWriter.outputResponse(export);
if (!response.successful() || !export.successful()) {
if (retry < 10) {
@@ -440,7 +468,7 @@ public class ECTesterReader {
String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv);
+ String line = String.format("%d;%d;%d;%s;%s\n", generated, response.getDuration() / 1000000, export.getDuration() / 1000000, pub, priv);
keysFile.write(line);
keysFile.flush();
generated++;
@@ -533,10 +561,10 @@ public class ECTesterReader {
*/
private void ecdh() throws IOException, CardException {
byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
+ Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
List<Response> prepare = new LinkedList<>();
prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
if (curve != null)
prepare.add(curve.send());
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
index 5a4af21..a3560df 100644
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ b/src/cz/crcs/ectester/reader/command/Command.java
@@ -133,6 +133,9 @@ public abstract class Command implements Cloneable {
} else {
keypair = dataStore.getObject(EC_Keypair.class, cfg.namedKey);
}
+ if (keypair == null) {
+ throw new IOException("KeyPair not found.");
+ }
data = keypair.flatten();
if (data == null) {
@@ -155,6 +158,9 @@ public abstract class Command implements Cloneable {
pub = dataStore.getObject(EC_Keypair.class, cfg.namedPublicKey);
}
}
+ if (pub == null) {
+ throw new IOException("Public key not found.");
+ }
byte[] pubkey = pub.flatten(EC_Consts.PARAMETER_W);
if (pubkey == null) {
@@ -177,6 +183,9 @@ public abstract class Command implements Cloneable {
priv = dataStore.getObject(EC_Keypair.class, cfg.namedPrivateKey);
}
}
+ if (priv == null) {
+ throw new IOException("Private key not found.");
+ }
byte[] privkey = priv.flatten(EC_Consts.PARAMETER_S);
if (privkey == null) {
@@ -383,18 +392,7 @@ public abstract class Command implements Cloneable {
@Override
public String getDescription() {
- String name;
- switch (curve) {
- case EC_Consts.CURVE_default:
- name = "default";
- break;
- case EC_Consts.CURVE_external:
- name = "external";
- break;
- default:
- name = "custom";
- break;
- }
+ String name = CardUtil.getCurveName(curve);
String what = CardUtil.getParameterString(params);
String pair;
@@ -864,5 +862,33 @@ public abstract class Command implements Cloneable {
return "Request JCSystem object deletion";
}
}
+
+ /**
+ *
+ */
+ public static class GetInfo extends Command {
+
+ /**
+ * @param cardManager cardManager to send APDU through
+ */
+ public GetInfo(CardMngr cardManager) {
+ super(cardManager);
+
+ this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0);
+ }
+
+ @Override
+ public Response.GetInfo send() throws CardException {
+ long elapsed = -System.nanoTime();
+ ResponseAPDU response = cardManager.send(cmd);
+ elapsed += System.nanoTime();
+ return new Response.GetInfo(response, getDescription(), elapsed);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Get applet info";
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
index ad35012..e89d403 100644
--- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
@@ -1,5 +1,6 @@
package cz.crcs.ectester.reader.output;
+import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.common.cli.Colors;
import cz.crcs.ectester.common.output.BaseTextTestWriter;
import cz.crcs.ectester.common.test.TestSuite;
@@ -7,6 +8,7 @@ import cz.crcs.ectester.common.test.Testable;
import cz.crcs.ectester.common.util.ByteUtil;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
+import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
import cz.crcs.ectester.reader.test.CardTestSuite;
import cz.crcs.ectester.reader.test.CommandTestable;
@@ -43,9 +45,13 @@ public class TextTestWriter extends BaseTextTestWriter {
if (suite instanceof CardTestSuite) {
CardTestSuite cardSuite = (CardTestSuite) suite;
StringBuilder sb = new StringBuilder();
- sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
try {
+ sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator());
+ Response.GetInfo info = new Command.GetInfo(cardSuite.getCard()).send();
+ sb.append("═══ ").append(Colors.underline("ECTester applet version:")).append(" ").append(info.getVersion()).append(info.getBase() == ECTesterApplet.BASE_221 ? "" : " (extended length)").append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator());
+ sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator());
CardMngr.CPLC cplc = cardSuite.getCard().getCPLC();
if (!cplc.values().isEmpty()) {
sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator());
diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
index 00cc6c6..9add072 100644
--- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
@@ -108,6 +108,37 @@ public class XMLTestWriter extends BaseXMLTestWriter {
return result;
}
+ private Element appletElement(CardMngr card) {
+ Element result = doc.createElement("applet");
+ try {
+ Response.GetInfo info = new Command.GetInfo(card).send();
+ result.setAttribute("version", info.getVersion());
+ result.setAttribute("javacard", String.format("%.1f", info.getJavaCardVersion()));
+ result.setAttribute("base", String.format("%#x",info.getBase()));
+ result.setAttribute("cleanup", String.valueOf(info.getCleanupSupport()));
+ Element arrays = doc.createElement("arrays");
+ Element apduBuf = doc.createElement("length");
+ apduBuf.setAttribute("name", "apduBuf");
+ apduBuf.setTextContent(String.valueOf(info.getApduBufferLength()));
+ Element ramArray = doc.createElement("length");
+ ramArray.setAttribute("name", "ramArray");
+ ramArray.setTextContent(String.valueOf(info.getRamArrayLength()));
+ Element ramArray2 = doc.createElement("length");
+ ramArray2.setAttribute("name", "ramArray2");
+ ramArray2.setTextContent(String.valueOf(info.getRamArray2Length()));
+ Element apduArray = doc.createElement("length");
+ apduArray.setAttribute("name", "apduArray");
+ apduArray.setTextContent(String.valueOf(info.getApduArrayLength()));
+ arrays.appendChild(apduBuf);
+ arrays.appendChild(ramArray);
+ arrays.appendChild(ramArray2);
+ arrays.appendChild(apduArray);
+ result.appendChild(arrays);
+ } catch (CardException ignored) {
+ }
+ return result;
+ }
+
@Override
protected Element deviceElement(TestSuite suite) {
if (suite instanceof CardTestSuite) {
@@ -116,6 +147,7 @@ public class XMLTestWriter extends BaseXMLTestWriter {
result.setAttribute("type", "card");
result.setAttribute("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
result.appendChild(cplcElement(cardSuite.getCard()));
+ result.appendChild(appletElement(cardSuite.getCard()));
Element atr = doc.createElement("ATR");
atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
index 7c99a4a..56ecb71 100644
--- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
+++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
@@ -83,6 +83,25 @@ public class YAMLTestWriter extends BaseYAMLTestWriter {
return result;
}
+ private Map<String, Object> appletObject(CardMngr card) {
+ Map<String, Object> result = new LinkedHashMap<>();
+ try {
+ Response.GetInfo info = new Command.GetInfo(card).send();
+ result.put("version", info.getVersion());
+ result.put("javacard", info.getJavaCardVersion());
+ result.put("base", info.getBase());
+ result.put("cleanup", info.getCleanupSupport());
+ Map<String, Integer> arrays = new LinkedHashMap<>();
+ arrays.put("apduBuf", Short.toUnsignedInt(info.getApduBufferLength()));
+ arrays.put("ramArray", Short.toUnsignedInt(info.getRamArrayLength()));
+ arrays.put("ramArray2", Short.toUnsignedInt(info.getRamArray2Length()));
+ arrays.put("apduArray", Short.toUnsignedInt(info.getApduArrayLength()));
+ result.put("arrays", arrays);
+ } catch (CardException ignored) {
+ }
+ return result;
+ }
+
@Override
protected Map<String, Object> deviceObject(TestSuite suite) {
if (suite instanceof CardTestSuite) {
@@ -91,6 +110,7 @@ public class YAMLTestWriter extends BaseYAMLTestWriter {
result.put("type", "card");
result.put("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
result.put("cplc", cplcObject(cardSuite.getCard()));
+ result.put("applet", appletObject(cardSuite.getCard()));
result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
return result;
}
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
index 4814e41..235564e 100644
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ b/src/cz/crcs/ectester/reader/response/Response.java
@@ -79,6 +79,10 @@ public abstract class Response {
return resp;
}
+ public byte[] getData() {
+ return resp.getData();
+ }
+
public long getDuration() {
return time;
}
@@ -304,7 +308,7 @@ public abstract class Response {
if (pair == keyPair && param == mask) {
return index;
}
- if ((parameters & mask) != 0 && (pair & keyPair) != 0) {
+ if ((parameters & mask) != 0 && (pair & this.keyPair) != 0) {
if (mask == EC_Consts.PARAMETER_W) {
if ((key & EC_Consts.KEY_PUBLIC) != 0)
index++;
@@ -424,4 +428,78 @@ public abstract class Response {
parse(1, 0);
}
}
+
+ /**
+ *
+ */
+ public static class GetInfo extends Response {
+ private short base;
+ private short jcVersion;
+ private short cleanupSupport;
+ private short apduBufferLength;
+ private short ramArrayLength;
+ private short ramArray2Length;
+ private short apduArrayLength;
+
+ public GetInfo(ResponseAPDU response, String description, long time) {
+ super(response, description, time);
+
+ parse(1, 1);
+ int offset = 2 + 2 + getParamLength(0);
+ byte[] data = getData();
+ base = ByteUtil.getShort(data, offset);
+ offset += 2;
+ jcVersion = ByteUtil.getShort(data, offset);
+ offset += 2;
+ cleanupSupport = ByteUtil.getShort(data, offset);
+ offset += 2;
+ apduBufferLength = ByteUtil.getShort(data, offset);
+ offset += 2;
+ ramArrayLength = ByteUtil.getShort(data, offset);
+ offset += 2;
+ ramArray2Length = ByteUtil.getShort(data, offset);
+ offset += 2;
+ apduArrayLength = ByteUtil.getShort(data, offset);
+ }
+
+ public String getVersion() {
+ return new String(getParam(0));
+ }
+
+ public short getBase() {
+ return base;
+ }
+
+ public float getJavaCardVersion() {
+ byte major = (byte) (jcVersion >> 8);
+ byte minor = (byte) (jcVersion & 0xff);
+ int minorSize;
+ if (minor == 0) {
+ minorSize = 1;
+ } else {
+ minorSize = (int) Math.ceil(Math.log10(minor));
+ }
+ return (major + ((float) (minor) / (minorSize * 10)));
+ }
+
+ public boolean getCleanupSupport() {
+ return cleanupSupport == 1;
+ }
+
+ public short getApduBufferLength() {
+ return apduBufferLength;
+ }
+
+ public short getRamArrayLength() {
+ return ramArrayLength;
+ }
+
+ public short getRamArray2Length() {
+ return ramArray2Length;
+ }
+
+ public short getApduArrayLength() {
+ return apduArrayLength;
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
index 710b704..172c8af 100644
--- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
@@ -31,8 +31,8 @@ public class CardCofactorSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
@@ -46,7 +46,7 @@ public class CardCofactorSuite extends CardTestSuite {
for (EC_Key.Public pub : keys) {
Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
- Test objectEcdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh);
+ Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh);
Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup.");
ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", objectEcdh, rawEcdh));
diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
index 336b371..4bf9290 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
@@ -37,8 +37,8 @@ public class CardCompositeSuite extends CardTestSuite {
* is revealed.
*/
Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite");
- List<Map.Entry<EC_Curve, List<EC_Key>>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
- for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys) {
+ Map<EC_Curve, List<EC_Key>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys.entrySet()) {
EC_Curve curve = curveKeys.getKey();
List<Test> tests = new LinkedList<>();
Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
@@ -59,35 +59,35 @@ public class CardCompositeSuite extends CardTestSuite {
Map<String, EC_Curve> results = EC_Store.getInstance().getObjects(EC_Curve.class, "composite");
- List<Map.Entry<String, List<EC_Curve>>> groupList = EC_Store.mapToPrefix(results.values());
+ Map<String, List<EC_Curve>> groups = EC_Store.mapToPrefix(results.values());
/* Test the whole curves with both keypairs generated on card(no small-order public points provided).
*/
- List<EC_Curve> wholeCurves = groupList.stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
+ List<EC_Curve> wholeCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
testGroup(wholeCurves, "Composite generator order", ExpectedValue.FAILURE, "Card rejected to do ECDH with composite order generator.", "Card did not reject to do ECDH with composite order generator.");
/* Also test having a G of small order, so small R.
*/
- List<EC_Curve> smallRCurves = groupList.stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
+ List<EC_Curve> smallRCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
testGroup(smallRCurves, "Small generator order", ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a small order generator.", "Card incorrectly does ECDH over a small order generator.");
/* Test increasingly larger prime R, to determine where/if card behavior changes.
*/
- List<EC_Curve> varyingCurves = groupList.stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
+ List<EC_Curve> varyingCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
testGroup(varyingCurves, null, ExpectedValue.ANY, "", "");
/* Also test having a G of large but composite order, R = p * q,
*/
- List<EC_Curve> pqCurves = groupList.stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
+ List<EC_Curve> pqCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
testGroup(pqCurves, null, ExpectedValue.ANY, "", "");
/* Also test having G or large order being a Carmichael pseudoprime, R = p * q * r,
*/
- List<EC_Curve> ppCurves = groupList.stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
+ List<EC_Curve> ppCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
testGroup(ppCurves, "Generator order = Carmichael pseudoprime", ExpectedValue.ANY, "", "");
/* Also test rg0 curves.
*/
- List<EC_Curve> rg0Curves = groupList.stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
+ List<EC_Curve> rg0Curves = groups.entrySet().stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
testGroup(rg0Curves, null, ExpectedValue.ANY, "", "");
}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
index ae25bf1..291cc04 100644
--- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
@@ -2,6 +2,8 @@ package cz.crcs.ectester.reader.test;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.common.ec.EC_Curve;
+import cz.crcs.ectester.common.ec.EC_Key;
import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.CompoundTest;
import cz.crcs.ectester.common.test.Result;
@@ -9,6 +11,7 @@ import cz.crcs.ectester.common.test.Test;
import cz.crcs.ectester.common.util.ByteUtil;
import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
@@ -18,6 +21,7 @@ import javacard.security.KeyPair;
import java.security.spec.ECPoint;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* @author Jan Jancar johny@neuromancer.sk
@@ -51,6 +55,10 @@ public class CardCompressionSuite extends CardTestSuite {
if (cfg.binaryField) {
runCompression(KeyPair.ALG_EC_F2M);
}
+
+ // Now, do ECDH over SECG curves and give the implementation a compressed key that is not a quadratic residue in
+ // decompression.
+ runNonResidue();
}
private void runCompression(byte field) throws Exception {
@@ -59,27 +67,28 @@ public class CardCompressionSuite extends CardTestSuite {
for (short keyLength : keySizes) {
String spec = keyLength + "b " + CardUtil.getKeyTypeString(field);
+ byte curveId = EC_Consts.getCurve(keyLength, field);
Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS));
if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + spec + ".", allocateFirst));
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for compression test on " + spec + ".", allocateFirst));
continue;
}
List<Test> compressionTests = new LinkedList<>();
compressionTests.add(allocateFirst);
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), Result.ExpectedValue.SUCCESS));
+ Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curveId, domain, null), Result.ExpectedValue.SUCCESS));
Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
compressionTests.add(setCustom);
compressionTests.add(genCustom);
Response.Export key = new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
byte[] pubkey = key.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC);
+ EC_Curve secgCurve = EC_Store.getInstance().getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
ECPoint pub;
try {
- pub = ECUtil.fromX962(pubkey, null);
+ pub = ECUtil.fromX962(pubkey, secgCurve.toCurve());
} catch (IllegalArgumentException iae) {
- // TODO: use external SECG curves so we have them here.
doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "", compressionTests.toArray(new Test[0])));
continue;
}
@@ -119,4 +128,26 @@ public class CardCompressionSuite extends CardTestSuite {
doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0])));
}
}
+
+ private void runNonResidue() {
+ Map<String, EC_Key.Public> otherKeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "misc");
+ List<EC_Key.Public> compressionKeys = EC_Store.mapToPrefix(otherKeys.values()).get("compression");
+
+ for (EC_Key.Public key : compressionKeys) {
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
+ List<Test> tests = new LinkedList<>();
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for non-residue test on " + curve.getBits() + "b " + curve.getId() + ".", allocate));
+ continue;
+ }
+ tests.add(allocate);
+ tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
+ tests.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
+ byte[] pointData = ECUtil.toX962Compressed(key.getParam(EC_Consts.PARAMETER_W));
+ byte[] pointDataEncoded = ByteUtil.prependLength(pointData);
+ tests.add(CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pointDataEncoded), Result.ExpectedValue.FAILURE));
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Non-residue test of " + curve.getId() + ".", tests.toArray(new Test[0])));
+ }
+ }
}
diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
index e495b00..91f9ef6 100644
--- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
@@ -10,6 +10,7 @@ import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
+import cz.crcs.ectester.reader.response.Response;
import javacard.security.KeyPair;
import java.util.LinkedList;
diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
index c926a4d..f434d4d 100644
--- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
@@ -31,8 +31,8 @@ public class CardDegenerateSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "degenerate");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
index b68b2ec..ccec401 100644
--- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
@@ -39,8 +39,8 @@ public class CardEdgeCasesSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "wycheproof");
- List<Map.Entry<String, List<EC_KAResult>>> groupList = EC_Store.mapToPrefix(results.values());
- for (Map.Entry<String, List<EC_KAResult>> e : groupList) {
+ Map<String, List<EC_KAResult>> groups = EC_Store.mapToPrefix(results.values());
+ for (Map.Entry<String, List<EC_KAResult>> e : groups.entrySet()) {
String description = null;
switch (e.getKey()) {
case "addsub":
@@ -55,8 +55,8 @@ public class CardEdgeCasesSuite extends CardTestSuite {
}
List<Test> groupTests = new LinkedList<>();
- List<Map.Entry<EC_Curve, List<EC_KAResult>>> curveList = EC_Store.mapResultToCurve(e.getValue());
- for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList) {
+ Map<EC_Curve, List<EC_KAResult>> curveList = EC_Store.mapResultToCurve(e.getValue());
+ for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList.entrySet()) {
EC_Curve curve = c.getKey();
List<Test> curveTests = new LinkedList<>();
@@ -111,7 +111,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
}
{
- EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "other", "openssl-bug");
+ EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "misc", "openssl-bug");
EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, openssl_bug.getCurve());
EC_Key.Private skey = EC_Store.getInstance().getObject(EC_Key.Private.class, openssl_bug.getOtherKey());
EC_Key.Public pkey = EC_Store.getInstance().getObject(EC_Key.Public.class, openssl_bug.getOneKey());
@@ -145,7 +145,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
for (EC_Curve curve : curves) {
Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b ALG_EC_FP.", key));
+ doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + curve.getId() + ".", key));
continue;
}
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
@@ -238,7 +238,7 @@ public class CardEdgeCasesSuite extends CardTestSuite {
Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, secp160r1.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b ALG_EC_FP.", key));
+ doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b secp160r1.", key));
return;
}
Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, secp160r1.getParams(), secp160r1.flatten()), Result.ExpectedValue.SUCCESS);
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
index 17c5d4b..3b9e0e5 100644
--- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
@@ -35,8 +35,8 @@ public class CardInvalidSuite extends CardTestSuite {
* Try ECDH with invalid public keys of increasing order.
*/
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
index 8623e36..a2ce2ce 100644
--- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
@@ -7,12 +7,14 @@ import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.CompoundTest;
import cz.crcs.ectester.common.test.Result;
import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -21,7 +23,9 @@ import java.util.Map;
public class CardMiscSuite extends CardTestSuite {
public CardMiscSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves and some Barreto-Naehrig curves with small embedding degree and CM discriminant.");
+ super(writer, cfg, cardManager, "miscellaneous", "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves,",
+ "Barreto-Naehrig curves with small embedding degree and CM discriminant, MNT curves,",
+ "some Montgomery curves transformed to short Weierstrass form and Curve25519 transformed to short Weierstrass form.");
}
@Override
@@ -29,32 +33,45 @@ public class CardMiscSuite extends CardTestSuite {
Map<String, EC_Curve> anCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "anomalous");
Map<String, EC_Curve> ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular");
Map<String, EC_Curve> bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig");
+ Map<String, EC_Curve> mntCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "MNT");
+ List<EC_Curve> mCurves = new ArrayList<>();
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-221"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-383"));
+ mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-511"));
+ EC_Curve curve25519 = EC_Store.getInstance().getObject(EC_Curve.class, "other", "Curve25519");
- testCurves(anCurves, "anomalous", Result.ExpectedValue.FAILURE);
- testCurves(ssCurves, "supersingular", Result.ExpectedValue.FAILURE);
- testCurves(bnCurves, "Barreto-Naehrig", Result.ExpectedValue.ANY);
+ testCurves(anCurves.values(), "anomalous", Result.ExpectedValue.FAILURE);
+ testCurves(ssCurves.values(), "supersingular", Result.ExpectedValue.FAILURE);
+ testCurves(bnCurves.values(), "Barreto-Naehrig", Result.ExpectedValue.SUCCESS);
+ testCurves(mntCurves.values(), "MNT", Result.ExpectedValue.SUCCESS);
+ testCurves(mCurves, "Montgomery", Result.ExpectedValue.SUCCESS);
+ testCurve(curve25519, "Montgomery", Result.ExpectedValue.SUCCESS);
}
- private void testCurves(Map<String, EC_Curve> curves, String catName, Result.ExpectedValue expected) throws Exception {
- for (EC_Curve curve : curves.values()) {
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocateFirst));
- continue;
- }
+ private void testCurve(EC_Curve curve, String catName, Result.ExpectedValue expected) {
+ Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
+ if (!allocateFirst.ok()) {
+ doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst));
+ return;
+ }
+
+ Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
+ Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.ANY);
+ Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected);
+ Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected);
+ Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ka, sig);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.ANY);
- Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected);
- Test sig = CommandTest.expect(new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected);
- Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA", ka, sig);
+ if (cfg.cleanup) {
+ Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
+ } else {
+ doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
+ }
+ }
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
- } else {
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + " " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
- }
+ private void testCurves(Collection<EC_Curve> curves, String catName, Result.ExpectedValue expected) {
+ for (EC_Curve curve : curves) {
+ testCurve(curve, catName, expected);
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
index 59def74..20546c8 100644
--- a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
@@ -28,16 +28,16 @@ public class CardSignatureSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_SigResult> results = EC_Store.getInstance().getObjects(EC_SigResult.class, "wrong");
- List<Map.Entry<String, List<EC_SigResult>>> groupList = EC_Store.mapToPrefix(results.values());
+ Map<String, List<EC_SigResult>> groups = EC_Store.mapToPrefix(results.values());
- List<EC_SigResult> nok = groupList.stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
+ List<EC_SigResult> nok = groups.entrySet().stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
byte[] data = "Some stuff that is not the actual data".getBytes();
for (EC_SigResult sig : nok) {
ecdsaTest(sig, Result.ExpectedValue.FAILURE, data);
}
- List<EC_SigResult> ok = groupList.stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
+ List<EC_SigResult> ok = groups.entrySet().stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
for (EC_SigResult sig : ok) {
ecdsaTest(sig, Result.ExpectedValue.SUCCESS, null);
}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
index fbdf103..3abcebb 100644
--- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
@@ -9,16 +9,28 @@ import cz.crcs.ectester.common.test.Result;
import cz.crcs.ectester.common.test.Test;
import cz.crcs.ectester.common.test.TestCallback;
import cz.crcs.ectester.common.util.ByteUtil;
+import cz.crcs.ectester.common.util.CardUtil;
+import cz.crcs.ectester.common.util.ECUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.reader.CardMngr;
import cz.crcs.ectester.reader.ECTesterReader;
import cz.crcs.ectester.reader.command.Command;
import cz.crcs.ectester.reader.response.Response;
+import javacard.security.KeyPair;
+import javax.crypto.KeyAgreement;
import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import static cz.crcs.ectester.common.test.Result.ExpectedValue;
import static cz.crcs.ectester.common.test.Result.Value;
@@ -52,8 +64,13 @@ public class CardTestVectorSuite extends CardTestSuite {
throw new IOException("Test vector keys couldn't be located.");
}
List<Test> testVector = new LinkedList<>();
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
+ continue;
+ }
- testVector.add(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ testVector.add(allocate);
testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
@@ -75,7 +92,89 @@ public class CardTestVectorSuite extends CardTestSuite {
if (cfg.cleanup) {
testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY));
}
- doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0])));
+ doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId() + ".", testVector.toArray(new Test[0])));
+ }
+
+ KeyAgreement ka;
+ KeyFactory kf;
+ MessageDigest md;
+ try {
+ ka = KeyAgreement.getInstance("ECDH", "BC");
+ kf = KeyFactory.getInstance("ECDH", "BC");
+ md = MessageDigest.getInstance("SHA1", "BC");
+ } catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
+ return;
+ }
+
+ List<EC_Curve> testCurves = new ArrayList<>();
+ testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "secg").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList()));
+ testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "brainpool").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList()));
+ for (EC_Curve curve : testCurves) {
+ List<Test> testVector = new LinkedList<>();
+ Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
+ if (!allocate.ok()) {
+ doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
+ continue;
+ }
+ testVector.add(allocate);
+ testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
+ testVector.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
+ CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR), ExpectedValue.ANY);
+ testVector.add(export);
+ TestCallback<CommandTestable> kaCallback = new TestCallback<CommandTestable>() {
+ @Override
+ public Result apply(CommandTestable testable) {
+ Response.ECDH ecdhData = (Response.ECDH) testable.getResponse();
+ if (!ecdhData.successful())
+ return new Result(Value.FAILURE, "ECDH was unsuccessful.");
+ if (!ecdhData.hasSecret()) {
+ return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
+ }
+ byte[] secret = ecdhData.getSecret();
+ Response.Export keyData = (Response.Export) export.getResponse();
+ byte[] pkey = keyData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
+ byte[] skey = keyData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S);
+ ECParameterSpec spec = curve.toSpec();
+ ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec);
+ ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec);
+ PrivateKey privKey;
+ PublicKey pubkey;
+ try {
+ privKey = kf.generatePrivate(privKeySpec);
+ pubkey = kf.generatePublic(pubKeySpec);
+ ka.init(privKey);
+ ka.doPhase(pubkey, true);
+ byte[] rawDerived = ka.generateSecret();
+ int fieldSize = (curve.getBits() + 7) / 8;
+ if (rawDerived.length < fieldSize) {
+ byte[] padded = new byte[fieldSize];
+ System.arraycopy(rawDerived, 0, padded, fieldSize - rawDerived.length, rawDerived.length);
+ rawDerived = padded;
+ }
+ byte[] derived = md.digest(rawDerived);
+ if (secret.length != derived.length) {
+ if (secret.length < derived.length) {
+ return new Result(Value.FAILURE, String.format("Derived secret was shorter than expected: %d vs %d (expected).", secret.length, derived.length));
+ } else {
+ return new Result(Value.FAILURE, String.format("Derived secret was longer than expected: %d vs %d (expected).", secret.length, derived.length));
+ }
+ }
+ int diff = ByteUtil.diffBytes(derived, 0, secret, 0, secret.length);
+ if (diff == secret.length) {
+ return new Result(Value.SUCCESS, "Derived secret matched expected value.");
+ } else {
+ return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + String.valueOf(diff) + ".");
+ }
+ } catch (InvalidKeySpecException | InvalidKeyException ex) {
+ return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage());
+ }
+ }
+ };
+ testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback));
+ if (cfg.cleanup) {
+ testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY));
+ }
+ doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Validation test on " + curve.getId() + ".", testVector.toArray(new Test[0])));
}
}
}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
index 6ad4ce6..3df4c65 100644
--- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
+++ b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
@@ -29,8 +29,8 @@ public class CardTwistSuite extends CardTestSuite {
@Override
protected void runTests() throws Exception {
Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
- List<Map.Entry<EC_Curve, List<EC_Key.Public>>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList) {
+ Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
+ for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
EC_Curve curve = e.getKey();
List<EC_Key.Public> keys = e.getValue();
diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
index 1d7b821..e19377d 100644
--- a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
+++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java
@@ -28,6 +28,7 @@ import cz.crcs.ectester.common.output.TestWriter;
import cz.crcs.ectester.common.test.TestException;
import cz.crcs.ectester.common.util.ByteUtil;
import cz.crcs.ectester.common.util.ECUtil;
+import cz.crcs.ectester.common.util.FileUtil;
import cz.crcs.ectester.data.EC_Store;
import cz.crcs.ectester.standalone.consts.KeyAgreementIdent;
import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent;
@@ -49,6 +50,7 @@ import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.PrintStream;
import java.nio.file.Files;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
@@ -66,7 +68,17 @@ import java.util.stream.Collectors;
* @version v0.3.0
*/
public class ECTesterStandalone {
- private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib(), new CryptoppLib(), new OpensslLib(), new MscngLib()};
+ private ProviderECLibrary[] libs = new ProviderECLibrary[]{
+ new SunECLib(),
+ new BouncyCastleLib(),
+ new TomcryptLib(),
+ new BotanLib(),
+ new CryptoppLib(),
+ new OpensslLib(),
+ new BoringsslLib(),
+ new GcryptLib(),
+ new MscngLib(),
+ new WolfCryptLib()};
private Config cfg;
private Options opts = new Options();
@@ -140,6 +152,7 @@ public class ECTesterStandalone {
Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").optionalArg(false).build();
Option curveName = Option.builder("cn").longOpt("curve-name").desc("Use a named curve, search from curves supported by the library: <name>").hasArg().argName("name").optionalArg(false).build();
Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build();
+ Option output = Option.builder("o").longOpt("output").desc("Output into file <output_file>.").hasArgs().argName("output_file").optionalArg(false).build();
Options testOpts = new Options();
testOpts.addOption(bits);
@@ -159,9 +172,12 @@ public class ECTesterStandalone {
ecdhOpts.addOption(bits);
ecdhOpts.addOption(namedCurve);
ecdhOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build());
ecdhOpts.addOption(Option.builder().longOpt("key-type").desc("Set the key [algorithm] for which the key should be derived in KeyAgreements with KDF. Default is \"AES\".").hasArg().argName("algorithm").optionalArg(false).build());
ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build());
+ ecdhOpts.addOption(Option.builder().longOpt("fixed-private").desc("Perform ECDH with fixed private key.").build());
+ ecdhOpts.addOption(Option.builder().longOpt("fixed-public").desc("Perform ECDH with fixed public key.").build());
ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts, "Perform EC based KeyAgreement.");
actions.put("ecdh", ecdh);
@@ -169,6 +185,7 @@ public class ECTesterStandalone {
ecdsaOpts.addOption(bits);
ecdsaOpts.addOption(namedCurve);
ecdsaOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build());
ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build());
ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build());
@@ -179,6 +196,7 @@ public class ECTesterStandalone {
generateOpts.addOption(bits);
generateOpts.addOption(namedCurve);
generateOpts.addOption(curveName);
+ ecdhOpts.addOption(output);
generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build());
generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build());
ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts, "Generate EC keypairs.");
@@ -186,6 +204,7 @@ public class ECTesterStandalone {
Options exportOpts = new Options();
exportOpts.addOption(bits);
+ ecdhOpts.addOption(output);
exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build());
ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts, "Export default curve parameters.");
actions.put("export", export);
@@ -222,6 +241,7 @@ public class ECTesterStandalone {
for (ProviderECLibrary lib : libs) {
if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) {
System.out.println("\t- " + Colors.bold(lib.name()));
+ System.out.println(Colors.bold("\t\t- Supports native timing: ") + lib.supportsNativeTiming());
Set<KeyPairGeneratorIdent> kpgs = lib.getKPGs();
if (!kpgs.isEmpty()) {
System.out.println(Colors.bold("\t\t- KeyPairGenerators: ") + String.join(", ", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList())));
@@ -259,7 +279,7 @@ public class ECTesterStandalone {
/**
*
*/
- private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
+ private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, FileNotFoundException {
ProviderECLibrary lib = cfg.selected;
String algo = cli.getOptionValue("ecdh.type", "ECDH");
@@ -292,63 +312,90 @@ public class ECTesterStandalone {
if (kaIdent == null || kpIdent == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- KeyAgreement ka = kaIdent.getInstance(lib.getProvider());
- KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
- AlgorithmParameterSpec spec = null;
- if (cli.hasOption("ecdh.bits")) {
- int bits = Integer.parseInt(cli.getOptionValue("ecdh.bits"));
- kpg.initialize(bits);
- } else if (cli.hasOption("ecdh.named-curve")) {
- String curveName = cli.getOptionValue("ecdh.named-curve");
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
- if (curve == null) {
- System.err.println("Curve not found: " + curveName);
- return;
- }
- spec = curve.toSpec();
- kpg.initialize(spec);
- } else if (cli.hasOption("ecdh.curve-name")) {
- String curveName = cli.getOptionValue("ecdh.curve-name");
- spec = new ECGenParameterSpec(curveName);
- kpg.initialize(spec);
+ }
+
+ KeyAgreement ka = kaIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ AlgorithmParameterSpec spec = null;
+ if (cli.hasOption("ecdh.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdh.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdh.named-curve")) {
+ String curveName = cli.getOptionValue("ecdh.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
}
+ spec = curve.toSpec();
+ kpg.initialize(spec);
+ } else if (cli.hasOption("ecdh.curve-name")) {
+ String curveName = cli.getOptionValue("ecdh.curve-name");
+ spec = new ECGenParameterSpec(curveName);
+ kpg.initialize(spec);
+ }
- System.out.println("index;nanotime;pubW;privS;secret");
+ PrintStream out;
+ if (cli.hasOption("ecdh.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- KeyPair one = kpg.genKeyPair();
- KeyPair other = kpg.genKeyPair();
+ out.println("index;time[nano];pubW;privS;secret");
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) other.getPublic();
+ KeyPair one = null;
+ if (cli.hasOption("ecdh.fixed-private")) {
+ one = kpg.genKeyPair();
+ }
+ KeyPair other = null;
+ if (cli.hasOption("ecdh.fixed-public")) {
+ other = kpg.genKeyPair();
+ }
- long elapsed = -System.nanoTime();
- if (spec != null) {
- ka.init(privkey, spec);
- } else {
- ka.init(privkey);
- }
- ka.doPhase(pubkey, true);
- elapsed += System.nanoTime();
- SecretKey derived;
- byte[] result;
- elapsed -= System.nanoTime();
- if (kaIdent.requiresKeyAlgo()) {
- derived = ka.generateSecret(keyAlgo);
- result = derived.getEncoded();
- } else {
- result = ka.generateSecret();
- }
- elapsed += System.nanoTime();
- ka = kaIdent.getInstance(lib.getProvider());
+ int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ if (!cli.hasOption("ecdh.fixed-private")) {
+ one = kpg.genKeyPair();
+ }
+ if (!cli.hasOption("ecdh.fixed-public")) {
+ other = kpg.genKeyPair();
+ }
+
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) other.getPublic();
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
- String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
- String dh = ByteUtil.bytesToHex(result, false);
- System.out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
+ long elapsed = -System.nanoTime();
+ if (spec instanceof ECParameterSpec) {
+ ka.init(privkey, spec);
+ } else {
+ ka.init(privkey);
}
+ ka.doPhase(pubkey, true);
+ elapsed += System.nanoTime();
+ SecretKey derived;
+ byte[] result;
+ elapsed -= System.nanoTime();
+ if (kaIdent.requiresKeyAlgo()) {
+ derived = ka.generateSecret(keyAlgo);
+ result = derived.getEncoded();
+ } else {
+ result = ka.generateSecret();
+ }
+ elapsed += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ elapsed = lib.getLastNativeTiming();
+ }
+ ka = kaIdent.getInstance(lib.getProvider());
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String dh = ByteUtil.bytesToHex(result, false);
+ out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh));
+ }
+
+ if (cli.hasOption("ecdh.output")) {
+ out.close();
}
}
@@ -405,61 +452,76 @@ public class ECTesterStandalone {
if (sigIdent == null || kpIdent == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- Signature sig = sigIdent.getInstance(lib.getProvider());
- KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
- if (cli.hasOption("ecdsa.bits")) {
- int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits"));
- kpg.initialize(bits);
- } else if (cli.hasOption("ecdsa.named-curve")) {
- String curveName = cli.getOptionValue("ecdsa.named-curve");
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
- if (curve == null) {
- System.err.println("Curve not found: " + curveName);
- return;
- }
- kpg.initialize(curve.toSpec());
- } else if (cli.hasOption("ecdsa.curve-name")) {
- String curveName = cli.getOptionValue("ecdsa.curve-name");
- kpg.initialize(new ECGenParameterSpec(curveName));
+ }
+ Signature sig = sigIdent.getInstance(lib.getProvider());
+ KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider());
+ if (cli.hasOption("ecdsa.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("ecdsa.named-curve")) {
+ String curveName = cli.getOptionValue("ecdsa.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
}
+ kpg.initialize(curve.toSpec());
+ } else if (cli.hasOption("ecdsa.curve-name")) {
+ String curveName = cli.getOptionValue("ecdsa.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
- System.out.println("index;data;signtime;verifytime;pubW;privS;signature;verified");
-
- int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- KeyPair one = kpg.genKeyPair();
+ PrintStream out;
+ if (cli.hasOption("ecdsa.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
- ECPublicKey pubkey = (ECPublicKey) one.getPublic();
+ out.println("index;data;signTime[nano];verifyTime[nano];pubW;privS;signature;verified");
- sig.initSign(privkey);
- sig.update(data);
+ int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1"));
+ for (int i = 0; i < amount; ++i) {
+ KeyPair one = kpg.genKeyPair();
- long signTime = -System.nanoTime();
- byte[] signature = sig.sign();
- signTime += System.nanoTime();
+ ECPrivateKey privkey = (ECPrivateKey) one.getPrivate();
+ ECPublicKey pubkey = (ECPublicKey) one.getPublic();
- sig.initVerify(pubkey);
- sig.update(data);
+ sig.initSign(privkey);
+ sig.update(data);
- long verifyTime = -System.nanoTime();
- boolean verified = sig.verify(signature);
- verifyTime += System.nanoTime();
+ long signTime = -System.nanoTime();
+ byte[] signature = sig.sign();
+ signTime += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ signTime = lib.getLastNativeTiming();
+ }
+ sig.initVerify(pubkey);
+ sig.update(data);
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
- String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
- String sign = ByteUtil.bytesToHex(signature, false);
- System.out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ long verifyTime = -System.nanoTime();
+ boolean verified = sig.verify(signature);
+ verifyTime += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ verifyTime = lib.getLastNativeTiming();
}
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false);
+ String sign = ByteUtil.bytesToHex(signature, false);
+ out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0));
+ }
+
+ if (cli.hasOption("ecdsa.output")) {
+ out.close();
}
}
/**
*
*/
- private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, FileNotFoundException {
ProviderECLibrary lib = cfg.selected;
KeyPairGeneratorIdent ident = null;
String algo = cli.getOptionValue("generate.type", "EC");
@@ -471,37 +533,51 @@ public class ECTesterStandalone {
}
if (ident == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
- if (cli.hasOption("generate.bits")) {
- int bits = Integer.parseInt(cli.getOptionValue("generate.bits"));
- kpg.initialize(bits);
- } else if (cli.hasOption("generate.named-curve")) {
- String curveName = cli.getOptionValue("generate.named-curve");
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
- if (curve == null) {
- System.err.println("Curve not found: " + curveName);
- return;
- }
- kpg.initialize(curve.toSpec());
- } else if (cli.hasOption("generate.curve-name")) {
- String curveName = cli.getOptionValue("generate.curve-name");
- kpg.initialize(new ECGenParameterSpec(curveName));
+ }
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("generate.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("generate.bits"));
+ kpg.initialize(bits);
+ } else if (cli.hasOption("generate.named-curve")) {
+ String curveName = cli.getOptionValue("generate.named-curve");
+ EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName);
+ if (curve == null) {
+ System.err.println("Curve not found: " + curveName);
+ return;
}
- System.out.println("index;nanotime;pubW;privS");
+ kpg.initialize(curve.toSpec());
+ } else if (cli.hasOption("generate.curve-name")) {
+ String curveName = cli.getOptionValue("generate.curve-name");
+ kpg.initialize(new ECGenParameterSpec(curveName));
+ }
- int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1"));
- for (int i = 0; i < amount; ++i) {
- long elapsed = -System.nanoTime();
- KeyPair kp = kpg.genKeyPair();
- elapsed += System.nanoTime();
- ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
- ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+ PrintStream out;
+ if (cli.hasOption("generate.output")) {
+ out = new PrintStream(FileUtil.openStream(cli.getOptionValues("ecdh.output")));
+ } else {
+ out = System.out;
+ }
- String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
- String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
- System.out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
+ out.println("index;time[nano];pubW;privS");
+
+ int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1"));
+ for (int i = 0; i < amount || amount == 0; ++i) {
+ long elapsed = -System.nanoTime();
+ KeyPair kp = kpg.genKeyPair();
+ elapsed += System.nanoTime();
+ if (lib.supportsNativeTiming()) {
+ elapsed = lib.getLastNativeTiming();
}
+ ECPublicKey publicKey = (ECPublicKey) kp.getPublic();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+
+ String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false);
+ String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false);
+ out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv));
+ }
+
+ if (cli.hasOption("generate.output")) {
+ out.close();
}
}
@@ -545,19 +621,18 @@ public class ECTesterStandalone {
}
if (ident == null) {
throw new NoSuchAlgorithmException(algo);
- } else {
- KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
- if (cli.hasOption("export.bits")) {
- int bits = Integer.parseInt(cli.getOptionValue("export.bits"));
- kpg.initialize(bits);
- }
- KeyPair kp = kpg.genKeyPair();
- ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
- ECParameterSpec params = privateKey.getParams();
- System.out.println(params);
- EC_Curve curve = EC_Curve.fromSpec(params);
- curve.writeCSV(System.out);
}
+ KeyPairGenerator kpg = ident.getInstance(lib.getProvider());
+ if (cli.hasOption("export.bits")) {
+ int bits = Integer.parseInt(cli.getOptionValue("export.bits"));
+ kpg.initialize(bits);
+ }
+ KeyPair kp = kpg.genKeyPair();
+ ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate();
+ ECParameterSpec params = privateKey.getParams();
+ System.out.println(params);
+ EC_Curve curve = EC_Curve.fromSpec(params);
+ curve.writeCSV(System.out);
}
public static void main(String[] args) {
diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
index 66d8235..808f298 100644
--- a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java
@@ -11,6 +11,8 @@ import java.util.List;
*/
public class KeyAgreementIdent extends Ident {
private boolean requiresKeyAlgo;
+ private String kdf;
+ private String algo;
private static final List<KeyAgreementIdent> ALL = new LinkedList<>();
@@ -73,6 +75,19 @@ public class KeyAgreementIdent extends Ident {
private KeyAgreementIdent(String name, String... aliases) {
super(name, aliases);
+ if (name.contains("with")) {
+ int split = name.indexOf("with");
+ this.algo = name.substring(0, split);
+ this.kdf = name.substring(split + 4);
+ } else {
+ for (String alias : aliases) {
+ if (alias.contains("with")) {
+ int split = alias.indexOf("with");
+ this.algo = alias.substring(0, split);
+ this.kdf = alias.substring(split + 4);
+ }
+ }
+ }
}
private KeyAgreementIdent(String name, boolean requiresKeyAlgo, String... aliases) {
@@ -84,6 +99,14 @@ public class KeyAgreementIdent extends Ident {
return requiresKeyAlgo;
}
+ public String getKdfAlgo() {
+ return kdf;
+ }
+
+ public String getBaseAlgo() {
+ return algo;
+ }
+
public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException {
KeyAgreement instance = getInstance((algorithm, provider1) -> {
try {
diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
index dea8abe..e40731b 100644
--- a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
+++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java
@@ -10,6 +10,9 @@ import java.util.List;
* @author Jan Jancar johny@neuromancer.sk
*/
public class SignatureIdent extends Ident {
+ private String hash;
+ private String sig;
+
private static final List<SignatureIdent> ALL = new LinkedList<>();
static {
@@ -52,9 +55,8 @@ public class SignatureIdent extends Ident {
ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512"));
ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3"));
ALL.add(new SignatureIdent("SM3withSM2"));
- // ECDDSA
- ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA"));
- ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA"));
+ // ECDDSA (rfc6979?)
+ ALL.add(new SignatureIdent("ECDDSA", "SHA1withECDDSA", "SHA1withDETECDSA", "DETECDSA", "ECDETDSA"));
ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA"));
ALL.add(new SignatureIdent("SHA256withECDDSA", "SHA256withDETECDSA"));
ALL.add(new SignatureIdent("SHA384withECDDSA", "SHA384withDETECDSA"));
@@ -92,6 +94,19 @@ public class SignatureIdent extends Ident {
private SignatureIdent(String name, String... aliases) {
super(name, aliases);
+ if (name.contains("with")) {
+ int split = name.indexOf("with");
+ this.hash = name.substring(0, split);
+ this.sig = name.substring(split + 4);
+ } else {
+ for (String alias : aliases) {
+ if (alias.contains("with")) {
+ int split = alias.indexOf("with");
+ this.hash = alias.substring(0, split);
+ this.sig = alias.substring(split + 4);
+ }
+ }
+ }
}
public Signature getInstance(Provider provider) throws NoSuchAlgorithmException {
@@ -105,4 +120,12 @@ public class SignatureIdent extends Ident {
instance.getProvider();
return instance;
}
+
+ public String getHashAlgo() {
+ return hash;
+ }
+
+ public String getSigType() {
+ return sig;
+ }
}
diff --git a/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java
new file mode 100644
index 0000000..35a48a8
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/BoringsslLib.java
@@ -0,0 +1,28 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class BoringsslLib extends NativeECLibrary {
+ public BoringsslLib() {
+ super("boringssl_provider", "lib_boringssl.so");
+ }
+
+ @Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java
index cd28791..34fb178 100644
--- a/src/cz/crcs/ectester/standalone/libs/BotanLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.java
@@ -13,6 +13,15 @@ public class BotanLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
index 5112d7d..5153df5 100644
--- a/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/CryptoppLib.java
@@ -13,6 +13,15 @@ public class CryptoppLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/GcryptLib.java b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java
new file mode 100644
index 0000000..ef20f97
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/GcryptLib.java
@@ -0,0 +1,29 @@
+package cz.crcs.ectester.standalone.libs;
+
+import java.security.Provider;
+import java.util.Set;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class GcryptLib extends NativeECLibrary {
+
+ public GcryptLib() {
+ super("gcrypt_provider", "gcrypt", "gpg-error");
+ }
+
+ @Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
+ native Provider createProvider();
+
+ @Override
+ public native Set<String> getCurves();
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/MscngLib.java b/src/cz/crcs/ectester/standalone/libs/MscngLib.java
index 527a65b..354199a 100644
--- a/src/cz/crcs/ectester/standalone/libs/MscngLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/MscngLib.java
@@ -13,6 +13,15 @@ public class MscngLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
index 6b98cc1..7870377 100644
--- a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
+++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java
@@ -47,39 +47,19 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
appData = Paths.get(System.getProperty("user.home"), ".local", "share");
}
}
+ /* Resolve and create the ECTester directories in appData. */
Path libDir = appData.resolve("ECTesterStandalone");
File libDirFile = libDir.toFile();
+ Path libReqDir = libDir.resolve("lib");
+ File libReqDirFile = libReqDir.toFile();
Path libPath = libDir.resolve(resource + "." + suffix);
- File libFile = libPath.toFile();
- URL jarURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource + "." + suffix);
- if (jarURL == null) {
- return false;
- }
- URLConnection jarConnection = jarURL.openConnection();
-
- /* Only write the file if it does not exist,
- * or if the existing one is older than the
- * one in the JAR.
- */
- boolean write = false;
- if (libDirFile.isDirectory() && libFile.isFile()) {
- long jarModified = jarConnection.getLastModified();
+ /* Create directory for shims and for requirements. */
+ libDirFile.mkdirs();
+ libReqDirFile.mkdirs();
- long libModified = Files.getLastModifiedTime(libPath).toMillis();
- if (jarModified > libModified) {
- write = true;
- }
- } else {
- libDir.toFile().mkdirs();
- libFile.createNewFile();
- write = true;
- }
-
- if (write) {
- Files.copy(jarConnection.getInputStream(), libPath, StandardCopyOption.REPLACE_EXISTING);
- }
- jarConnection.getInputStream().close();
+ /* Write the shim. */
+ writeNewer(resource + "." + suffix, libPath);
/*
* Need to hack in /usr/local/lib to path.
@@ -98,12 +78,24 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
}
}
- for (String requirement : requriements) {
- System.loadLibrary(requirement);
- }
-
- if (suffix.equals("so")) {
- System.setProperty("java.library.path", path);
+ /* Load the requirements, if they are bundled, write them in and load them. */
+ try {
+ for (String requirement : requriements) {
+ if (requirement.endsWith(suffix)) {
+ /* The requirement is bundled, write it */
+ Path reqPath = libReqDir.resolve(requirement);
+ writeNewer(requirement, reqPath);
+ System.load(reqPath.toString());
+ } else {
+ System.loadLibrary(requirement);
+ }
+ }
+ } catch (UnsatisfiedLinkError ule) {
+ return false;
+ } finally {
+ if (suffix.equals("so")) {
+ System.setProperty("java.library.path", path);
+ }
}
System.load(libPath.toString());
@@ -116,5 +108,36 @@ public abstract class NativeECLibrary extends ProviderECLibrary {
return false;
}
+ private boolean isNewer(URLConnection jarConn, Path realPath) throws IOException {
+ if (realPath.toFile().isFile()) {
+ long jarModified = jarConn.getLastModified();
+ long realModified = Files.getLastModifiedTime(realPath).toMillis();
+ return jarModified > realModified;
+ }
+ return true;
+ }
+
+ private boolean writeNewer(String resource, Path outPath) throws IOException {
+ URL reqURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource);
+ if (reqURL == null) {
+ return false;
+ }
+ URLConnection reqConn = reqURL.openConnection();
+ if (isNewer(reqConn, outPath)) {
+ Files.copy(reqConn.getInputStream(), outPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ reqConn.getInputStream().close();
+ return true;
+ }
+
+ @Override
+ public abstract boolean supportsNativeTiming();
+
+ @Override
+ public abstract long getNativeTimingResolution();
+
+ @Override
+ public abstract long getLastNativeTiming();
+
abstract Provider createProvider();
}
diff --git a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
index e558336..4f44a2a 100644
--- a/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/OpensslLib.java
@@ -12,6 +12,15 @@ public class OpensslLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
index 9108eaf..83a9dc9 100644
--- a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
+++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java
@@ -62,6 +62,18 @@ public abstract class ProviderECLibrary implements ECLibrary {
return results;
}
+ public boolean supportsNativeTiming() {
+ return false;
+ }
+
+ public long getNativeTimingResolution() {
+ return 0;
+ }
+
+ public long getLastNativeTiming() {
+ return 0;
+ }
+
@Override
public Set<KeyAgreementIdent> getKAs() {
return getIdents("KeyAgreement", KeyAgreementIdent::get);
diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
index 78db00e..6ac74c9 100644
--- a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
+++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java
@@ -13,6 +13,16 @@ public class TomcryptLib extends NativeECLibrary {
}
@Override
+ public native boolean supportsNativeTiming();
+
+ @Override
+ public native long getNativeTimingResolution();
+
+ @Override
+ public native long getLastNativeTiming();
+
+
+ @Override
native Provider createProvider();
@Override
diff --git a/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
new file mode 100644
index 0000000..b58eb91
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/WolfCryptLib.java
@@ -0,0 +1,18 @@
+package cz.crcs.ectester.standalone.libs;
+
+import com.wolfssl.provider.jce.WolfCryptProvider;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class WolfCryptLib extends ProviderECLibrary {
+
+ public WolfCryptLib() {
+ super(new WolfCryptProvider());
+ }
+
+ @Override
+ public Set<String> getCurves() {
+ return new HashSet<>();
+ }
+}
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
index 006a3b1..c8ab47b 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/Makefile
+++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile
@@ -1,3 +1,28 @@
+###############################################################################
+## General CC setup.
+
+CC?=gcc
+CXX?=g++
+
+LFLAGS+=-fPIC -shared
+CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
+
+DEBUG ?= 0
+
+ifeq ($(DEBUG), 1)
+ CFLAGS+=-g -Wall
+ LFLAGS+=-g
+ CXXFLAGS+=-g -Wall
+else
+ CFLAGS+=-O2
+ LFLAGS+=-O2
+ CXXFLAGS+=-O2
+endif
+
+###############################################################################
+## Java JNI setup.
+
ifeq ($(JAVA_HOME),)
ifeq ($(OS),Windows_NT)
which = $(shell where $1)
@@ -24,56 +49,55 @@ ifeq ($(JNI_PLATFORM),)
else
ifeq ($(findstring linux,$(TARGETTRIPLET)),linux)
JNI_PLATFORM:= linux
- # add more checks here
endif
endif
endif
JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM)
-LOCAL_INCLUDES = /usr/local/include
-LOCAL_LIBS = /usr/local/lib
-
-CC?=gcc
-CXX?=g++
-STRIP?=strip
-
-LFLAGS+=-fPIC -shared
-CFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
-CXXFLAGS+=-fPIC -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I.
-
-DEBUG ?= 0
-
-ifeq ($(DEBUG), 1)
- CFLAGS+=-g
- LFLAGS+=-g
- CXXFLAGS+=-g
-else
- CFLAGS+=-O2
- LFLAGS+=-O2
- CXXFLAGS+=-O2
-endif
+###############################################################################
+## Targets.
-all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so
+all: tomcrypt_provider.so botan_provider.so cryptopp_provider.so openssl_provider.so boringssl_provider.so gcrypt_provider.so
# Common utils
c_utils.o: c_utils.c
$(CC) $(CFLAGS) -c $<
+c_timing.o: c_timing.c
+ $(CC) $(CFLAGS) -c $<
+
cpp_utils.o: cpp_utils.cpp
$(CXX) $(CXXFLAGS) -c $<
# OpenSSL shim
-openssl_provider.so: openssl.o c_utils.o
+openssl_provider.so: openssl.o c_utils.o c_timing.o
$(CC) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs openssl)
openssl.o: openssl.c
$(CC) $(shell pkg-config --cflags openssl) $(CFLAGS) -c $<
+# BoringSSL shim
+boringssl_provider.so: boringssl.o c_utils.o c_timing.o
+ $(CC) $(LFLAGS) -o $@ $^ -L. ../../../../../../../ext/boringssl/build/crypto/libcrypto.so
+ cp ../../../../../../../ext/boringssl/build/crypto/libcrypto.so lib_boringssl.so
+
+boringssl.o: boringssl.c
+ $(CC) -I../../../../../../../ext/boringssl/include/ $(CFLAGS) -c $<
+
+
+# libgcrypt shim
+gcrypt_provider.so: gcrypt.o c_utils.o c_timing.o
+ $(CC) $(LFLAGS) -o $@ $^ -L. $(shell libgcrypt-config --libs)
+
+gcrypt.o: gcrypt.c
+ $(CC) $(shell libgcrypt-config --cflags) $(CFLAGS) -c $<
+
+
# Libtomcrypt shim
-tomcrypt_provider.so: tomcrypt.o c_utils.o
+tomcrypt_provider.so: tomcrypt.o c_utils.o c_timing.o
$(CC) $(LFLAGS) -o $@ $^ -L. -ltommath $(shell pkg-config --libs libtomcrypt)
tomcrypt.o: tomcrypt.c
@@ -81,7 +105,7 @@ tomcrypt.o: tomcrypt.c
# Botan-2 shim
-botan_provider.so: botan.o cpp_utils.o
+botan_provider.so: botan.o cpp_utils.o c_timing.o
$(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs botan-2)
botan.o: botan.cpp
@@ -89,15 +113,24 @@ botan.o: botan.cpp
# Crypto++ shim
-cryptopp_provider.so: cryptopp.o cpp_utils.o
+cryptopp_provider.so: cryptopp.o cpp_utils.o c_timing.o
$(CXX) $(LFLAGS) -o $@ $^ -L. $(shell pkg-config --libs libcrypto++)
cryptopp.o: cryptopp.cpp
$(CXX) $(shell pkg-config --cflags libcrypto++) $(CXXFLAGS) -c $<
+help:
+ @echo "# This makefile builds the JNI shims necessary to test native libraries."
+ @echo "# Targets:"
+ @echo " - openssl_provider.so"
+ @echo " - boringssl_provider.so"
+ @echo " - gcrypt_provider.so"
+ @echo " - tomcrypt_provider.so"
+ @echo " - botan_provider.so"
+ @echo " - cryptopp_provider.so"
clean:
rm -rf *.o
rm -rf *.so
-.PHONY: all clean \ No newline at end of file
+.PHONY: all help clean \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
index 4cd4a9d..6d8101f 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java
@@ -85,6 +85,18 @@ public abstract class NativeECPrivateKey implements ECPrivateKey {
}
}
+ public static class Boringssl extends Raw {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Gcrypt extends Raw {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
public static class Mscng extends Raw {
// 0 -> implicit (meta = curveName UTF16, header = full);
// 1 -> explicit (meta = null, header = full);
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
index 33dd3ef..dcb8b3f 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java
@@ -86,6 +86,18 @@ public abstract class NativeECPublicKey implements ECPublicKey {
}
}
+ public static class Boringssl extends ANSIX962 {
+ public Boringssl(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
+ public static class Gcrypt extends ANSIX962 {
+ public Gcrypt(byte[] keyData, ECParameterSpec params) {
+ super(keyData, params);
+ }
+ }
+
public static class Mscng extends ANSIX962 {
// 0 -> implicit (meta = curveName UTF16, header = full);
// 1 -> explicit (meta = null, header = full);
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
index fdbdccf..7b531f5 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java
@@ -65,7 +65,7 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
@Override
protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
if (!(params instanceof ECParameterSpec)) {
- throw new InvalidAlgorithmParameterException();
+ throw new InvalidAlgorithmParameterException(params.toString());
}
engineInit(key, random);
this.params = params;
@@ -234,6 +234,47 @@ public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi {
}
}
+ public abstract static class Boringssl extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Boringssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class BoringsslECDH extends Boringssl {
+ public BoringsslECDH() {
+ super("ECDH");
+ }
+ }
+
+ public abstract static class Gcrypt extends SimpleKeyAgreementSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native SecretKey generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params, String algorithm);
+ }
+
+ public static class GcryptECDH extends Gcrypt {
+ public GcryptECDH() {
+ super("ECDH");
+ }
+ }
+
+
public abstract static class Mscng extends ExtendedKeyAgreementSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
index aa83479..78656fc 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java
@@ -180,6 +180,42 @@ public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
}
+ public static class Boringssl extends NativeKeyPairGeneratorSpi {
+ public Boringssl() {
+ initialize(256, new SecureRandom());
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
+ public static class Gcrypt extends NativeKeyPairGeneratorSpi {
+
+ public Gcrypt() {
+ }
+
+ @Override
+ native boolean keysizeSupported(int keysize);
+
+ @Override
+ native boolean paramsSupported(AlgorithmParameterSpec params);
+
+ @Override
+ native KeyPair generate(int keysize, SecureRandom random);
+
+ @Override
+ native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random);
+ }
+
public static abstract class Mscng extends NativeKeyPairGeneratorSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
index fef2930..99baa97 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java
@@ -64,6 +64,26 @@ public abstract class NativeProvider extends Provider {
native void setup();
}
+ public static class Boringssl extends NativeProvider {
+
+ public Boringssl(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
+ public static class Gcrypt extends NativeProvider {
+
+ public Gcrypt(String name, double version, String info) {
+ super(name, version, info);
+ }
+
+ @Override
+ native void setup();
+ }
+
public static class Mscng extends NativeProvider {
public Mscng(String name, double version, String info) {
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
index 602b1c4..f2b1ab9 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
+++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java
@@ -328,6 +328,118 @@ public abstract class NativeSignatureSpi extends SignatureSpi {
}
}
+ public abstract static class Boringssl extends SimpleSignatureSpi {
+ private String type;
+
+ public Boringssl(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class BoringsslECDSAwithNONE extends Boringssl {
+
+ public BoringsslECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public abstract static class Gcrypt extends SimpleSignatureSpi {
+ private String type;
+
+ public Gcrypt(String type) {
+ this.type = type;
+ }
+
+ @Override
+ native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params);
+
+ @Override
+ native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params);
+ }
+
+ public static class GcryptECDSAwithNONE extends Gcrypt {
+
+ public GcryptECDSAwithNONE() {
+ super("NONEwithECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDSAwithSHA1() {
+ super("SHA1withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDSAwithSHA224() {
+ super("SHA224withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDSAwithSHA256() {
+ super("SHA256withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDSAwithSHA384() {
+ super("SHA384withECDSA");
+ }
+ }
+
+ public static class GcryptECDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDSAwithSHA512() {
+ super("SHA512withECDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA1 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA1() {
+ super("SHA1withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA224 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA224() {
+ super("SHA224withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA256 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA256() {
+ super("SHA256withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA384 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA384() {
+ super("SHA384withECDDSA");
+ }
+ }
+
+ public static class GcryptECDDSAwithSHA512 extends Gcrypt {
+
+ public GcryptECDDSAwithSHA512() {
+ super("SHA512withECDDSA");
+ }
+ }
+
public abstract static class Mscng extends ExtendedSignatureSpi {
private String type;
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c
new file mode 100644
index 0000000..0484d28
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/boringssl.c
@@ -0,0 +1,528 @@
+#include "native.h"
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/opensslv.h>
+#include <openssl/objects.h>
+#include <openssl/obj_mac.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+
+#include "c_utils.h"
+#include "c_timing.h"
+
+
+static jclass provider_class;
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider(JNIEnv *env, jobject self) {
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Boringssl");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ jstring name = (*env)->NewStringUTF(env, OPENSSL_VERSION_TEXT);
+ long ver_hi = (OPENSSL_VERSION_NUMBER & 0xff000000L) >> 28;
+ long ver_mid = (OPENSSL_VERSION_NUMBER & 0xff0000L) >> 20;
+ long ver_low = (OPENSSL_VERSION_NUMBER & 0xff00L) >> 12;
+ double version = (double)ver_hi + ((double)ver_mid/10) + ((double)ver_low/100);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup(JNIEnv *env, jobject self) {
+ ERR_load_crypto_strings();
+ CRYPTO_library_init();
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, self, "EC", "Boringssl");
+ ADD_KA(env, self, "ECDH", "BoringsslECDH");
+ ADD_SIG(env, self, "NONEwithECDSA", "BoringsslECDSAwithNONE");
+
+ init_classes(env, "Boringssl");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves(JNIEnv *env, jobject self) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ jstring curve_name = (*env)->NewStringUTF(env, OBJ_nid2sn(curves[i].nid));
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported(JNIEnv *env, jobject self, jint keysize) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ for (size_t i = 0; i < ncurves; ++i) {
+ EC_GROUP *curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ EC_GROUP_free(curve);
+ return JNI_TRUE;
+ }
+ EC_GROUP_free(curve);
+ }
+ return JNI_FALSE;
+}
+
+static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ int size = BN_num_bytes(bn);
+ jbyteArray bytes = (*env)->NewByteArray(env, size);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ BN_bn2bin(bn, (unsigned char *) data);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ jsize byte_length = (*env)->GetArrayLength(env, byte_array);
+ jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
+ (*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
+ return result;
+}
+
+static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ if ((*env)->IsInstanceOf(env, field, f2m_field_class)) {
+ return NULL;
+ }
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ BIGNUM *a_bn = biginteger_to_bignum(env, a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ BIGNUM *b_bn = biginteger_to_bignum(env, b);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g = (*env)->CallObjectMethod(env, params, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g, get_x);
+ BIGNUM *gx_bn = biginteger_to_bignum(env, gx);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g, get_y);
+ BIGNUM *gy_bn = biginteger_to_bignum(env, gy);
+
+ EC_GROUP *result;
+ EC_POINT *g_point;
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject p = (*env)->CallObjectMethod(env, field, get_p);
+
+ BIGNUM *p_bn = biginteger_to_bignum(env, p);
+ result = EC_GROUP_new_curve_GFp(p_bn, a_bn, b_bn, NULL);
+ BN_free(p_bn);
+ BN_free(a_bn);
+ BN_free(b_bn);
+
+ if (!result) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_new_curve_GFp.");
+ BN_free(gx_bn); BN_free(gy_bn);
+ return NULL;
+ }
+
+ g_point = EC_POINT_new(result);
+ if(!EC_POINT_set_affine_coordinates_GFp(result, g_point, gx_bn, gy_bn, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_POINT_set_affine_coordinates_GFp.");
+ BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject n = (*env)->CallObjectMethod(env, params, get_n);
+ BIGNUM *n_bn = biginteger_to_bignum(env, n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint h = (*env)->CallIntMethod(env, params, get_h);
+ BIGNUM *h_bn = BN_new();
+ BN_set_word(h_bn, h);
+
+ if (!EC_GROUP_set_generator(result, g_point, n_bn, h_bn)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating EC_GROUP, EC_GROUP_set_generator.");
+ BN_free(n_bn); BN_free(h_bn); BN_free(gx_bn); BN_free(gy_bn); EC_POINT_free(g_point); EC_GROUP_free(result);
+ return NULL;
+ }
+
+ EC_POINT_free(g_point);
+ BN_free(gx_bn);
+ BN_free(gy_bn);
+ BN_free(n_bn);
+ BN_free(h_bn);
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported(JNIEnv *env, jobject self, jobject params){
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jboolean result = !curve;
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_TRUE;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ return JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
+ BIGNUM *a;
+ BIGNUM *b;
+
+ BIGNUM *gx;
+ BIGNUM *gy;
+ jobject field;
+
+ BIGNUM *p = BN_new();
+ a = BN_new();
+ b = BN_new();
+ if (!EC_GROUP_get_curve_GFp(curve, p, a, b, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_curve_GFp.");
+ BN_free(p); BN_free(a); BN_free(b);
+ return NULL;
+ }
+
+ jobject p_int = bignum_to_biginteger(env, p);
+
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ field = (*env)->NewObject(env, fp_field_class, fp_field_init, p_int);
+
+ BN_free(p);
+
+ gx = BN_new();
+ gy = BN_new();
+ if (!EC_POINT_get_affine_coordinates_GFp(curve, EC_GROUP_get0_generator(curve), gx, gy, NULL)) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_POINT_get_affine_coordinates_GFp.");
+ BN_free(a); BN_free(b); BN_free(gx); BN_free(gy);
+ return NULL;
+ }
+
+ jobject a_int = bignum_to_biginteger(env, a);
+ jobject b_int = bignum_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
+
+ BN_free(a);
+ BN_free(b);
+
+ jobject gx_int = bignum_to_biginteger(env, gx);
+ jobject gy_int = bignum_to_biginteger(env, gy);
+
+ BN_free(gx);
+ BN_free(gy);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject g = (*env)->NewObject(env, point_class, point_init, gx_int, gy_int);
+
+ jobject order = bignum_to_biginteger(env, EC_GROUP_get0_order(curve));
+ BIGNUM *h = BN_new();
+ EC_GROUP_get_cofactor(curve, h, NULL);
+ jint cofactor = BN_get_word(h);
+ BN_free(h);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, order, cofactor);
+}
+
+static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
+ jint keysize = EC_GROUP_get_degree(curve);
+ unsigned long key_bytes = (keysize + 7) / 8;
+
+ EC_KEY *key = EC_KEY_new();
+ EC_KEY_set_group(key, curve);
+
+ native_timing_start();
+ int err = EC_KEY_generate_key(key);
+ native_timing_stop();
+
+ if (!err) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key.");
+ EC_KEY_free(key);
+ return NULL;
+ }
+
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ BN_bn2bin_padded((unsigned char *) key_priv, key_bytes, EC_KEY_get0_private_key(key));
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ unsigned long key_len = 2*key_bytes + 1;
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ EC_KEY_free(key);
+
+ jobject ec_param_spec = create_ec_param_spec(env, curve);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random) {
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ if (EC_GROUP_get_degree(curve) == keysize) {
+ break;
+ }
+ EC_GROUP_free(curve);
+ }
+
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ EC_GROUP *curve = create_curve(env, params);
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ size_t ncurves = EC_get_builtin_curves(NULL, 0);
+ EC_builtin_curve curves[ncurves];
+ EC_get_builtin_curves(curves, ncurves);
+ EC_GROUP *curve = NULL;
+ for (size_t i = 0; i < ncurves; ++i) {
+ if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
+ curve = EC_GROUP_new_by_curve_name(curves[i].nid);
+ break;
+ }
+ }
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found.");
+ return NULL;
+ }
+ jobject result = generate_from_curve(env, curve);
+ EC_GROUP_free(curve);
+ return result;
+ } else {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+}
+
+EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize pub_len = (*env)->GetArrayLength(env, pub);
+ jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
+ EC_POINT *pub_point = EC_POINT_new(curve);
+ EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
+ EC_KEY_set_public_key(result, pub_point);
+ EC_POINT_free(pub_point);
+ return result;
+}
+
+EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv) {
+ EC_KEY *result = EC_KEY_new();
+ EC_KEY_set_group(result, curve);
+ jsize priv_len = (*env)->GetArrayLength(env, priv);
+ jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
+ BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL);
+ (*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
+ EC_KEY_set_private_key(result, s);
+ BN_free(s);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ int field_size = EC_GROUP_get_degree(curve);
+ size_t secret_len = (field_size + 7)/8;
+
+ //TODO: Do more KeyAgreements here, but will have to do the hash-fun manually,
+ // probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string.
+ jbyteArray result = (*env)->NewByteArray(env, secret_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+
+ native_timing_start();
+ int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL);
+ native_timing_stop();
+
+ if (err <= 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key.");
+ EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT);
+ return NULL;
+ }
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ EC_KEY_free(pub);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return NULL;
+ }
+
+ EC_KEY *priv = barray_to_privkey(env, curve, privkey);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+ // TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually?
+
+ native_timing_start();
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv);
+ native_timing_stop();
+
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ if (!signature) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign.");
+ EC_KEY_free(priv); EC_GROUP_free(curve);
+ return NULL;
+ }
+
+ jsize sig_len = i2d_ECDSA_SIG(signature, NULL);
+ jbyteArray result = (*env)->NewByteArray(env, sig_len);
+ jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
+ jbyte *result_data_ptr = result_data;
+ i2d_ECDSA_SIG(signature, (unsigned char **)&result_data_ptr);
+ (*env)->ReleaseByteArrayElements(env, result, result_data, 0);
+
+ ECDSA_SIG_free(signature);
+ EC_KEY_free(priv);
+ EC_GROUP_free(curve);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) {
+ EC_GROUP *curve = create_curve(env, params);
+ if (!curve) {
+ throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found.");
+ return JNI_FALSE;
+ }
+
+ EC_KEY *pub = barray_to_pubkey(env, curve, pubkey);
+
+ jsize sig_len = (*env)->GetArrayLength(env, signature);
+ jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
+ jbyte *sig_data_ptr = sig_data;
+ ECDSA_SIG *sig_obj = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig_data_ptr, sig_len);
+ (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
+
+ jsize data_size = (*env)->GetArrayLength(env, data);
+ jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
+
+ native_timing_start();
+ int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub);
+ native_timing_stop();
+
+ if (result < 0) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify.");
+ EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj);
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+ return JNI_FALSE;
+ }
+ (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
+
+ ECDSA_SIG_free(sig_obj);
+ EC_KEY_free(pub);
+ EC_GROUP_free(curve);
+ return (result == 1) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
index 207532d..813b9f8 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
+++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp
@@ -17,8 +17,10 @@
#include <botan/ecdh.h>
#include <botan/pubkey.h>
#include "cpp_utils.hpp"
+#include "c_timing.h"
static jclass provider_class;
+static Botan::AutoSeeded_RNG rng;
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) {
/* Create the custom provider. */
@@ -145,7 +147,7 @@ static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) {
jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array);
jsize byte_length = env->GetArrayLength(byte_array);
jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL);
- Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length);
+ Botan::BigInt result((unsigned char *) byte_data, byte_length);
env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT);
return result;
}
@@ -157,10 +159,6 @@ static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) {
jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
jobject field = env->CallObjectMethod(elliptic_curve, get_field);
-
- jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I");
- jint bits = env->CallIntMethod(field, get_bits);
- jint bytes = (bits + 7) / 8;
jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
jobject a = env->CallObjectMethod(elliptic_curve, get_a);
@@ -238,8 +236,6 @@ static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) {
}
static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) {
- Botan::AutoSeeded_RNG rng;
-
jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan");
jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;");
jstring type = (jstring) env->GetObjectField(self, type_id);
@@ -249,6 +245,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr
std::unique_ptr<Botan::EC_PrivateKey> skey;
try {
+ native_timing_start();
if (type_str == "ECDH") {
skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group);
} else if (type_str == "ECDSA") {
@@ -258,6 +255,7 @@ static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group gr
} else if (type_str == "ECGDSA") {
skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group);
}
+ native_timing_stop();
} catch (Botan::Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
return NULL;
@@ -299,7 +297,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
for (auto it = curves.begin(); it != curves.end(); ++it) {
Botan::EC_Group curve_group = Botan::EC_Group(*it);
size_t curve_size = curve_group.get_p_bits();
- if (curve_size == keysize) {
+ if (curve_size == (size_t) keysize) {
//generate on this group. Even thou no default groups are present...
return generate_from_group(env, self, curve_group);
}
@@ -349,11 +347,9 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr
jsize privkey_length = env->GetArrayLength(privkey);
jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL);
- Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length);
+ Botan::BigInt privkey_scalar((unsigned char *) privkey_data, privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
- Botan::AutoSeeded_RNG rng;
-
Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar);
jsize pubkey_length = env->GetArrayLength(pubkey);
@@ -378,7 +374,9 @@ jbyteArray generate_secret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteAr
std::vector<uint8_t> derived;
try {
+ native_timing_start();
derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of());
+ native_timing_stop();
} catch (Botan::Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
return NULL;
@@ -419,8 +417,6 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT);
- Botan::AutoSeeded_RNG rng;
-
std::unique_ptr<Botan::EC_PrivateKey> skey;
if (type_str.find("ECDSA") != std::string::npos) {
skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, curve_group, privkey_scalar);
@@ -430,28 +426,30 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar);
}
- std::string kdf;
+ std::string emsa;
if (type_str.find("NONE") != std::string::npos) {
- kdf = "Raw";
+ emsa = "Raw";
} else if (type_str.find("SHA1") != std::string::npos) {
- kdf = "EMSA1(SHA-1)";
+ emsa = "EMSA1(SHA-1)";
} else if (type_str.find("SHA224") != std::string::npos) {
- kdf = "EMSA1(SHA-224)";
+ emsa = "EMSA1(SHA-224)";
} else if (type_str.find("SHA256") != std::string::npos) {
- kdf = "EMSA1(SHA-256)";
+ emsa = "EMSA1(SHA-256)";
} else if (type_str.find("SHA384") != std::string::npos) {
- kdf = "EMSA1(SHA-384)";
+ emsa = "EMSA1(SHA-384)";
} else if (type_str.find("SHA512") != std::string::npos) {
- kdf = "EMSA1(SHA-512)";
+ emsa = "EMSA1(SHA-512)";
}
- Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE);
+ Botan::PK_Signer signer(*skey, rng, emsa, Botan::DER_SEQUENCE);
jsize data_length = env->GetArrayLength(data);
jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
std::vector<uint8_t> sig;
try {
+ native_timing_start();
sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng);
+ native_timing_stop();
} catch (Botan::Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
@@ -491,22 +489,22 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point);
}
- std::string kdf;
+ std::string emsa;
if (type_str.find("NONE") != std::string::npos) {
- kdf = "Raw";
+ emsa = "Raw";
} else if (type_str.find("SHA1") != std::string::npos) {
- kdf = "EMSA1(SHA-1)";
+ emsa = "EMSA1(SHA-1)";
} else if (type_str.find("SHA224") != std::string::npos) {
- kdf = "EMSA1(SHA-224)";
+ emsa = "EMSA1(SHA-224)";
} else if (type_str.find("SHA256") != std::string::npos) {
- kdf = "EMSA1(SHA-256)";
+ emsa = "EMSA1(SHA-256)";
} else if (type_str.find("SHA384") != std::string::npos) {
- kdf = "EMSA1(SHA-384)";
+ emsa = "EMSA1(SHA-384)";
} else if (type_str.find("SHA512") != std::string::npos) {
- kdf = "EMSA1(SHA-512)";
+ emsa = "EMSA1(SHA-512)";
}
- Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE);
+ Botan::PK_Verifier verifier(*pkey, emsa, Botan::DER_SEQUENCE);
jsize data_length = env->GetArrayLength(data);
jsize sig_length = env->GetArrayLength(signature);
@@ -515,7 +513,9 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
bool result;
try {
+ native_timing_start();
result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length);
+ native_timing_stop();
} catch (Botan::Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
@@ -528,4 +528,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
return JNI_TRUE;
}
return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_last();
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c
new file mode 100644
index 0000000..be46398
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.c
@@ -0,0 +1,57 @@
+#include "c_timing.h"
+#include <time.h>
+
+#if _POSIX_TIMERS > 0
+
+struct timespec start = {0};
+struct timespec end = {0};
+
+jboolean native_timing_supported() {
+ return JNI_TRUE;
+}
+
+jlong native_timing_resolution() {
+ struct timespec timeval;
+ clock_getres(CLOCK_MONOTONIC, &timeval);
+ return timeval.tv_nsec;
+}
+
+
+void native_timing_start() {
+ clock_gettime(CLOCK_MONOTONIC, &start);
+}
+
+
+void native_timing_stop() {
+ clock_gettime(CLOCK_MONOTONIC, &end);
+}
+
+
+jlong native_timing_last() {
+ jlong res = (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec);
+ if (res < 0) {
+ return 0;
+ } else {
+ return res;
+ }
+}
+
+#else
+
+jboolean native_timing_supported() {
+ return JNI_FALSE;
+}
+
+jlong native_timing_resolution() {
+ return 0;
+}
+
+void native_timing_start() {}
+
+void native_timing_stop() {}
+
+jlong native_timing_last() {
+ return 0;
+}
+
+#endif \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h
new file mode 100644
index 0000000..bce2a19
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_timing.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <jni.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ *
+ */
+jboolean native_timing_supported();
+
+/**
+ *
+ */
+jlong native_timing_resolution();
+
+/**
+ *
+ */
+void native_timing_start();
+
+/**
+ *
+ */
+void native_timing_stop();
+
+/**
+ *
+ */
+jlong native_timing_last();
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
index 49cab44..81d1fb8 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c
@@ -75,7 +75,7 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...) {
char buffer[2048];
va_list args;
va_start(args, format);
- int res = vsnprintf(buffer, 2048, format, args);
+ vsnprintf(buffer, 2048, format, args);
va_end(args);
throw_new(env, class, buffer);
}
@@ -105,4 +105,109 @@ jint get_kdf_bits(JNIEnv *env, jstring algorithm) {
}
(*env)->ReleaseStringUTFChars(env, algorithm, algo_data);
return result;
+}
+
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len) {
+ jbyte r_length = (jbyte) r_len + (r[0] & 0x80 ? 1 : 0);
+ jbyte s_length = (jbyte) s_len + (s[0] & 0x80 ? 1 : 0);
+
+ // R and S are < 128 bytes, so 1 byte tag + 1 byte len + len bytes value
+ size_t seq_value_len = 2 + r_length + 2 + s_length;
+ size_t whole_len = seq_value_len;
+
+ // The SEQUENCE length might be >= 128, so more bytes of length
+ size_t seq_len_len = 0;
+ if (seq_value_len >= 128) {
+ size_t s = seq_value_len;
+ while ((s = s >> 8)) {
+ seq_len_len++;
+ }
+ }
+ // seq_len_len bytes for length and one for length of length
+ whole_len += seq_len_len + 1;
+
+ // 1 byte tag for SEQUENCE
+ whole_len += 1;
+
+ jbyteArray result = (jbyteArray) (*env)->NewByteArray(env, whole_len);
+ jbyte *data = (*env)->GetByteArrayElements(env, result, NULL);
+ size_t i = 0;
+ data[i++] = 0x30; // SEQUENCE
+ if (seq_value_len < 128) {
+ data[i++] = (jbyte) seq_value_len;
+ } else {
+ data[i++] = (jbyte) (seq_len_len | (1 << 7));
+ for (size_t j = 0; j < seq_len_len; ++j) {
+ data[i++] = (jbyte) (seq_value_len & (0xff << (seq_len_len - j)));
+ }
+ }
+ data[i++] = 0x02; //INTEGER
+ data[i++] = r_length;
+ if (r[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, r, r_len);
+ i += r_len;
+ data[i++] = 0x02; //INTEGER
+ data[i++] = s_length;
+ if (s[0] & 0x80) {
+ data[i++] = 0;
+ }
+ memcpy(data + i, s, s_len);
+ i += s_len;
+ (*env)->ReleaseByteArrayElements(env, result, data, 0);
+
+ return result;
+}
+
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len) {
+ size_t sig_len = (*env)->GetArrayLength(env, sig);
+ jbyte *data = (*env)->GetByteArrayElements(env, sig, NULL);
+ size_t i = 0;
+ if (data[i++] != 0x30) {//SEQUENCE
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t seq_value_len = 0;
+ if (!(data[i] & 0x80)) {
+ seq_value_len = data[i++];
+ } else {
+ size_t seq_len_len = data[i++] & 0x7f;
+ while (seq_len_len > 0) {
+ seq_value_len |= (data[i++] << (seq_len_len - 1));
+ seq_len_len--;
+ }
+ }
+
+ if (data[i++] != 0x02) {//INTEGER
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t r_length = data[i++];
+ jbyte *r_out = malloc(r_length);
+ memcpy(r_out, data + i, r_length);
+ i += r_length;
+
+ if (data[i++] != 0x02) {//INTEGER
+ free(r_out);
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ return false;
+ }
+ size_t s_length = data[i++];
+ jbyte *s_out = malloc(s_length);
+ memcpy(s_out, data + i, s_length);
+ i += s_length;
+
+ (*env)->ReleaseByteArrayElements(env, sig, data, JNI_ABORT);
+ if (i != sig_len) {
+ free(r_out);
+ free(s_out);
+ return false;
+ }
+
+ *r_len = r_length;
+ *r_data = r_out;
+ *s_len = s_length;
+ *s_data = s_out;
+ return true;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
index b767b61..82c3538 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h
@@ -1,6 +1,7 @@
#pragma once
#include "native.h"
+#include <stdbool.h>
/**
* Classes that are accessed alot are cached here, manually.
@@ -39,6 +40,16 @@ void throw_new_var(JNIEnv *env, const char *class, const char *format, ...);
jint get_kdf_bits(JNIEnv *env, jstring algorithm);
/**
+ * DER encode the r and s values.
+ */
+jbyteArray asn1_der_encode(JNIEnv *env, const jbyte *r, size_t r_len, const jbyte *s, size_t s_len);
+
+/**
+ * DER decode a signature into r and s values.
+ */
+bool asn1_der_decode(JNIEnv *env, jbyteArray sig, jbyte **r_data, size_t *r_len, jbyte **s_data, size_t *s_len);
+
+/**
* Some useful defines to init the provider.
*/
#define INIT_PROVIDER(env, provider_class) jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
index 32121c5..089724e 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
+++ b/src/cz/crcs/ectester/standalone/libs/jni/cryptopp.cpp
@@ -23,7 +23,6 @@ using CryptoPP::byte;
#include "cryptopp/osrng.h"
using CryptoPP::AutoSeededRandomPool;
-using CryptoPP::AutoSeededX917RNG;
#include "cryptopp/sha.h"
using CryptoPP::SHA1;
@@ -71,8 +70,10 @@ using CryptoPP::Integer;
#include "cpp_utils.hpp"
+#include "c_timing.h"
static jclass provider_class;
+static AutoSeededRandomPool rng;
JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_createProvider(JNIEnv *env, jobject self) {
@@ -89,7 +90,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_crea
std::stringstream ss;
ss << lib_name << " ";
ss << info_str[0];
- for (int i = 1; i < info_str.size(); ++i) {
+ for (size_t i = 1; i < info_str.size(); ++i) {
ss << "." << info_str[i];
}
@@ -470,6 +471,8 @@ template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<E
//pentanomial
ks = env->NewIntArray(3);
to_find = 3;
+ } else {
+ return NULL;
}
jint *ks_data = env->GetIntArrayElements(ks, NULL);
for (int i = m - 1; i > 0 && found < to_find; --i) {
@@ -492,12 +495,13 @@ template <> jobject params_from_group<EC2N>(JNIEnv *env, DL_GroupParameters_EC<E
}
template <class EC> jobject generate_from_group(JNIEnv *env, DL_GroupParameters_EC<EC> group, jobject params) {
- AutoSeededRandomPool rng;
typename ECDH<EC>::Domain ec_domain(group);
SecByteBlock priv(ec_domain.PrivateKeyLength()), pub(ec_domain.PublicKeyLength());
try {
+ native_timing_start();
ec_domain.GenerateKeyPair(rng, priv, pub);
+ native_timing_stop();
} catch (Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
return NULL;
@@ -578,7 +582,9 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
try {
secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ native_timing_start();
success = dh_agreement.Agree(*secret, private_key, public_key);
+ native_timing_stop();
} catch (Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
return NULL;
@@ -588,12 +594,18 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
try {
secret = std::make_unique<SecByteBlock>(dh_agreement.AgreedValueLength());
+ native_timing_start();
success = dh_agreement.Agree(*secret, private_key, public_key);
+ native_timing_stop();
} catch (Exception & ex) {
throw_new(env, "java/security/GeneralSecurityException", ex.what());
return NULL;
}
}
+ if (!success) {
+ throw_new(env, "java/security/GeneralSecurityException", "Agreement was unsuccessful.");
+ return NULL;
+ }
jbyteArray result = env->NewByteArray(secret->size());
jbyte *result_data = env->GetByteArrayElements(result, NULL);
@@ -610,7 +622,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgr
template <class EC, class H>
jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray data, const Integer & private_key_x) {
- AutoSeededRandomPool prng;
typename ECDSA<EC, H>::PrivateKey pkey;
pkey.Initialize(group, private_key_x);
@@ -620,7 +631,9 @@ jbyteArray sign_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray
jsize data_length = env->GetArrayLength(data);
jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
- size_t len = signer.SignMessage(prng, (byte *)data_bytes, data_length, (byte *)signature.c_str());
+ native_timing_start();
+ size_t len = signer.SignMessage(rng, (byte *)data_bytes, data_length, (byte *)signature.c_str());
+ native_timing_stop();
env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
signature.resize(len);
@@ -648,7 +661,7 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
Integer private_key_x((byte *) privkey_data, (size_t) privkey_length);
env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT);
- jbyteArray result;
+ jbyteArray result = NULL;
std::unique_ptr<DL_GroupParameters_EC<ECP>> ecp_group = fp_group_from_params(env, params);
if (ecp_group == nullptr) {
@@ -705,7 +718,9 @@ jboolean verify_message(JNIEnv *env, DL_GroupParameters_EC<EC> group, jbyteArray
jsize data_length = env->GetArrayLength(data);
jbyte *data_bytes = env->GetByteArrayElements(data, NULL);
+ native_timing_start();
bool result = verifier.VerifyMessage((byte *)data_bytes, data_length, sig, sig_len);
+ native_timing_stop();
env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT);
return result;
@@ -750,3 +765,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
// unreachable
return JNI_FALSE;
}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
new file mode 100644
index 0000000..359d0f4
--- /dev/null
+++ b/src/cz/crcs/ectester/standalone/libs/jni/gcrypt.c
@@ -0,0 +1,635 @@
+#include "native.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <gcrypt.h>
+#include "c_utils.h"
+#include "c_timing.h"
+
+static jclass provider_class;
+
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider(JNIEnv *env, jobject this){
+ /* Create the custom provider. */
+ jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$Gcrypt");
+ provider_class = (*env)->NewGlobalRef(env, local_provider_class);
+
+ jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V");
+
+ const char *running_with = gcry_check_version(GCRYPT_VERSION);
+ if (!running_with) {
+ return NULL;
+ }
+ char full_name[strlen("libgcrypt ") + strlen(running_with) + 1];
+ strcpy(full_name, "libgcrypt ");
+ strcat(full_name, running_with);
+ jstring name = (*env)->NewStringUTF(env, full_name);
+ double version = strtod(running_with, NULL);
+
+ return (*env)->NewObject(env, provider_class, init, name, version, name);
+}
+
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup(JNIEnv *env, jobject this) {
+ gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
+ //gcry_control(GCRYCTL_SET_DEBUG_FLAGS, 1);
+ gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+ INIT_PROVIDER(env, provider_class);
+
+ ADD_KPG(env, this, "EC", "Gcrypt");
+ ADD_KA(env, this, "ECDH", "GcryptECDH");
+ ADD_SIG(env, this, "NONEwithECDSA", "GcryptECDSAwithNONE");
+ ADD_SIG(env, this, "SHA1withECDSA", "GcryptECDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDSA", "GcryptECDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDSA", "GcryptECDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDSA", "GcryptECDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDSA", "GcryptECDSAwithSHA512");
+ ADD_SIG(env, this, "SHA1withECDDSA", "GcryptECDDSAwithSHA1");
+ ADD_SIG(env, this, "SHA224withECDDSA", "GcryptECDDSAwithSHA224");
+ ADD_SIG(env, this, "SHA256withECDDSA", "GcryptECDDSAwithSHA256");
+ ADD_SIG(env, this, "SHA384withECDDSA", "GcryptECDDSAwithSHA384");
+ ADD_SIG(env, this, "SHA512withECDDSA", "GcryptECDDSAwithSHA512");
+
+ init_classes(env, "Gcrypt");
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves(JNIEnv *env, jobject this) {
+ jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet");
+
+ jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V");
+ jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z");
+
+ jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr);
+
+ const char *name;
+ unsigned int nbits;
+
+ for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){
+ jstring curve_name = (*env)->NewStringUTF(env, name);
+ (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name);
+ }
+
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize) {
+ const char *name;
+ unsigned int nbits;
+
+ for (size_t i = 0; (name = gcry_pk_get_curve(NULL, i, &nbits)); i++){
+ if (nbits == keysize) {
+ return JNI_TRUE;
+ }
+ }
+
+ return JNI_FALSE;
+}
+
+/*
+static void print_sexp(gcry_sexp_t sexp) {
+ size_t len = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ char string[len];
+ gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, string, len);
+ printf("%s\n", string);
+ fflush(stdout);
+}
+
+static void print_chrray(unsigned char *arr, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ printf("%02x,", ((unsigned char) arr[i] & 0xff));
+ }
+ printf("\n");
+}
+*/
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported(JNIEnv *env, jobject this, jobject params) {
+ if (params == NULL) {
+ return JNI_FALSE;
+ }
+
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return JNI_FALSE;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ gcry_sexp_t curve_sexp;
+ gcry_sexp_build(&curve_sexp, NULL, "(public-key (ecc (curve %s)))", utf_name);
+ unsigned int nbits;
+ const char *ret_name = gcry_pk_get_curve(curve_sexp, 0, &nbits);
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ gcry_sexp_release(curve_sexp);
+ return ret_name ? JNI_TRUE : JNI_FALSE;
+ } else {
+ return JNI_FALSE;
+ }
+}
+
+static gcry_mpi_t bytearray_to_mpi(JNIEnv *env, jbyteArray array) {
+ if (!array) {
+ return NULL;
+ }
+
+ gcry_mpi_t result;
+
+ size_t length = (*env)->GetArrayLength(env, array);
+ jbyte data[length + 1];
+ data[0] = 0;
+ (*env)->GetByteArrayRegion(env, array, 0, length, data + 1);
+ gcry_mpi_scan(&result, GCRYMPI_FMT_STD, data, length + 1, NULL);
+ return result;
+}
+
+static jbyteArray mpi_to_bytearray0(JNIEnv *env, gcry_mpi_t mpi, size_t start, size_t len) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ size_t mpi_len = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &mpi_len, mpi);
+ if (start >= mpi_len) {
+ return NULL;
+ }
+ if (start + len > mpi_len || len == 0) {
+ len = mpi_len - start;
+ }
+ unsigned char buff[mpi_len];
+ gcry_mpi_print(GCRYMPI_FMT_USG, buff, mpi_len, NULL, mpi);
+ jbyteArray bytes = (*env)->NewByteArray(env, len);
+ jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
+ memcpy(data, buff + start, len);
+ (*env)->ReleaseByteArrayElements(env, bytes, data, 0);
+ return bytes;
+}
+
+static jbyteArray mpi_to_bytearray(JNIEnv *env, gcry_mpi_t mpi) {
+ return mpi_to_bytearray0(env, mpi, 0, 0);
+}
+
+static jobject mpi_to_biginteger(JNIEnv *env, gcry_mpi_t mpi) {
+ if (!mpi) {
+ return NULL;
+ }
+
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+ jbyteArray bytes = mpi_to_bytearray(env, mpi);
+ jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
+ return result;
+}
+
+static gcry_mpi_t biginteger_to_mpi(JNIEnv *env, jobject bigint) {
+ if (!bigint) {
+ return NULL;
+ }
+
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+ jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
+ return bytearray_to_mpi(env, byte_array);
+}
+
+static jint mpi_to_jint(gcry_mpi_t mpi) {
+ jint result = 0;
+ unsigned long nbits = gcry_mpi_get_nbits(mpi);
+ int max_bits = sizeof(jint) * 8;
+ for (size_t i = 0; i < nbits && i < max_bits; ++i) {
+ if (gcry_mpi_test_bit(mpi, nbits - i - 1)) {
+ result = ((result << 1) | 1);
+ } else {
+ result = (result << 1);
+ }
+ }
+ return result;
+}
+
+static jobject buff_to_ecpoint(JNIEnv *env, gcry_buffer_t buff) {
+ jint coord_size = (buff.len - 1) / 2;
+ jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(I[B)V");
+
+ jbyteArray x_bytes = (*env)->NewByteArray(env, coord_size);
+ jbyte *x_data = (*env)->GetByteArrayElements(env, x_bytes, NULL);
+ memcpy(x_data, ((char *) buff.data) + 1, coord_size);
+ (*env)->ReleaseByteArrayElements(env, x_bytes, x_data, 0);
+ jobject xi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, x_bytes);
+
+ jbyteArray y_bytes = (*env)->NewByteArray(env, coord_size);
+ jbyte *y_data = (*env)->GetByteArrayElements(env, y_bytes, NULL);
+ memcpy(y_data, ((char *) buff.data) + 1 + coord_size, coord_size);
+ (*env)->ReleaseByteArrayElements(env, y_bytes, y_data, 0);
+ jobject yi = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, y_bytes);
+
+ jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ return (*env)->NewObject(env, point_class, point_init, xi, yi);
+}
+
+static jobject create_ec_param_spec(JNIEnv *env, gcry_sexp_t key) {
+ jobject result = NULL;
+ gcry_mpi_t p, a, b, n, h;
+ gcry_buffer_t g = {0};
+ gcry_error_t err = gcry_sexp_extract_param(key, "ecc", "pab&g+nh", &p, &a, &b, &g, &n, &h, NULL);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error exporting domain parameters. Error: %ui", gcry_err_code(err));
+ goto end;
+ }
+
+ jobject pi = mpi_to_biginteger(env, p);
+ jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V");
+ jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, pi);
+
+ jobject ai = mpi_to_biginteger(env, a);
+ jobject bi = mpi_to_biginteger(env, b);
+
+ jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
+ jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, ai, bi);
+
+ jobject gen = buff_to_ecpoint(env, g);
+
+ jobject order = mpi_to_biginteger(env, n);
+ jint cofactor = mpi_to_jint(h);
+
+ jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V");
+ result = (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, gen, order, cofactor);
+
+end:
+ gcry_mpi_release(p);
+ gcry_mpi_release(a);
+ gcry_mpi_release(b);
+ gcry_free(g.data);
+ gcry_mpi_release(n);
+ gcry_mpi_release(h);
+ return result;
+}
+
+static jobject generate_from_sexp(JNIEnv *env, gcry_sexp_t gen_sexp) {
+ jobject result = NULL;
+ gcry_sexp_t key_sexp;
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_genkey(&key_sexp, gen_sexp);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error generating key. Error: %ui", gcry_err_code(err));
+ goto release_sexp;
+ }
+ gcry_sexp_t pkey = gcry_sexp_find_token(key_sexp, "public-key", 0);
+ gcry_sexp_t skey = gcry_sexp_find_token(key_sexp, "private-key", 0);
+
+ jobject ec_param_spec = create_ec_param_spec(env, skey);
+ if (!ec_param_spec) {
+ goto release_keypair;
+ }
+
+ gcry_buffer_t q = {0};
+ gcry_mpi_t d;
+ err = gcry_sexp_extract_param(skey, "ecc", "&q+d", &q, &d, NULL);
+
+ jbyteArray pub_bytes = (*env)->NewByteArray(env, q.size);
+ jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
+ memcpy(key_pub, q.data, q.size);
+ (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
+
+ size_t priv_len = 0;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &priv_len, d);
+ jbyteArray priv_bytes = (*env)->NewByteArray(env, priv_len);
+ jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
+ gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char *) key_priv, priv_len, NULL, d);
+ (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
+
+ jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
+
+ jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
+ jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
+ jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec);
+
+ jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V");
+ result = (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey);
+
+ gcry_mpi_release(d);
+ gcry_free(q.data);
+
+release_keypair:
+ gcry_sexp_release(pkey);
+ gcry_sexp_release(skey);
+release_sexp:
+ gcry_sexp_release(key_sexp);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random) {
+ gcry_sexp_t gen_sexp;
+ gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (nbits %d)))", keysize);
+
+ jobject result = generate_from_sexp(env, gen_sexp);
+ gcry_sexp_release(gen_sexp);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random) {
+ if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) {
+ return NULL;
+ } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) {
+ jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;");
+ jstring name = (*env)->CallObjectMethod(env, params, get_name);
+ const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL);
+ gcry_sexp_t gen_sexp;
+ gcry_sexp_build(&gen_sexp, NULL, "(genkey (ecc (flags no-keytest param) (curve %s)))", utf_name);
+ (*env)->ReleaseStringUTFChars(env, name, utf_name);
+ jobject result = generate_from_sexp(env, gen_sexp);
+ gcry_sexp_release(gen_sexp);
+ return result;
+ } else {
+ return NULL;
+ }
+}
+
+static gcry_sexp_t create_key(JNIEnv *env, jobject ec_param_spec, const char *key_fmt, gcry_mpi_t q, gcry_mpi_t d) {
+ gcry_mpi_t p, a, b, g, n, h;
+
+ jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;");
+ jobject elliptic_curve = (*env)->CallObjectMethod(env, ec_param_spec, get_curve);
+
+ jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
+ jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
+
+ jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
+ jint bits = (*env)->CallIntMethod(env, field, get_bits);
+ jint bytes = (bits + 7) / 8;
+
+ jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
+ jobject big_a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
+ a = biginteger_to_mpi(env, big_a);
+
+ jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;");
+ jobject big_b = (*env)->CallObjectMethod(env, elliptic_curve, get_b);
+ b = biginteger_to_mpi(env, big_b);
+
+ jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;");
+ jobject big_p = (*env)->CallObjectMethod(env, field, get_p);
+ p = biginteger_to_mpi(env, big_p);
+
+ jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;");
+ jobject g_point = (*env)->CallObjectMethod(env, ec_param_spec, get_g);
+
+ jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;");
+ jobject gx = (*env)->CallObjectMethod(env, g_point, get_x);
+
+ jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;");
+ jobject gy = (*env)->CallObjectMethod(env, g_point, get_y);
+
+ jmethodID to_byte_array = (*env)->GetMethodID(env, biginteger_class, "toByteArray", "()[B");
+
+ jbyteArray gx_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gx, to_byte_array);
+ size_t gx_len = (*env)->GetArrayLength(env, gx_bytes);
+ jbyteArray gy_bytes = (jbyteArray) (*env)->CallObjectMethod(env, gy, to_byte_array);
+ size_t gy_len = (*env)->GetArrayLength(env, gy_bytes);
+ unsigned char g_data[1 + 2 * bytes];
+ g_data[0] = 0x04;
+ jbyte *gx_data = (*env)->GetByteArrayElements(env, gx_bytes, NULL);
+ memcpy(g_data + 1, gx_data + (gx_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gx_bytes, gx_data, JNI_ABORT);
+ jbyte *gy_data = (*env)->GetByteArrayElements(env, gy_bytes, NULL);
+ memcpy(g_data + 1 + bytes, gy_data + (gy_len - bytes), bytes);
+ (*env)->ReleaseByteArrayElements(env, gy_bytes, gy_data, JNI_ABORT);
+
+ gcry_mpi_scan(&g, GCRYMPI_FMT_USG, g_data, 1 + 2 * bytes, NULL);
+
+ jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;");
+ jobject big_n = (*env)->CallObjectMethod(env, ec_param_spec, get_n);
+ n = biginteger_to_mpi(env, big_n);
+
+ jmethodID get_h = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCofactor", "()I");
+ jint jh = (*env)->CallIntMethod(env, ec_param_spec, get_h);
+ h = gcry_mpi_set_ui(NULL, jh);
+
+ gcry_sexp_t inner = NULL;
+ if (q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %M) (d %M))", p, a, b, g, n, h, q, d, NULL);
+ } else if (q && !d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (q %m))", p, a, b, g, n, h, q, NULL);
+ } else if (!q && d) {
+ gcry_sexp_build(&inner, NULL, "(ecc (flags param) (p %m) (a %m) (b %m) (g %m) (n %m) (h %m) (d %m))", p, a, b, g, n, h, d, NULL);
+ }
+ gcry_sexp_t result;
+ gcry_sexp_build(&result, NULL, key_fmt, inner, NULL);
+ gcry_sexp_release(inner);
+ return result;
+}
+
+static gcry_sexp_t create_pubkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(public-key %S)", q, NULL);
+ gcry_mpi_release(q);
+ return result;
+}
+
+static gcry_sexp_t create_privkey(JNIEnv *env, jobject ec_param_spec, jbyteArray pubkey, jbyteArray privkey) {
+ gcry_mpi_t q = bytearray_to_mpi(env, pubkey);
+ gcry_mpi_t d = bytearray_to_mpi(env, privkey);
+ gcry_sexp_t result = create_key(env, ec_param_spec, "(private-key %S)", q, d);
+ gcry_mpi_release(q);
+ gcry_mpi_release(d);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t pub = create_pubkey(env, params, pubkey);
+ gcry_mpi_t priv = bytearray_to_mpi(env, privkey);
+
+ gcry_sexp_t enc_sexp;
+ gcry_sexp_build(&enc_sexp, NULL, "(data (flags raw) (value %M))", priv, NULL);
+ gcry_sexp_t res_sexp;
+ // TODO: figure out why ecc_encrypt_raw takes signed representation.. Nobody uses that., everybody uses unsigned reduced mod p.
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_encrypt(&res_sexp, enc_sexp, pub);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDH. Error: %ui", gcry_err_code(err));
+ goto end;
+ }
+
+ gcry_mpi_t derived;
+ err = gcry_sexp_extract_param(res_sexp, NULL, "s", &derived, NULL);
+
+ size_t derived_bytes;
+ gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &derived_bytes, derived);
+ size_t coord_bytes = (derived_bytes - 1) / 2;
+ result = mpi_to_bytearray0(env, derived, 1, coord_bytes);
+
+ gcry_mpi_release(derived);
+end:
+ gcry_sexp_release(enc_sexp);
+ gcry_sexp_release(res_sexp);
+ gcry_sexp_release(pub);
+ gcry_mpi_release(priv);
+ return result;
+}
+
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params, jstring algorithm) {
+ throw_new(env, "java/lang/UnsupportedOperationException", "Not supported.");
+ return NULL;
+}
+
+static int starts_with(const char *whole, const char *prefix) {
+ return !strncmp(whole, prefix, strlen(prefix));
+}
+
+static int get_hash_algo(const char *sig_type) {
+ if (starts_with(sig_type, "SHA1")) {
+ return GCRY_MD_SHA1;
+ } else if (starts_with(sig_type, "SHA224")) {
+ return GCRY_MD_SHA224;
+ } else if (starts_with(sig_type, "SHA256")) {
+ return GCRY_MD_SHA256;
+ } else if (starts_with(sig_type, "SHA384")) {
+ return GCRY_MD_SHA384;
+ } else if (starts_with(sig_type, "SHA512")) {
+ return GCRY_MD_SHA512;
+ } else {
+ return GCRY_MD_NONE;
+ }
+}
+
+static const char *get_sig_algo(const char *sig_type) {
+ const char *start = strstr(sig_type, "with") + strlen("with");
+ if (starts_with(start, "ECDSA")) {
+ return NULL;
+ } else if (starts_with(start, "ECDDSA")) {
+ return "rfc6979";
+ } else {
+ return NULL;
+ }
+}
+
+static void get_sign_data_sexp(JNIEnv *env, gcry_sexp_t *result, jobject this, jbyteArray data) {
+ jclass sig_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Gcrypt");
+ jfieldID type_id = (*env)->GetFieldID(env, sig_class, "type", "Ljava/lang/String;");
+ jstring type = (jstring)(*env)->GetObjectField(env, this, type_id);
+ const char* type_data = (*env)->GetStringUTFChars(env, type, NULL);
+ int hash_algo = get_hash_algo(type_data);
+ const char *sig_algo = get_sig_algo(type_data);
+ const char *with = strstr(type_data, "with");
+ char hash_name[with - type_data + 1];
+ memcpy(hash_name, type_data, with - type_data);
+ for (size_t i = 0; i < with - type_data; ++i) {
+ hash_name[i] = tolower(hash_name[i]);
+ }
+ hash_name[with - type_data] = 0;
+ (*env)->ReleaseStringUTFChars(env, type, type_data);
+
+ if (hash_algo == GCRY_MD_NONE) {
+ gcry_mpi_t data_mpi = bytearray_to_mpi(env, data);
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", data_mpi);
+ gcry_mpi_release(data_mpi);
+ } else {
+ unsigned int hash_len = gcry_md_get_algo_dlen(hash_algo);
+ size_t data_len = (*env)->GetArrayLength(env, data);
+ jbyte *data_bytes = (*env)->GetByteArrayElements(env, data, NULL);
+ unsigned char out_hash[hash_len];
+ gcry_md_hash_buffer(hash_algo, out_hash, data_bytes, data_len);
+ (*env)->ReleaseByteArrayElements(env, data, data_bytes, JNI_ABORT);
+ gcry_mpi_t hash_mpi;
+ gcry_mpi_scan(&hash_mpi, GCRYMPI_FMT_USG, out_hash, hash_len, NULL);
+ if (!sig_algo) {
+ gcry_sexp_build(result, NULL, "(data (flags raw param) (value %M))", hash_mpi);
+ } else {
+ gcry_sexp_build(result, NULL, "(data (flags %s param) (hash %s %M))", sig_algo, hash_name, hash_mpi);
+ }
+ gcry_mpi_release(hash_mpi);
+ }
+}
+
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) {
+ jbyteArray result = NULL;
+ gcry_sexp_t priv_sexp = create_privkey(env, params, NULL, privkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ gcry_sexp_t res_sexp;
+ native_timing_start();
+ gcry_error_t err = gcry_pk_sign(&res_sexp, data_sexp, priv_sexp);
+ native_timing_stop();
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error performing ECDSA. Error: %ui", gcry_err_code(err));
+ goto release_init;
+ }
+
+ gcry_buffer_t r_buf = {0};
+ gcry_buffer_t s_buf = {0};
+ err = gcry_sexp_extract_param(res_sexp, "ecdsa", "&rs", &r_buf, &s_buf, NULL);
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ throw_new_var(env, "java/security/GeneralSecurityException", "Error extracting ECDSA output. Error: %ui", gcry_err_code(err));
+ goto release_res;
+ }
+ result = asn1_der_encode(env, r_buf.data, r_buf.len, s_buf.data, s_buf.len);
+
+ gcry_free(r_buf.data);
+ gcry_free(s_buf.data);
+release_res:
+ gcry_sexp_release(res_sexp);
+release_init:
+ gcry_sexp_release(priv_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify(JNIEnv *env, jobject this, jbyteArray sig, jbyteArray data, jbyteArray pubkey, jobject params) {
+ jboolean result = JNI_FALSE;
+ gcry_sexp_t pub_sexp = create_pubkey(env, params, pubkey);
+
+ gcry_sexp_t data_sexp;
+ get_sign_data_sexp(env, &data_sexp, this, data);
+
+ size_t r_len, s_len;
+ jbyte *r_data, *s_data;
+ bool decode = asn1_der_decode(env, sig, &r_data, &r_len, &s_data, &s_len);
+ if (!decode) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error decoding sig.");
+ goto release_init;
+ }
+
+ gcry_mpi_t r_mpi, s_mpi;
+ gcry_mpi_scan(&r_mpi, GCRYMPI_FMT_USG, r_data, r_len, NULL);
+ gcry_mpi_scan(&s_mpi, GCRYMPI_FMT_USG, s_data, s_len, NULL);
+ free(r_data);
+ free(s_data);
+
+ gcry_sexp_t sig_sexp;
+ gcry_sexp_build(&sig_sexp, NULL, "(sig-val (ecdsa (r %M) (s %M)))", r_mpi, s_mpi);
+
+ native_timing_start();
+ gcry_error_t err = gcry_pk_verify(sig_sexp, data_sexp, pub_sexp);
+ native_timing_stop();
+
+ if (gcry_err_code(err) != GPG_ERR_NO_ERROR) {
+ if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) {
+ throw_new(env, "java/security/GeneralSecurityException", "Error verif sig.");
+ goto release_init;
+ }
+ } else {
+ result = JNI_TRUE;
+ }
+
+release_init:
+ gcry_sexp_release(pub_sexp);
+ gcry_sexp_release(data_sexp);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
index 5820afd..568e924 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/mscng.c
@@ -1211,4 +1211,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
throw_new_var(env, "java/security/GeneralSecurityException", "Error 0x%x returned by BCryptVerifySignature\n", status);
return JNI_FALSE;
}
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming(JNIEnv *env, jobject self) {
+ return JNI_FALSE;
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution(JNIEnv *env, jobject self) {
+ return 0;
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming(JNIEnv *env, jobject self) {
+ return 0;
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h
index e3bf3d8..e410204 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/native.h
+++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h
@@ -9,6 +9,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_TomcryptLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -190,6 +214,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BotanLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -371,6 +419,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_CryptoppLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_CryptoppLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -552,6 +624,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_OpensslLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -733,6 +829,30 @@ extern "C" {
#endif
/*
* Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_MscngLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_MscngLib
* Method: createProvider
* Signature: ()Ljava/security/Provider;
*/
@@ -905,3 +1025,413 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
}
#endif
#endif
+/* Header for class cz_crcs_ectester_standalone_libs_BoringsslLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_BoringsslLib
+#define _Included_cz_crcs_ectester_standalone_libs_BoringsslLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_BoringsslLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BoringsslLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Boringssl
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Boringssl_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Boringssl
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Boringssl_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Boringssl
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Boringssl_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Boringssl
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Boringssl_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_GcryptLib */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_GcryptLib
+#define _Included_cz_crcs_ectester_standalone_libs_GcryptLib
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: supportsNativeTiming
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_supportsNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getNativeTimingResolution
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getNativeTimingResolution
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getLastNativeTiming
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getLastNativeTiming
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: createProvider
+ * Signature: ()Ljava/security/Provider;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_createProvider
+ (JNIEnv *, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_GcryptLib
+ * Method: getCurves
+ * Signature: ()Ljava/util/Set;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_GcryptLib_getCurves
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 1421746759512286392LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_MAX_ARRAY_SIZE 2147483639L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_KEYS 0L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_VALUES 1L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_ENTRIES 2L
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID 4112578634029874840LL
+#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID
+#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt_serialVersionUID -4298000515446427739LL
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Gcrypt
+ * Method: setup
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Gcrypt_setup
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE
+#define cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt_DEFAULT_KEYSIZE 256L
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: keysizeSupported
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_keysizeSupported
+ (JNIEnv *, jobject, jint);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: paramsSupported
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_paramsSupported
+ (JNIEnv *, jobject, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: generate
+ * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__ILjava_security_SecureRandom_2
+ (JNIEnv *, jobject, jint, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Gcrypt
+ * Method: generate
+ * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Gcrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2
+ (JNIEnv *, jobject, jobject, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Gcrypt
+ * Method: generateSecret
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;Ljava/lang/String;)Ljavax/crypto/SecretKey;
+ */
+JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Gcrypt_generateSecret___3B_3BLjava_security_spec_ECParameterSpec_2Ljava_lang_String_2
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt */
+
+#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: sign
+ * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_sign
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject);
+
+/*
+ * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Gcrypt
+ * Method: verify
+ * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z
+ */
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Gcrypt_verify
+ (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
index 255834a..a63c2fb 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/openssl.c
@@ -1,6 +1,5 @@
#include "native.h"
#include <string.h>
-#include <stdio.h>
#include <openssl/conf.h>
#include <openssl/opensslv.h>
@@ -13,6 +12,8 @@
#include <openssl/ecdsa.h>
#include "c_utils.h"
+#include "c_timing.h"
+
static jclass provider_class;
@@ -88,7 +89,7 @@ static jobject bignum_to_biginteger(JNIEnv *env, const BIGNUM *bn) {
int size = BN_num_bytes(bn);
jbyteArray bytes = (*env)->NewByteArray(env, size);
jbyte *data = (*env)->GetByteArrayElements(env, bytes, NULL);
- BN_bn2bin(bn, data);
+ BN_bn2bin(bn, (unsigned char *) data);
(*env)->ReleaseByteArrayElements(env, bytes, data, 0);
jobject result = (*env)->NewObject(env, biginteger_class, biginteger_init, 1, bytes);
return result;
@@ -100,7 +101,7 @@ static BIGNUM *biginteger_to_bignum(JNIEnv *env, jobject bigint) {
jbyteArray byte_array = (jbyteArray) (*env)->CallObjectMethod(env, bigint, to_byte_array);
jsize byte_length = (*env)->GetArrayLength(env, byte_array);
jbyte *byte_data = (*env)->GetByteArrayElements(env, byte_array, NULL);
- BIGNUM *result = BN_bin2bn(byte_data, byte_length, NULL);
+ BIGNUM *result = BN_bin2bn((unsigned char *) byte_data, byte_length, NULL);
(*env)->ReleaseByteArrayElements(env, byte_array, byte_data, JNI_ABORT);
return result;
}
@@ -112,10 +113,6 @@ static EC_GROUP *create_curve(JNIEnv *env, jobject params) {
jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;");
jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field);
- jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I");
- jint bits = (*env)->CallIntMethod(env, field, get_bits);
- jint bytes = (bits + 7) / 8;
-
jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;");
jobject a = (*env)->CallObjectMethod(env, elliptic_curve, get_a);
BIGNUM *a_bn = biginteger_to_bignum(env, a);
@@ -286,7 +283,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
if (basis_type == NID_X9_62_tpBasis) {
ks = (*env)->NewIntArray(env, 1);
ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
- if (!EC_GROUP_get_trinomial_basis(curve, &ks_data[0])) {
+ if (!EC_GROUP_get_trinomial_basis(curve, (unsigned int *) &ks_data[0])) {
throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_trinomial_basis.");
BN_free(a); BN_free(b);
(*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
@@ -295,7 +292,7 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
} else if (basis_type == NID_X9_62_ppBasis) {
ks = (*env)->NewIntArray(env, 3);
ks_data = (*env)->GetIntArrayElements(env, ks, NULL);
- if (!EC_GROUP_get_pentanomial_basis(curve, &ks_data[0], &ks_data[1], &ks_data[2])) {
+ if (!EC_GROUP_get_pentanomial_basis(curve, (unsigned int *) &ks_data[0], (unsigned int *) &ks_data[1], (unsigned int *) &ks_data[2])) {
throw_new(env, "java/security/InvalidAlgorithmParameterException", "Error creating ECParameterSpec, EC_GROUP_get_pentanomial_basis.");
BN_free(a); BN_free(b);
(*env)->ReleaseIntArrayElements(env, ks, ks_data, JNI_ABORT);
@@ -327,7 +324,6 @@ static jobject create_ec_param_spec(JNIEnv *env, const EC_GROUP *curve) {
jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V");
jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a_int, b_int);
- fflush(stderr);
BN_free(a);
BN_free(b);
@@ -354,7 +350,12 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
EC_KEY *key = EC_KEY_new();
EC_KEY_set_group(key, curve);
- if (!EC_KEY_generate_key(key)) {
+
+ native_timing_start();
+ int result = EC_KEY_generate_key(key);
+ native_timing_stop();
+
+ if (!result) {
throw_new(env, "java/security/GeneralSecurityException", "Error generating key, EC_KEY_generate_key.");
EC_KEY_free(key);
return NULL;
@@ -362,13 +363,13 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
jbyteArray priv_bytes = (*env)->NewByteArray(env, key_bytes);
jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
- BN_bn2binpad(EC_KEY_get0_private_key(key), key_priv, key_bytes);
+ BN_bn2binpad(EC_KEY_get0_private_key(key), (unsigned char *) key_priv, key_bytes);
(*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
unsigned long key_len = 2*key_bytes + 1;
jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
- EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, key_pub, key_len, NULL);
+ EC_POINT_point2oct(curve, EC_KEY_get0_public_key(key), POINT_CONVERSION_UNCOMPRESSED, (unsigned char *) key_pub, key_len, NULL);
(*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
EC_KEY_free(key);
@@ -377,7 +378,7 @@ static jobject generate_from_curve(JNIEnv *env, const EC_GROUP *curve) {
jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
- jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec);
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
@@ -424,7 +425,7 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPai
size_t ncurves = EC_get_builtin_curves(NULL, 0);
EC_builtin_curve curves[ncurves];
EC_get_builtin_curves(curves, ncurves);
- EC_GROUP *curve;
+ EC_GROUP *curve = NULL;
for (size_t i = 0; i < ncurves; ++i) {
if (strcasecmp(utf_name, OBJ_nid2sn(curves[i].nid)) == 0) {
curve = EC_GROUP_new_by_curve_name(curves[i].nid);
@@ -451,7 +452,7 @@ EC_KEY *barray_to_pubkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray pub) {
jsize pub_len = (*env)->GetArrayLength(env, pub);
jbyte *pub_data = (*env)->GetByteArrayElements(env, pub, NULL);
EC_POINT *pub_point = EC_POINT_new(curve);
- EC_POINT_oct2point(curve, pub_point, pub_data, pub_len, NULL);
+ EC_POINT_oct2point(curve, pub_point, (unsigned char *) pub_data, pub_len, NULL);
(*env)->ReleaseByteArrayElements(env, pub, pub_data, JNI_ABORT);
EC_KEY_set_public_key(result, pub_point);
EC_POINT_free(pub_point);
@@ -463,7 +464,7 @@ EC_KEY *barray_to_privkey(JNIEnv *env, const EC_GROUP *curve, jbyteArray priv)
EC_KEY_set_group(result, curve);
jsize priv_len = (*env)->GetArrayLength(env, priv);
jbyte *priv_data = (*env)->GetByteArrayElements(env, priv, NULL);
- BIGNUM *s = BN_bin2bn(priv_data, priv_len, NULL);
+ BIGNUM *s = BN_bin2bn((unsigned char *) priv_data, priv_len, NULL);
(*env)->ReleaseByteArrayElements(env, priv, priv_data, JNI_ABORT);
EC_KEY_set_private_key(result, s);
BN_free(s);
@@ -487,7 +488,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
// probably using the ECDH_KDF_X9_62 by wrapping it and dynamically choosing the EVP_MD. from the type string.
jbyteArray result = (*env)->NewByteArray(env, secret_len);
jbyte *result_data = (*env)->GetByteArrayElements(env, result, NULL);
- if (ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL) <= 0) {
+
+ native_timing_start();
+ int err = ECDH_compute_key(result_data, secret_len, EC_KEY_get0_public_key(pub), priv, NULL);
+ native_timing_stop();
+
+ if (err <= 0) {
throw_new(env, "java/security/GeneralSecurityException", "Error computing ECDH, ECDH_compute_key.");
EC_KEY_free(pub); EC_KEY_free(priv); EC_GROUP_free(curve);
(*env)->ReleaseByteArrayElements(env, result, result_data, JNI_ABORT);
@@ -518,7 +524,11 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
jsize data_size = (*env)->GetArrayLength(env, data);
jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
// TODO: Do more Signatures here, maybe use the EVP interface to get to the hashes easier and not hash manually?
- ECDSA_SIG *signature = ECDSA_do_sign(data_data, data_size, priv);
+
+ native_timing_start();
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char *) data_data, data_size, priv);
+ native_timing_stop();
+
(*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
if (!signature) {
throw_new(env, "java/security/GeneralSecurityException", "Error signing, ECDSA_do_sign.");
@@ -556,7 +566,11 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
jsize data_size = (*env)->GetArrayLength(env, data);
jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL);
- int result = ECDSA_do_verify(data_data, data_size, sig_obj, pub);
+
+ native_timing_start();
+ int result = ECDSA_do_verify((unsigned char *) data_data, data_size, sig_obj, pub);
+ native_timing_stop();
+
if (result < 0) {
throw_new(env, "java/security/GeneralSecurityException", "Error verifying, ECDSA_do_verify.");
EC_KEY_free(pub); EC_GROUP_free(curve); ECDSA_SIG_free(sig_obj);
@@ -570,3 +584,15 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
EC_GROUP_free(curve);
return (result == 1) ? JNI_TRUE : JNI_FALSE;
}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_OpensslLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
+} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
index fdf5663..471190e 100644
--- a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
+++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <tomcrypt.h>
#include "c_utils.h"
+#include "c_timing.h"
static prng_state ltc_prng;
static jclass provider_class;
@@ -20,7 +21,6 @@ JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_crea
return (*env)->NewObject(env, provider_class, init, name, version, name);
}
-
JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) {
/* Initialize libtommath as the math lib. */
ltc_mp = ltm_desc;
@@ -243,26 +243,30 @@ static void free_curve(ltc_ecc_set_type *curve) {
static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) {
ecc_key key;
- int err;
- if ((err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) {
+
+ native_timing_start();
+ int err = ecc_make_key_ex(&ltc_prng, find_prng("yarrow"), &key, curve);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
return NULL;
}
unsigned long key_len = 2*curve->size + 1;
jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len);
jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL);
- ecc_ansi_x963_export(&key, key_pub, &key_len);
+ ecc_ansi_x963_export(&key, (unsigned char *) key_pub, &key_len);
(*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, 0);
jobject ec_param_spec = create_ec_param_spec(env, curve);
jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V");
- jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec);
+ jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_pub_param_spec);
jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size);
jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL);
- ltc_mp.unsigned_write(key.k, key_priv);
+ ltc_mp.unsigned_write(key.k, (unsigned char *) key_priv);
(*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, 0);
jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec);
@@ -334,7 +338,7 @@ static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ec
out->idx = -1;
out->dp = curve;
ltc_mp.init(&out->k);
- ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->k, (unsigned char *) priv_data, (unsigned long) curve->size);
(*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT);
return JNI_TRUE;
@@ -355,8 +359,8 @@ static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_
out->dp = curve;
ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL);
ltc_mp.set_int(out->pubkey.z, 1);
- ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size);
- ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->pubkey.x, (unsigned char *) pub_data + 1, (unsigned long) curve->size);
+ ltc_mp.unsigned_read(out->pubkey.y, (unsigned char *) pub_data + 1 + curve->size, (unsigned long) curve->size);
(*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT);
@@ -380,8 +384,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKey
unsigned char result[curve->size];
unsigned long output_len = curve->size;
- int err;
- if ((err = ecc_shared_secret(&priv, &pub, result, &output_len)) != CRYPT_OK) {
+
+ native_timing_start();
+ int err = ecc_shared_secret(&priv, &pub, result, &output_len);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
free_curve(curve);
return NULL;
@@ -416,8 +424,12 @@ JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSig
unsigned char result[curve->size*4];
unsigned long output_len = curve->size*4;
- int err;
- if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) {
+
+ native_timing_start();
+ int err = ecc_sign_hash((unsigned char *) data_data, data_size, result, &output_len, &ltc_prng, find_prng("yarrow"), &priv);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
free_curve(curve);
(*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
@@ -450,9 +462,12 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
jsize sig_size = (*env)->GetArrayLength(env, signature);
jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL);
- int err;
int result;
- if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) {
+ native_timing_start();
+ int err = ecc_verify_hash((unsigned char *) sig_data, sig_size, (unsigned char *) data_data, data_size, &result, &pub);
+ native_timing_stop();
+
+ if (err != CRYPT_OK) {
throw_new(env, "java/security/GeneralSecurityException", error_to_string(err));
free_curve(curve);
(*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT);
@@ -464,4 +479,16 @@ JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSigna
(*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT);
free_curve(curve);
return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_supportsNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_supported();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getNativeTimingResolution(JNIEnv *env, jobject this) {
+ return native_timing_resolution();
+}
+
+JNIEXPORT jlong JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getLastNativeTiming(JNIEnv *env, jobject this) {
+ return native_timing_last();
} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
index bf9ec7d..d7be4dc 100644
--- a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
+++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java
@@ -33,10 +33,11 @@ public class TextTestWriter extends BaseTextTestWriter {
protected String testableString(Testable t) {
if (t instanceof StandaloneTestable) {
StandaloneTestable<?> testable = (StandaloneTestable) t;
- String stage = testable.getStage().name();
+ Enum<?> stage = testable.getStage();
+ String stageName = stage.name();
String exception = causeString(testable.getException());
String errorCause = causeString(testable.errorCause());
- return stage + exception + errorCause;
+ return String.format("[%d/%d] %s %s %s", stage.ordinal() + 1, stage.getClass().getEnumConstants().length, stageName, exception, errorCause);
}
return "";
}