diff options
| -rw-r--r-- | !uploader/simpleECC.cap | bin | 6852 -> 7687 bytes | |||
| -rw-r--r-- | src/applets/EC_Consts.java | 102 | ||||
| -rw-r--r-- | src/applets/SimpleECCApplet.java | 72 | ||||
| -rw-r--r-- | src/simpleapdu/SimpleAPDU.java | 42 |
4 files changed, 200 insertions, 16 deletions
diff --git a/!uploader/simpleECC.cap b/!uploader/simpleECC.cap Binary files differindex 2f78be2..e194d6a 100644 --- a/!uploader/simpleECC.cap +++ b/!uploader/simpleECC.cap diff --git a/src/applets/EC_Consts.java b/src/applets/EC_Consts.java index a4164ac..dd58bed 100644 --- a/src/applets/EC_Consts.java +++ b/src/applets/EC_Consts.java @@ -279,7 +279,97 @@ public class EC_Consts { // cofactor of G public static final short EC256_FP_K = 1; - // TODO: add parameters for longer lengths + // secp384r1 from http://www.secg.org/sec2-v2.pdf + public static final byte[] EC384_FP_P = new byte[]{ + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + + public static final byte[] EC384_FP_A = new byte[]{ + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFC}; + + public static final byte[] EC384_FP_B = new byte[]{ + (byte) 0xB3, (byte) 0x31, (byte) 0x2F, (byte) 0xA7, + (byte) 0xE2, (byte) 0x3E, (byte) 0xE7, (byte) 0xE4, + (byte) 0x98, (byte) 0x8E, (byte) 0x05, (byte) 0x6B, + (byte) 0xE3, (byte) 0xF8, (byte) 0x2D, (byte) 0x19, + (byte) 0x18, (byte) 0x1D, (byte) 0x9C, (byte) 0x6E, + (byte) 0xFE, (byte) 0x81, (byte) 0x41, (byte) 0x12, + (byte) 0x03, (byte) 0x14, (byte) 0x08, (byte) 0x8F, + (byte) 0x50, (byte) 0x13, (byte) 0x87, (byte) 0x5A, + (byte) 0xC6, (byte) 0x56, (byte) 0x39, (byte) 0x8D, + (byte) 0x8A, (byte) 0x2E, (byte) 0xD1, (byte) 0x9D, + (byte) 0x2A, (byte) 0x85, (byte) 0xC8, (byte) 0xED, + (byte) 0xD3, (byte) 0xEC, (byte) 0x2A, (byte) 0xEF}; + + // G in compressed form / first part of ucompressed + public static final byte[] EC384_FP_G_X = new byte[]{ + (byte) 0xAA, (byte) 0x87, (byte) 0xCA, (byte) 0x22, + (byte) 0xBE, (byte) 0x8B, (byte) 0x05, (byte) 0x37, + (byte) 0x8E, (byte) 0xB1, (byte) 0xC7, (byte) 0x1E, + (byte) 0xF3, (byte) 0x20, (byte) 0xAD, (byte) 0x74, + (byte) 0x6E, (byte) 0x1D, (byte) 0x3B, (byte) 0x62, + (byte) 0x8B, (byte) 0xA7, (byte) 0x9B, (byte) 0x98, + (byte) 0x59, (byte) 0xF7, (byte) 0x41, (byte) 0xE0, + (byte) 0x82, (byte) 0x54, (byte) 0x2A, (byte) 0x38, + (byte) 0x55, (byte) 0x02, (byte) 0xF2, (byte) 0x5D, + (byte) 0xBF, (byte) 0x55, (byte) 0x29, (byte) 0x6C, + (byte) 0x3A, (byte) 0x54, (byte) 0x5E, (byte) 0x38, + (byte) 0x72, (byte) 0x76, (byte) 0x0A, (byte) 0xB7}; + // second part of G uncompressed + public static final byte[] EC384_FP_G_Y = new byte[]{ + (byte) 0x36, (byte) 0x17, (byte) 0xDE, (byte) 0x4A, + (byte) 0x96, (byte) 0x26, (byte) 0x2C, (byte) 0x6F, + (byte) 0x5D, (byte) 0x9E, (byte) 0x98, (byte) 0xBF, + (byte) 0x92, (byte) 0x92, (byte) 0xDC, (byte) 0x29, + (byte) 0xF8, (byte) 0xF4, (byte) 0x1D, (byte) 0xBD, + (byte) 0x28, (byte) 0x9A, (byte) 0x14, (byte) 0x7C, + (byte) 0xE9, (byte) 0xDA, (byte) 0x31, (byte) 0x13, + (byte) 0xB5, (byte) 0xF0, (byte) 0xB8, (byte) 0xC0, + (byte) 0x0A, (byte) 0x60, (byte) 0xB1, (byte) 0xCE, + (byte) 0x1D, (byte) 0x7E, (byte) 0x81, (byte) 0x9D, + (byte) 0x7A, (byte) 0x43, (byte) 0x1D, (byte) 0x7C, + (byte) 0x90, (byte) 0xEA, (byte) 0x0E, (byte) 0x5F}; + + // Order of G + public static final byte[] EC384_FP_R = new byte[]{ + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xC7, (byte) 0x63, (byte) 0x4D, (byte) 0x81, + (byte) 0xF4, (byte) 0x37, (byte) 0x2D, (byte) 0xDF, + (byte) 0x58, (byte) 0x1A, (byte) 0x0D, (byte) 0xB2, + (byte) 0x48, (byte) 0xB0, (byte) 0xA7, (byte) 0x7A, + (byte) 0xEC, (byte) 0xEC, (byte) 0x19, (byte) 0x6A, + (byte) 0xCC, (byte) 0xC5, (byte) 0x29, (byte) 0x73}; + // cofactor of G + public static final short EC384_FP_K = 1; + + // TODO: secp521r1 + public static void setValidECKeyParams(ECPublicKey ecPubKey, ECPrivateKey ecPrivKey, byte ecClass, short ecLength, byte[] auxBuffer) { setECKeyParams(ecPubKey, ecPrivKey, ecClass, ecLength, auxBuffer, false); @@ -341,6 +431,16 @@ public class EC_Consts { EC_FP_K = EC256_FP_K; break; } + case (short) 384: { + EC_FP_P = EC384_FP_P; + EC_FP_A = EC384_FP_A; + EC_FP_B = EC384_FP_B; + EC_FP_G_X = EC384_FP_G_X; + EC_FP_G_Y = EC384_FP_G_Y; + EC_FP_R = EC384_FP_R; + EC_FP_K = EC384_FP_K; + break; + } default: { ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); } diff --git a/src/applets/SimpleECCApplet.java b/src/applets/SimpleECCApplet.java index ab6eede..b9fd347 100644 --- a/src/applets/SimpleECCApplet.java +++ b/src/applets/SimpleECCApplet.java @@ -38,6 +38,8 @@ public class SimpleECCApplet extends javacard.framework.Applet 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 byte ECTEST_ECDH_AGREEMENT_VALID_POINT = (byte) 0xc7; + public final static byte ECTEST_ECDH_AGREEMENT_INVALID_POINT = (byte) 0xc8; public final static short SW_SKIPPED = (short) 0x0ee1; /* @@ -83,7 +85,8 @@ public class SimpleECCApplet extends javacard.framework.Applet private KeyAgreement dhKeyAgreement = null; // TEMPORARRY ARRAY IN RAM - private byte m_ramArray[] = null; + private byte m_ramArray[] = null; + private byte m_ramArray2[] = null; // PERSISTENT ARRAY IN EEPROM private byte m_dataArray[] = null; @@ -99,10 +102,10 @@ public class SimpleECCApplet extends javacard.framework.Applet dataOffset++; m_ramArray = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); + m_ramArray2 = JCSystem.makeTransientByteArray(ARRAY_LENGTH, JCSystem.CLEAR_ON_RESET); + m_dataArray = new byte[ARRAY_LENGTH]; Util.arrayFillNonAtomic(m_dataArray, (short) 0, ARRAY_LENGTH, (byte) 0); - - dhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false); } register(); @@ -241,6 +244,9 @@ public class SimpleECCApplet extends javacard.framework.Applet ecKeyPair.genKeyPair(); ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + if (dhKeyAgreement == null) { + dhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false); + } dhKeyAgreement.init(ecPrivKey); short secretLen = 0; // Generate and export secret @@ -347,8 +353,64 @@ public class SimpleECCApplet extends javacard.framework.Applet Util.setShort(buffer, bufferOffset, SW_SKIPPED); bufferOffset += 2; } + + // + // 5. ECDH agreement with valid public key + // + buffer[bufferOffset] = ECTEST_ECDH_AGREEMENT_VALID_POINT; + bufferOffset++; + try { + // Generate fresh EC keypair + ecKeyPair.genKeyPair(); + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + if (dhKeyAgreement == null) { + dhKeyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false); + } + dhKeyAgreement.init(ecPrivKey); + + short pubKeyLen = ecPubKey.getW(m_ramArray, (short) 0); + short secretLen = dhKeyAgreement.generateSecret(m_ramArray, (short) 0, pubKeyLen, m_ramArray2, (short) 0); + + 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; + } + + // + // 6. ECDH agreement with invalid public key + // + buffer[bufferOffset] = ECTEST_ECDH_AGREEMENT_VALID_POINT; + bufferOffset++; + try { + // Generate fresh EC keypair + ecKeyPair.genKeyPair(); + ecPubKey = (ECPublicKey) ecKeyPair.getPublic(); + ecPrivKey = (ECPrivateKey) ecKeyPair.getPrivate(); + dhKeyAgreement.init(ecPrivKey); + + short pubKeyLen = ecPubKey.getW(m_ramArray, (short) 0); + m_ramArray[(byte) 10] = (byte) 0xcc; // Corrupt public key + m_ramArray[(byte) 11] = (byte) 0xcc; + short secretLen = dhKeyAgreement.generateSecret(m_ramArray, (short) 0, pubKeyLen, m_ramArray2, (short) 0); + + 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; + } + // - // 5. Set invalid custom curve + // 7. Set invalid custom curve // buffer[bufferOffset] = ECTEST_SET_INVALIDCURVE; bufferOffset++; @@ -368,7 +430,7 @@ public class SimpleECCApplet extends javacard.framework.Applet } // - // 6. Generate keypair with invalid custom curve + // 8. Generate keypair with invalid custom curve // buffer[bufferOffset] = ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE; bufferOffset++; diff --git a/src/simpleapdu/SimpleAPDU.java b/src/simpleapdu/SimpleAPDU.java index 5b10cee..428d4f4 100644 --- a/src/simpleapdu/SimpleAPDU.java +++ b/src/simpleapdu/SimpleAPDU.java @@ -110,17 +110,37 @@ public class SimpleAPDU { return String.format("fail\t(%s,\t0x%4x)", codeStr, code); } } - static int VerifyPrintResult(String message, byte expectedTag, byte[] buffer, int bufferOffset) { + + enum ExpResult { + SHOULD_SUCCEDD, + MAY_FAIL, + MUST_FAIL + } + static int VerifyPrintResult(String message, byte expectedTag, byte[] buffer, int bufferOffset, ExpResult expRes) { assert (buffer[bufferOffset] == expectedTag); bufferOffset++; short resCode = getShort(buffer, bufferOffset); bufferOffset += 2; - System.out.println(String.format("%-50s%s", message, getPrintError(resCode))); + + boolean bHiglight = false; + if ((expRes == ExpResult.MUST_FAIL) && (resCode == ISO7816.SW_NO_ERROR)) { + bHiglight = true; + } + if ((expRes == ExpResult.SHOULD_SUCCEDD) && (resCode != ISO7816.SW_NO_ERROR)) { + bHiglight = true; + } + if (bHiglight) { + System.out.println(String.format("!! %-50s%s", message, getPrintError(resCode))); + } + else { + System.out.println(String.format(" %-50s%s", message, getPrintError(resCode))); + } return bufferOffset; } static void PrintECSupport(ResponseAPDU resp) { byte[] buffer = resp.getData(); + System.out.println();System.out.println(); int bufferOffset = 0; while (bufferOffset < buffer.length) { assert(buffer[bufferOffset] == SimpleECCApplet.ECTEST_SEPARATOR); @@ -132,18 +152,20 @@ public class SimpleAPDU { if (buffer[bufferOffset] == KeyPair.ALG_EC_F2M) { ecType = "ALG_EC_F2M"; } - System.out.println(String.format("%-50s%s", "EC type:", ecType)); + System.out.println(String.format("%-53s%s", "EC type:", ecType)); bufferOffset++; short keyLen = getShort(buffer, bufferOffset); - System.out.println(String.format("%-50s%d bits", "EC key length (bits):", keyLen)); + System.out.println(String.format("%-53s%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 (fails if no def):", 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 (fail is good):", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset); - bufferOffset = VerifyPrintResult("Generate key with invalid curve (fail is good):", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE, buffer, bufferOffset); + bufferOffset = VerifyPrintResult("KeyPair object allocation:", SimpleECCApplet.ECTEST_ALLOCATE_KEYPAIR, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); + bufferOffset = VerifyPrintResult("Generate key with def curve (fails if no def):", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_DEFCURVE, buffer, bufferOffset, ExpResult.MAY_FAIL); + bufferOffset = VerifyPrintResult("Set valid custom curve:", SimpleECCApplet.ECTEST_SET_VALIDCURVE, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); + bufferOffset = VerifyPrintResult("Generate key with valid curve:", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_CUSTOMCURVE, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); + bufferOffset = VerifyPrintResult("ECDH agreement with valid point:", SimpleECCApplet.ECTEST_ECDH_AGREEMENT_VALID_POINT, buffer, bufferOffset, ExpResult.SHOULD_SUCCEDD); + bufferOffset = VerifyPrintResult("ECDH agreement with invalid point (fail is good):", SimpleECCApplet.ECTEST_ECDH_AGREEMENT_INVALID_POINT, buffer, bufferOffset, ExpResult.MUST_FAIL); + bufferOffset = VerifyPrintResult("Set invalid custom curve (fail is good):", SimpleECCApplet.ECTEST_SET_INVALIDCURVE, buffer, bufferOffset, ExpResult.MUST_FAIL); + bufferOffset = VerifyPrintResult("Generate key with invalid curve (fail is good):", SimpleECCApplet.ECTEST_GENERATE_KEYPAIR_INVALIDCUSTOMCURVE, buffer, bufferOffset, ExpResult.MUST_FAIL); System.out.println(); } |
