diff options
| -rw-r--r-- | !uploader/simpleECC.cap | bin | 4938 -> 6000 bytes | |||
| -rw-r--r-- | !uploader/simpleECC_testECFull.txt | 12 | ||||
| -rw-r--r-- | src/applets/EC_Consts.java | 115 | ||||
| -rw-r--r-- | src/applets/SimpleECCApplet.java | 394 | ||||
| -rw-r--r-- | src/simpleapdu/CardMngr.java | 1 | ||||
| -rw-r--r-- | src/simpleapdu/SimpleAPDU.java | 81 |
6 files changed, 446 insertions, 157 deletions
diff --git a/!uploader/simpleECC.cap b/!uploader/simpleECC.cap Binary files differindex 62e38b6..340da7c 100644 --- a/!uploader/simpleECC.cap +++ b/!uploader/simpleECC.cap diff --git a/!uploader/simpleECC_testECFull.txt b/!uploader/simpleECC_testECFull.txt new file mode 100644 index 0000000..acb4c4d --- /dev/null +++ b/!uploader/simpleECC_testECFull.txt @@ -0,0 +1,12 @@ +mode_211 +enable_trace +establish_context +card_connect + +select -AID 4C6162616B4170706C6574 + +send_apdu -APDU B05e000000 + + +card_disconnect +release_context diff --git a/src/applets/EC_Consts.java b/src/applets/EC_Consts.java index 7923c91..996766b 100644 --- a/src/applets/EC_Consts.java +++ b/src/applets/EC_Consts.java @@ -3,11 +3,13 @@ */ package applets; +import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.Util; import javacard.security.ECPrivateKey; import javacard.security.ECPublicKey; import javacard.security.KeyBuilder; +import javacard.security.KeyPair; public class EC_Consts { public static byte[] EC_FP_P = null; @@ -130,55 +132,76 @@ public class EC_Consts { // TODO: add parameters for longer lengths - public static void setECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, short ecLength, byte[] auxBuffer) { - // Select proper courve parameters - switch (ecLength) { - case (short) 192: { - EC_FP_P = EC192_FP_P; - EC_FP_A = EC192_FP_A; - EC_FP_B = EC192_FP_B; - EC_FP_G_X = EC192_FP_G_X; - EC_FP_G_Y = EC192_FP_G_Y; - EC_FP_R = EC192_FP_R; - EC_FP_K = EC192_FP_K; - break; + public static void setValidECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, byte ecClass, short ecLength, byte[] auxBuffer) { + setECKeyParams(ecPubKey, ecPrivKey, ecClass, ecLength, auxBuffer, false); + } + public static void setInValidECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, byte ecClass, short ecLength, byte[] auxBuffer) { + setECKeyParams(ecPubKey, ecPrivKey, ecClass, ecLength, auxBuffer, true); + } + private static void setECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, byte ecClass, short ecLength, byte[] auxBuffer, boolean bInvalidCurve) { + if (ecClass == KeyPair.ALG_EC_FP) { + // Select proper courve parameters + switch (ecLength) { + case (short) 192: { + EC_FP_P = EC192_FP_P; + EC_FP_A = EC192_FP_A; + EC_FP_B = EC192_FP_B; + EC_FP_G_X = EC192_FP_G_X; + EC_FP_G_Y = EC192_FP_G_Y; + EC_FP_R = EC192_FP_R; + EC_FP_K = EC192_FP_K; + break; + } + case (short) 256: { + EC_FP_P = EC256_FP_P; + EC_FP_A = EC256_FP_A; + EC_FP_B = EC256_FP_B; + EC_FP_G_X = EC256_FP_G_X; + EC_FP_G_Y = EC256_FP_G_Y; + EC_FP_R = EC256_FP_R; + EC_FP_K = EC256_FP_K; + break; + } + default: { + ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); + } } - case (short) 256: { - EC_FP_P = EC256_FP_P; - EC_FP_A = EC256_FP_A; - EC_FP_B = EC256_FP_B; - EC_FP_G_X = EC256_FP_G_X; - EC_FP_G_Y = EC256_FP_G_Y; - EC_FP_R = EC256_FP_R; - EC_FP_K = EC256_FP_K; - break; - } - default: { - ISOException.throwIt((short) -1); + + // prepare an ANSI X9.62 uncompressed EC point representation for G + short gSize = (short) 1; + gSize += (short) EC_FP_G_X.length; + gSize += (short) EC_FP_G_Y.length; + auxBuffer[0] = 0x04; + short off = 1; + off = Util.arrayCopyNonAtomic(EC_FP_G_X, (short) 0, auxBuffer, off, (short) EC_FP_G_X.length); + Util.arrayCopyNonAtomic(EC_FP_G_Y, (short) 0, auxBuffer, off, (short) EC_FP_G_Y.length); + + // pre-set basic EC parameters: + ecPubKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length); + ecPubKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length); + ecPubKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length); + if (bInvalidCurve) { // corrupt curve + Util.arrayCopyNonAtomic(EC_FP_B, (short) 0, auxBuffer, (short) 0, (short) EC_FP_B.length); + auxBuffer[(byte) 10] = (byte) 0xcc; + auxBuffer[(byte) 11] = (byte) 0xcc; + ecPubKey.setB(auxBuffer, (short) 0, (short) EC_FP_B.length); } - } - // prepare an ANSI X9.62 uncompressed EC point representation for G - short gSize = (short) 1; - gSize += (short) EC_FP_G_X.length; - gSize += (short) EC_FP_G_Y.length; - auxBuffer[0] = 0x04; - short off = 1; - off = Util.arrayCopy(EC_FP_G_X, (short) 0, auxBuffer, off, (short) EC_FP_G_X.length); - Util.arrayCopy(EC_FP_G_Y, (short) 0, auxBuffer, off, (short) EC_FP_G_Y.length); + + ecPubKey.setG(auxBuffer, (short) 0, gSize); + ecPubKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length); + ecPubKey.setK(EC_FP_K); - // pre-set basic EC parameters: - ecPubKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length); - ecPubKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length); - ecPubKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length); - ecPubKey.setG(auxBuffer, (short) 0, gSize); - ecPubKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length); - ecPubKey.setK(EC_FP_K); + ecPrivKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length); + ecPrivKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length); + ecPrivKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length); + ecPrivKey.setG(auxBuffer, (short) 0, gSize); + ecPrivKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length); + ecPrivKey.setK(EC_FP_K); + } + if (ecClass == KeyPair.ALG_EC_F2M) { + // Not supported yet + ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); + } - ecPrivKey.setFieldFP(EC_FP_P, (short) 0, (short) EC_FP_P.length); - ecPrivKey.setA(EC_FP_A, (short) 0, (short) EC_FP_A.length); - ecPrivKey.setB(EC_FP_B, (short) 0, (short) EC_FP_B.length); - ecPrivKey.setG(auxBuffer, (short) 0, gSize); - ecPrivKey.setR(EC_FP_R, (short) 0, (short) EC_FP_R.length); - ecPrivKey.setK(EC_FP_K); } } diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java index 325d834..ab6eede 100644 --- a/src/applets/SimpleECCApplet.java +++ b/src/applets/SimpleECCApplet.java @@ -16,9 +16,13 @@ public class SimpleECCApplet extends javacard.framework.Applet // INSTRUCTIONS final static byte INS_GENERATEKEY = (byte) 0x5a; final static byte INS_ALLOCATEKEYPAIRS = (byte) 0x5b; + final static byte INS_ALLOCATEKEYPAIR = (byte) 0x5c; final static byte INS_DERIVEECDHSECRET = (byte) 0x5d; + final static byte INS_TESTECSUPPORTALL = (byte) 0x5e; + + final static short ARRAY_LENGTH = (short) 0xff; final static byte AES_BLOCK_LENGTH = (short) 0x16; @@ -26,6 +30,16 @@ public class SimpleECCApplet extends javacard.framework.Applet final static short EC_LENGTH_BITS = KeyBuilder.LENGTH_EC_FP_192; //final static short EC_LENGTH_BITS = KeyBuilder.LENGTH_EC_FP_160; //final static short EC_LENGTH_BITS = (short) 256; + + public final static byte ECTEST_SEPARATOR = (byte) 0xff; + public final static byte ECTEST_ALLOCATE_KEYPAIR = (byte) 0xc1; + public final static byte ECTEST_GENERATE_KEYPAIR_DEFCURVE = (byte) 0xc2; + public final static byte ECTEST_SET_VALIDCURVE = (byte) 0xc3; + public final static byte ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE = (byte) 0xc4; + public final static byte ECTEST_SET_INVALIDCURVE = (byte) 0xc5; + public final static byte ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE = (byte) 0xc6; + + public final static short SW_SKIPPED = (short) 0x0ee1; /* public static final byte[] EC192_FP_PUBLICW = new byte[]{ (byte) 0x04, (byte) 0xC9, (byte) 0xC0, (byte) 0xED, (byte) 0xFB, (byte) 0x27, @@ -118,6 +132,9 @@ public class SimpleECCApplet extends javacard.framework.Applet if (apduBuffer[ISO7816.OFFSET_CLA] == CLA_SIMPLEECCAPPLET) { switch ( apduBuffer[ISO7816.OFFSET_INS] ) { + case INS_TESTECSUPPORTALL: + TestECSupportAllLengths(apdu); + break; case INS_ALLOCATEKEYPAIR: AllocateKeyPairReturnDefCourve(apdu); break; @@ -141,6 +158,274 @@ public class SimpleECCApplet extends javacard.framework.Applet else ISOException.throwIt( ISO7816.SW_CLA_NOT_SUPPORTED); } + + void AllocateKeyPairReturnDefCourve(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + apdu.setIncomingAndReceive(); + + short bitLen = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA); + + // Note: all locations shoudl happen in constructor. But here it is intentional + // as we like to test for result of allocation + ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, bitLen); + + // If required, generate also new key pair + if (apdubuf[ISO7816.OFFSET_P1] == (byte) 1) { + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + // Some implementation wil not return valid pub key until ecKeyPair.genKeyPair() is called + // Other implementation will fail with exception if same is called => try catch + try { + if (ecPubKey == null) { + ecKeyPair.genKeyPair(); + } + } catch (Exception e) { + } // do nothing + + // If required, initialize curve parameters first + if (apdubuf[ISO7816.OFFSET_P2] == (byte) 2) { + EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, bitLen, m_ramArray); + } + + // Now generate new keypair with either default or custom curve + ecKeyPair.genKeyPair(); + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + + short len = 0; + short offset = 0; + + // Export curve public parameters + offset += 2; // reserve space for length + len = ecPubKey.getField(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + offset += 2; // reserve space for length + len = ecPubKey.getA(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + + offset += 2; // reserve space for length + len = ecPubKey.getB(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + offset += 2; // reserve space for length + len = ecPubKey.getR(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + /* + offset += 2; // reserve space for length + len = ecPubKey.getW(apdubuf, offset); + Util.setShort(apdubuf, (short) (offset - 2), len); + offset += len; + */ + apdu.setOutgoingAndSend((short) 0, offset); + } + } + + + + void DeriveECDHSecret(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + short len = apdu.setIncomingAndReceive(); + + // Assumption: proper EC keyPair is already allocated + // If public key point is provided, then use it + if (len == 0) { + // if not provided, use build-in one (valid for for 192 only) + Util.arrayCopyNonAtomic(EC192_FP_PUBLICW, (short) 0, apdubuf, ISO7816.OFFSET_CDATA, (short) EC192_FP_PUBLICW.length); + len = (short) EC192_FP_PUBLICW.length; + } + + // Generate fresh EC keypair + ecKeyPair.genKeyPair(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + + dhKeyAgreement.init(ecPrivKey); + short secretLen = 0; + // Generate and export secret + secretLen = dhKeyAgreement.generateSecret(apdubuf, ISO7816.OFFSET_CDATA, len, m_ramArray, (short) 0); + Util.arrayCopyNonAtomic(m_ramArray, (short) 0, apdubuf, (short) 0, secretLen); + + apdu.setOutgoingAndSend((short) 0, secretLen); + } + + short TestECSupport(byte keyClass, short keyLen, byte[] buffer, short bufferOffset) { + short baseOffset = bufferOffset; + + ecKeyPair = null; + ecPubKey = null; + ecPrivKey = null; + + buffer[bufferOffset] = ECTEST_SEPARATOR; bufferOffset++; + buffer[bufferOffset] = keyClass; bufferOffset++; + Util.setShort(buffer, bufferOffset, keyLen); bufferOffset += 2; + // + // 1. Allocate KeyPair object + // + buffer[bufferOffset] = ECTEST_ALLOCATE_KEYPAIR; bufferOffset++; + try { + ecKeyPair = new KeyPair(keyClass, keyLen); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); bufferOffset += 2; + } + catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); bufferOffset += 2; + } + catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + + // + // 2. Test keypair generation without explicit curve (=> default curve preset) + // + buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_DEFCURVE; bufferOffset++; + try { + ecKeyPair.genKeyPair(); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); + bufferOffset += 2; + } catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); + bufferOffset += 2; + } + catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + + // + // 3. Set valid custom curve + // + buffer[bufferOffset] = ECTEST_SET_VALIDCURVE; + bufferOffset++; + boolean bGenerateKey = false; + try { + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + // Some implementation wil not return valid pub key until ecKeyPair.genKeyPair() is called + // Other implementation will fail with exception if same is called => try catch + try { + if (ecPubKey == null) { + ecKeyPair.genKeyPair(); + } + } catch (Exception e) {} // do intentionally nothing + + // Initialize curve parameters + EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); + bufferOffset += 2; + + bGenerateKey = true; + } catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); + bufferOffset += 2; + } + catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + + // + // 4. Generate keypair with custom curve + // + buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE; + bufferOffset++; + if (bGenerateKey) { + try { + ecKeyPair.genKeyPair(); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); + bufferOffset += 2; + } catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); + bufferOffset += 2; + } catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + } + else { + Util.setShort(buffer, bufferOffset, SW_SKIPPED); + bufferOffset += 2; + } + // + // 5. Set invalid custom curve + // + buffer[bufferOffset] = ECTEST_SET_INVALIDCURVE; + bufferOffset++; + bGenerateKey = false; + try { + // Initialize curve parameters + EC_Consts.setInValidECKeyParams(ecPubKey, ecPrivKey, keyClass, keyLen, m_ramArray); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); + bufferOffset += 2; + bGenerateKey = true; + } catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); + bufferOffset += 2; + } catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + + // + // 6. Generate keypair with invalid custom curve + // + buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE; + bufferOffset++; + if (bGenerateKey) { + try { + ecKeyPair.genKeyPair(); + Util.setShort(buffer, bufferOffset, ISO7816.SW_NO_ERROR); + bufferOffset += 2; + } catch (CryptoException e) { + Util.setShort(buffer, bufferOffset, e.getReason()); + bufferOffset += 2; + } catch (Exception e) { + Util.setShort(buffer, bufferOffset, ISO7816.SW_UNKNOWN); + bufferOffset += 2; + } + } else { + Util.setShort(buffer, bufferOffset, SW_SKIPPED); + bufferOffset += 2; + } + + return (short) (bufferOffset - baseOffset); + } + void TestECSupportAllLengths(APDU apdu) { + byte[] apdubuf = apdu.getBuffer(); + short len = apdu.setIncomingAndReceive(); + + short dataOffset = 0; + // FP - + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 128, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 160, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 192, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 224, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 256, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 384, apdubuf, dataOffset); + dataOffset += TestECSupport(KeyPair.ALG_EC_FP, (short) 521, apdubuf, dataOffset); + + apdu.setOutgoingAndSend((short) 0, dataOffset); + } + + + + + + + + + + + + + + + + + + + void AllocateKeyPair(byte algorithm, short bitLen) { // Select proper attributes switch (bitLen) { @@ -185,7 +470,7 @@ public class SimpleECCApplet extends javacard.framework.Applet ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); // Set required EC parameters - EC_Consts.setECKeyParams(ecPubKey, ecPrivKey, bitLen, m_ramArray); + EC_Consts.setValidECKeyParams(ecPubKey, ecPrivKey, KeyPair.ALG_EC_FP, bitLen, m_ramArray); } short TryAllocateKeyPair(byte algorithm, short bitLen, byte[] buffer, short offset) { @@ -215,114 +500,9 @@ public class SimpleECCApplet extends javacard.framework.Applet apdu.setOutgoingAndSend((short) 0, offset); } - void AllocateKeyPairReturnDefCourve(APDU apdu) { - byte[] apdubuf = apdu.getBuffer(); - apdu.setIncomingAndReceive(); - - short bitLen = Util.getShort(apdubuf, ISO7816.OFFSET_CDATA); - - // Note: all locations shoudl happen in constructor. But here it is intentional - // as we like to test for result of allocation - ecKeyPair = new KeyPair(KeyPair.ALG_EC_FP, bitLen); - - // If required, generate also new key pair - if (apdubuf[ISO7816.OFFSET_P1] == (byte) 1) { - ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); - ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); - // Some implementation wil not return valid pub key until ecKeyPair.genKeyPair() is called - // Other implementation will fail with exception if same is called => try catch - try { - if (ecPubKey == null) {ecKeyPair.genKeyPair();} - } - catch (Exception e) {} // do nothing - - - // If required, initialize curve parameters first - if (apdubuf[ISO7816.OFFSET_P2] == (byte) 2) { - EC_Consts.setECKeyParams(ecPubKey, ecPrivKey, bitLen, m_ramArray); - } - - // Now generate new keypair with either default or custom curve - ecKeyPair.genKeyPair(); - ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); - ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); - - short len = 0; - short offset = 0; - - // Export curve public parameters - offset += 2; // reserve space for length - len = ecPubKey.getField(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; - offset += 2; // reserve space for length - len = ecPubKey.getA(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; - offset += 2; // reserve space for length - len = ecPubKey.getB(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; - offset += 2; // reserve space for length - len = ecPubKey.getR(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; -/* - offset += 2; // reserve space for length - len = ecPubKey.getW(apdubuf, offset); - Util.setShort(apdubuf, (short) (offset - 2), len); - offset += len; -*/ - apdu.setOutgoingAndSend((short) 0, offset); - } - } -/** - For a first quick test, this would be the workflow: - * - * 1. Import a given ECC public key (i.e. a point that is not on the curve) - * - * 2. Generate a fresh ECC keypair - * - * 3. Perform a ECDH key-derivation with the keys from steps 1 and 2 - * - * 4. Repeat steps 2 & 3 a couple of times and record the generated secrets - * - * - * - * If the card is vulnerable, then the generated secrets will repeat. For - * example, we have points of order 5. With such a point and a vulnerable - * card, there are only 5 (or even less) different possible values for the - * generated secrets. This is pretty obvious, if you do a couple of (e.g. - * +-10) key-derivations ;) - * @param apdu - */ - void DeriveECDHSecret(APDU apdu) { - byte[] apdubuf = apdu.getBuffer(); - short len = apdu.setIncomingAndReceive(); - - // Assumption: proper EC keyPair is already allocated - - // If public key point is provided, then use it - if (len == 0) { - // if not provided, use build-in one - Util.arrayCopyNonAtomic(EC192_FP_PUBLICW, (short) 0, apdubuf, ISO7816.OFFSET_CDATA, (short) EC192_FP_PUBLICW.length); - len = (short) EC192_FP_PUBLICW.length; - } - - // Generate fresh EC keypair - ecKeyPair.genKeyPair(); - ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); - - dhKeyAgreement.init(ecPrivKey); - short secretLen = 0; - // Generate and export secret - secretLen = dhKeyAgreement.generateSecret(apdubuf, ISO7816.OFFSET_CDATA, len, m_ramArray, (short) 0); - Util.arrayCopyNonAtomic(m_ramArray, (short) 0, apdubuf, (short) 0, secretLen); - - apdu.setOutgoingAndSend((short) 0, secretLen); - } + void GenerateKey(APDU apdu) { diff --git a/src/simpleapdu/CardMngr.java b/src/simpleapdu/CardMngr.java index d3ff86b..1ab6408 100644 --- a/src/simpleapdu/CardMngr.java +++ b/src/simpleapdu/CardMngr.java @@ -165,6 +165,7 @@ public class CardMngr { return buf.toString(); } + public char toHexChar(int i) { if ((0 <= i) && (i <= 9)) { return (char) ('0' + i); diff --git a/src/simpleapdu/SimpleAPDU.java b/src/simpleapdu/SimpleAPDU.java index 240a1cf..d1e6ff1 100644 --- a/src/simpleapdu/SimpleAPDU.java +++ b/src/simpleapdu/SimpleAPDU.java @@ -1,6 +1,9 @@ package simpleapdu; import applets.SimpleECCApplet; +import javacard.framework.ISO7816; +import javacard.security.CryptoException; +import javacard.security.KeyPair; import javax.smartcardio.ResponseAPDU; /** @@ -24,6 +27,12 @@ public class SimpleAPDU { private static byte GENERATEKEY[] = {(byte) 0xB0, (byte) 0x5A, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00}; private static byte RESPONDDATA[] = {(byte) 0xB0, (byte) 0x5B, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x30}; + private static byte TESTECSUPPORTALL[] = {(byte) 0xB0, (byte) 0x5E, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + + static short getShort(byte[] array, int offset) { + return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); + } + public static void main(String[] args) { try { // @@ -62,10 +71,8 @@ public class SimpleAPDU { // Select our application on card cardManager.sendAPDU(SELECT_SIMPLEAPPLET); - for (int i = 0; i < 10; i++) { - cardManager.sendAPDU(GENERATEKEY); - } - cardManager.sendAPDU(RESPONDDATA); + ResponseAPDU resp = cardManager.sendAPDU(TESTECSUPPORTALL); + PrintECSupport(resp); cardManager.DisconnectFromCard(); } else { @@ -75,4 +82,70 @@ public class SimpleAPDU { System.out.println("Exception : " + ex); } } + + static String getPrintError(short code) { + if (code == ISO7816.SW_NO_ERROR) { + return "OK\t(0x9000)"; + } + else { + String codeStr = "unknown"; + if (code == CryptoException.ILLEGAL_VALUE) { + codeStr = "ILLEGAL_VALUE"; + } + if (code == CryptoException.UNINITIALIZED_KEY) { + codeStr = "UNINITIALIZED_KEY"; + } + if (code == CryptoException.NO_SUCH_ALGORITHM) { + codeStr = "NO_SUCH_ALG"; + } + if (code == CryptoException.INVALID_INIT) { + codeStr = "INVALID_INIT"; + } + if (code == CryptoException.ILLEGAL_USE) { + codeStr = "ILLEGAL_USE"; + } + if (code == SimpleECCApplet.SW_SKIPPED) { + codeStr = "skipped"; + } + return String.format("fail\t(%s,\t0x%4x)", codeStr, code); + } + } + static int VerifyPrintResult(String message, byte expectedTag, byte[] buffer, int bufferOffset) { + assert (buffer[bufferOffset] == expectedTag); + bufferOffset++; + short resCode = getShort(buffer, bufferOffset); + bufferOffset += 2; + System.out.println(String.format("%-40s%s", message, getPrintError(resCode))); + return bufferOffset; + } + static void PrintECSupport(ResponseAPDU resp) { + byte[] buffer = resp.getData(); + + int bufferOffset = 0; + while (bufferOffset < buffer.length) { + assert(buffer[bufferOffset] == SimpleECCApplet.ECTEST_SEPARATOR); + bufferOffset++; + String ecType = "unknown"; + if (buffer[bufferOffset] == KeyPair.ALG_EC_FP) { + ecType = "ALG_EC_FP"; + } + if (buffer[bufferOffset] == KeyPair.ALG_EC_F2M) { + ecType = "ALG_EC_F2M"; + } + System.out.println(String.format("%-40s%s", "EC type:", ecType)); + bufferOffset++; + short keyLen = getShort(buffer, bufferOffset); + System.out.println(String.format("%-40s%d bits", "EC key length (bits):", keyLen)); + bufferOffset += 2; + + bufferOffset = VerifyPrintResult("KeyPair object allocation:", SimpleECCApplet.ECTEST_ALLOCATE_KEYPAIR, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("Generate key with def curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_DEFCURVE, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("Set valid custom curve:", SimpleECCApplet.ECTEST_SET_VALIDCURVE, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("Generate key with valid curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("Set invalid custom curve:", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("Generate key with invalid curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE, buffer, bufferOffset); + + System.out.println(); + } + } } |
