diff options
| author | J08nY | 2018-11-06 16:12:09 +0100 |
|---|---|---|
| committer | J08nY | 2018-11-06 16:12:09 +0100 |
| commit | c676bacffd1305e1efc49b34d87ffd0a0a695ea7 (patch) | |
| tree | e3efe9f24d9be1064857ba9756de48134997a628 /src/cz/crcs/ectester/applet/AppletBase.java | |
| parent | 99e46d99005784ac1b8815c85cfd56994f8f1feb (diff) | |
| download | ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.tar.gz ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.tar.zst ECTester-c676bacffd1305e1efc49b34d87ffd0a0a695ea7.zip | |
Diffstat (limited to 'src/cz/crcs/ectester/applet/AppletBase.java')
| -rw-r--r-- | src/cz/crcs/ectester/applet/AppletBase.java | 878 |
1 files changed, 878 insertions, 0 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..aa6bc07 --- /dev/null +++ b/src/cz/crcs/ectester/applet/AppletBase.java @@ -0,0 +1,878 @@ +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 = 0xff; + 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; + return length; + } +} |
