aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/applet/ECTesterApplet.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/applet/ECTesterApplet.java')
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java722
1 files changed, 722 insertions, 0 deletions
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
new file mode 100644
index 0000000..c2e2c63
--- /dev/null
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) 2016-2017 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.*;
+import javacard.security.ECPrivateKey;
+import javacard.security.ECPublicKey;
+import javacard.security.KeyPair;
+import javacard.security.RandomData;
+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 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_CORRUPT = (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) 0x60;
+ public static final byte INS_ECDH_DIRECT = (byte) 0x61;
+ public static final byte INS_ECDSA = (byte) 0x62;
+ public static final byte INS_CLEANUP = (byte) 0x63;
+ public static final byte INS_SUPPORT = (byte) 0x64;
+
+ // 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;
+
+
+ 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;
+ // PERSISTENT ARRAY IN EEPROM
+ private byte[] dataArray = null; // unused
+
+
+ private RandomData randomData = null;
+
+ private ECKeyTester keyTester = null;
+ private short ecdhSW;
+ private short ecdhcSW;
+ private short ecdsaSW;
+ private ECKeyGenerator keyGenerator = null;
+ private KeyPair localKeypair = null;
+ private KeyPair remoteKeypair = null;
+
+ 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);
+
+ dataArray = new byte[ARRAY_LENGTH];
+ Util.arrayFillNonAtomic(dataArray, (short) 0, ARRAY_LENGTH, (byte) 0);
+
+ randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
+ EC_Consts.randomData = randomData;
+
+ keyGenerator = new ECKeyGenerator();
+ keyTester = new ECKeyTester();
+ ecdhSW = keyTester.allocateECDH();
+ ecdhcSW = keyTester.allocateECDHC();
+ ecdsaSW = keyTester.allocateECDSA();
+ }
+ register();
+ }
+
+ public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException {
+ // applet instance creation
+ 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) {
+ AppletUtil.readAPDU(apdu, apduArray, APDU_MAX_LENGTH);
+
+ short length = 0;
+ switch (ins) {
+ case INS_ALLOCATE:
+ length = insAllocate(apdu);
+ break;
+ case INS_CLEAR:
+ length = insClear(apdu);
+ break;
+ case INS_SET:
+ length = insSet(apdu);
+ break;
+ case INS_CORRUPT:
+ length = insCorrupt(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_CLEANUP:
+ length = insCleanup(apdu);
+ break;
+ case INS_SUPPORT:
+ length = insSupport(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);
+ } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Corrupts curve paramaters of local and remote keyPairs.
+ * returns corruptCurve SWs
+ *
+ * @param apdu P1 = byte keyPair (KEYPAIR_* | ...)
+ * P2 = byte key (EC_Consts.KEY_* | ...)
+ * DATA = short params (EC_Consts.PARAMETER_* | ...)
+ * byte corruption (EC_Consts.CORRUPTION_* || ...)
+ * @return length of response
+ */
+ private short insCorrupt(APDU apdu) {
+ byte keyPair = apduArray[ISO7816.OFFSET_P1];
+ byte key = apduArray[ISO7816.OFFSET_P2];
+ short cdata = apdu.getOffsetCdata();
+ short params = Util.getShort(apduArray, cdata);
+ byte corruption = apduArray[(short) (cdata + 2)];
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += corrupt(localKeypair, key, params, corruption, apdu.getBuffer(), (short) 0);
+ }
+
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += corrupt(remoteKeypair, key, params, corruption, 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 corruption (EC_Consts.CORRUPTION_* | ...)
+ * 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 corruption = Util.getShort(apduArray, (short) (cdata + 1));
+ byte type = apduArray[(short) (cdata + 3)];
+
+ return ecdh(pubkey, privkey, export, corruption, type, apdu.getBuffer(), (short) 0);
+ }
+
+ /**
+ *
+ * @param apdu P1 = byte privkey (KEYPAIR_*)
+ * @return P2 = byte export (EXPORT_TRUE || EXPORT_FALSE)
+ * DATA = short corruption (EC_Consts.CORRUPTION_* | ...)
+ * byte type (EC_Consts.KA_* | ...)
+ * short length
+ * byte[] pubkey
+ */
+ private short insECDH_direct(APDU apdu) {
+ byte privkey = apduArray[ISO7816.OFFSET_P1];
+ byte export = apduArray[ISO7816.OFFSET_P2];
+ short cdata = apdu.getOffsetCdata();
+ short corruption = Util.getShort(apduArray, cdata);
+ byte type = apduArray[(short) (cdata + 2)];
+ short length = Util.getShort(apduArray, (short) (cdata + 3));
+
+ return ecdh_direct(privkey, export, corruption, 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 = 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();
+
+ short len = 0;
+ if ((keyPair & KEYPAIR_LOCAL) != 0) {
+ len += ecdsa(localKeypair, export, apduArray, cdata, apdu.getBuffer(), (short) 0);
+ }
+ if ((keyPair & KEYPAIR_REMOTE) != 0) {
+ len += ecdsa(remoteKeypair, export, 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);
+ }
+
+ /**
+ * Returns data about card support for various EC related tasks collected on applet
+ * install.
+ *
+ * @param apdu no data
+ * @return length of response
+ */
+ private short insSupport(APDU apdu) {
+ byte[] apdubuf = apdu.getBuffer();
+
+ return support(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 corrupt
+ * @param key key to corrupt (EC_Consts.KEY_* | ...)
+ * @param params parameters to corrupt (EC_Consts.PARAMETER_* | ...)
+ * @param corruption corruption type (EC_Consts.CORRUPTION_*)
+ * @param outBuffer buffer to output sw to
+ * @param outOffset output offset in buffer
+ * @return length of data written to the buffer
+ */
+ private short corrupt(KeyPair keyPair, byte key, short params, byte corruption, byte[] outBuffer, short outOffset) {
+ short sw = keyGenerator.corruptCurve(keyPair, key, params, corruption, 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();
+ }
+ //TODO unify this, now that param key == the passed on param.
+ 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 corruption whether to invalidate the pubkey before ECDH
+ * @param type KeyAgreement type to test (EC_Consts.KA_* || ...)
+ * @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 corruption, 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;
+ switch (type) {
+ case EC_Consts.KA_ECDH:
+ secretLength = keyTester.testECDH(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ break;
+ case EC_Consts.KA_ECDHC:
+ secretLength = keyTester.testECDHC(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ break;
+ case EC_Consts.KA_BOTH:
+ secretLength = keyTester.testBOTH(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ break;
+ case EC_Consts.KA_ANY:
+ secretLength = keyTester.testANY(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption);
+ break;
+ default:
+ ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
+ }
+
+ 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 corruption, byte type, short keyOffset, short keyLength, byte[] outBuffer, short outOffset) {
+ short length = 0;
+
+ KeyPair priv = ((privkey & KEYPAIR_LOCAL) != 0) ? localKeypair : remoteKeypair;
+
+ short secretLength = 0;
+ switch (type) {
+ case EC_Consts.KA_ECDH:
+ secretLength = keyTester.testECDH_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
+ break;
+ case EC_Consts.KA_ECDHC:
+ secretLength = keyTester.testECDHC_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
+ break;
+ case EC_Consts.KA_BOTH:
+ secretLength = keyTester.testBOTH_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
+ break;
+ case EC_Consts.KA_ANY:
+ secretLength = keyTester.testANY_direct(priv, apduArray, keyOffset, keyLength, outBuffer, outOffset, corruption);
+ break;
+ default:
+ ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
+ }
+
+ 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 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 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 = 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;
+ }
+
+ /**
+ * @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 support(byte[] buffer, short offset) {
+
+ if (keyTester.hasECDH()) {
+ Util.setShort(buffer, offset, ecdhSW);
+ } else {
+ Util.setShort(buffer, offset, ISO7816.SW_FUNC_NOT_SUPPORTED);
+ }
+ if (keyTester.hasECDHC()) {
+ Util.setShort(buffer, (short) (offset + 2), ecdhcSW);
+ } else {
+ Util.setShort(buffer, (short) (offset + 2), ISO7816.SW_FUNC_NOT_SUPPORTED);
+ }
+ if (keyTester.hasECDSA()) {
+ Util.setShort(buffer, (short) (offset + 4), ecdsaSW);
+ } else {
+ Util.setShort(buffer, (short) (offset + 4), ISO7816.SW_FUNC_NOT_SUPPORTED);
+ }
+
+ return 6;
+ }
+}