diff options
| author | J08nY | 2018-01-23 17:31:15 +0100 |
|---|---|---|
| committer | J08nY | 2018-01-23 17:31:15 +0100 |
| commit | cb6c6b8b1274fe5a340c4317a4b015ea0ef15396 (patch) | |
| tree | 864a54dcdf07da33cd139312c8b0ee693e1a0eff /src | |
| parent | 6c46a27a52854aee24f7a37e74002bd6f4485723 (diff) | |
| parent | c581e39e539e6dadb49d9f83f563ab2b375f6e0b (diff) | |
| download | ECTester-0.2.0.tar.gz ECTester-0.2.0.tar.zst ECTester-0.2.0.zip | |
Diffstat (limited to 'src')
173 files changed, 8714 insertions, 2070 deletions
diff --git a/src/cz/crcs/ectester/applet/ECKeyGenerator.java b/src/cz/crcs/ectester/applet/ECKeyGenerator.java index 0c20333..b026cfe 100644 --- a/src/cz/crcs/ectester/applet/ECKeyGenerator.java +++ b/src/cz/crcs/ectester/applet/ECKeyGenerator.java @@ -201,13 +201,13 @@ public class ECKeyGenerator { break; case EC_Consts.PARAMETER_F2M: if (length == 4) { - short i = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]); + short i = Util.getShort(data, (short) (offset + 2)); if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i); if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i); } else if (length == 8) { - short i1 = Util.makeShort(data[(short) (offset + 2)], data[(short) (offset + 3)]); - short i2 = Util.makeShort(data[(short) (offset + 4)], data[(short) (offset + 5)]); - short i3 = Util.makeShort(data[(short) (offset + 6)], data[(short) (offset + 7)]); + short i1 = Util.getShort(data, (short) (offset + 2)); + short i2 = Util.getShort(data, (short) (offset + 4)); + short i3 = Util.getShort(data, (short) (offset + 6)); // if ((key & EC_Consts.KEY_PUBLIC) != 0) ecPublicKey.setFieldF2M(i1, i2, i3); // if ((key & EC_Consts.KEY_PRIVATE) != 0) ecPrivateKey.setFieldF2M(i1, i2, i3); // TODO: fix this, ^^ fails on jcardsim, but is up to spec diff --git a/src/cz/crcs/ectester/applet/ECKeyTester.java b/src/cz/crcs/ectester/applet/ECKeyTester.java index 0b3c1e0..36515ef 100644 --- a/src/cz/crcs/ectester/applet/ECKeyTester.java +++ b/src/cz/crcs/ectester/applet/ECKeyTester.java @@ -3,7 +3,6 @@ package cz.crcs.ectester.applet; import javacard.framework.CardRuntimeException; import javacard.framework.ISO7816; -import javacard.framework.ISOException; import javacard.security.*; /** @@ -13,77 +12,35 @@ import javacard.security.*; * @author Jan Jancar johny@neuromancer.sk */ public class ECKeyTester { - - private KeyAgreement ecdhKeyAgreement = null; - private KeyAgreement ecdhcKeyAgreement = null; + private KeyAgreement ecKeyAgreement = null; + private short kaType = 0; private Signature ecdsaSignature = null; + private short sigType = 0; private short sw = ISO7816.SW_NO_ERROR; - public short allocateECDH(byte algorithm) { + public short allocateKA(byte algorithm) { sw = ISO7816.SW_NO_ERROR; try { - ecdhKeyAgreement = KeyAgreement.getInstance(algorithm, false); + ecKeyAgreement = KeyAgreement.getInstance(algorithm, false); + kaType = algorithm; } catch (CardRuntimeException ce) { sw = ce.getReason(); } return sw; } - public short allocateECDHC(byte algorithm) { + public short allocateSig(byte algorithm) { sw = ISO7816.SW_NO_ERROR; try { - ecdhcKeyAgreement = KeyAgreement.getInstance(algorithm, false); + ecdsaSignature = Signature.getInstance(algorithm, false); + sigType = algorithm; } catch (CardRuntimeException ce) { sw = ce.getReason(); } return sw; } - public short allocateECDSA() { - sw = ISO7816.SW_NO_ERROR; - try { - ecdsaSignature = Signature.getInstance(Signature.ALG_ECDSA_SHA, false); - } catch (CardRuntimeException ce) { - sw = ce.getReason(); - } - return sw; - } - - private short testKA(KeyAgreement ka, KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { - short length = 0; - try { - sw = AppletUtil.kaCheck(ka); - sw = AppletUtil.keypairCheck(privatePair); - sw = AppletUtil.keypairCheck(publicPair); - short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset); - // reached ok - ka.init(privatePair.getPrivate()); // throws UNITIALIZED KEY when ALG_EC_SVDP_DHC_PLAIN is used - //ISOException.throwIt((short) 0x666); - - pubkeyLength = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, pubkeyLength); - length = ka.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset); - } catch (CardRuntimeException ce) { - sw = ce.getReason(); - } - return length; - } - - private short testKA_direct(KeyAgreement ka, KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) { - short length = 0; - try { - sw = AppletUtil.kaCheck(ka); - sw = AppletUtil.keypairCheck(privatePair); - - ka.init(privatePair.getPrivate()); - pubkeyLength = EC_Consts.corruptParameter(corruption, pubkey, pubkeyOffset, pubkeyLength); - length = ka.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset); - } catch (CardRuntimeException ce) { - sw = ce.getReason(); - } - return length; - } - /** * Tests ECDH secret generation with keys from given {@code privatePair} and {@code publicPair}. * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations. @@ -98,100 +55,46 @@ public class ECKeyTester { * @param corruption (EC_Consts.CORRUPTION_* | ...) * @return derived secret length **/ - public short testECDH(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { - return testKA(ecdhKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); - } - - public short testECDH_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) { - return testKA_direct(ecdhKeyAgreement, privatePair, pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset, corruption); - } - - /** - * Tests ECDHC secret generation with keys from given {@code privatePair} and {@code publicPair}. - * Uses {@code pubkeyBuffer} at {@code pubkeyOffset} for computations. - * Output should equal to ECDH output. - * - * @param privatePair KeyPair from which the private key is used - * @param publicPair KeyPair from which the public key is used - * @param pubkeyBuffer buffer to be used for the public key - * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key - * @param outputBuffer buffer to be used for the secret output - * @param outputOffset offset into the outputBuffer - * @param corruption (EC_Consts.CORRUPTION_* | ...) - * @return derived secret length - */ - public short testECDHC(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { - return testKA(ecdhcKeyAgreement, privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); - } - - public short testECDHC_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) { - return testKA_direct(ecdhcKeyAgreement, privatePair, pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset, corruption); - } - - /** - * @param privatePair KeyPair from which the private key is used - * @param publicPair KeyPair from which the public key is used - * @param pubkeyBuffer buffer to be used for the public key - * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key - * @param outputBuffer buffer to be used for the secret output - * @param outputOffset offset into the outputBuffer - * @param corruption (EC_Consts.CORRUPTION_* | ...) - * @return - */ - public short testBOTH(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { - short ecdhLength = testECDH(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); - if (sw != ISO7816.SW_NO_ERROR) { - return ecdhLength; - } - short ecdhcLength = testECDHC(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, (short) (outputOffset + ecdhLength), corruption); - short length = (short) (ecdhLength + ecdhcLength); - if (sw != ISO7816.SW_NO_ERROR) { - return length; - } - if (javacard.framework.Util.arrayCompare(outputBuffer, outputOffset, outputBuffer, (short) (outputOffset + ecdhLength), ecdhLength) != 0) { - sw = ECTesterApplet.SW_DH_DHC_MISMATCH; - } - return length; - } + public short testKA(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { + short length = 0; + try { + sw = AppletUtil.kaCheck(ecKeyAgreement); + sw = AppletUtil.keypairCheck(privatePair); + sw = AppletUtil.keypairCheck(publicPair); + short pubkeyLength = ((ECPublicKey) publicPair.getPublic()).getW(pubkeyBuffer, pubkeyOffset); + ecKeyAgreement.init(privatePair.getPrivate()); - public short testBOTH_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset, short corruption) { - short ecdhLength = testECDH_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption); - if (sw != ISO7816.SW_NO_ERROR) { - return ecdhLength; - } - short ecdhcLength = testECDHC_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption); - short length = (short) (ecdhLength + ecdhcLength); - if (sw != ISO7816.SW_NO_ERROR) { - return length; - } - if (javacard.framework.Util.arrayCompare(outputBuffer, outputOffset, outputBuffer, (short) (outputOffset + ecdhLength), ecdhLength) != 0) { - sw = ECTesterApplet.SW_DH_DHC_MISMATCH; + pubkeyLength = EC_Consts.corruptParameter(corruption, pubkeyBuffer, pubkeyOffset, pubkeyLength); + length = ecKeyAgreement.generateSecret(pubkeyBuffer, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset); + } catch (CardRuntimeException ce) { + sw = ce.getReason(); } return length; } /** - * @param privatePair KeyPair from which the private key is used - * @param publicPair KeyPair from which the public key is used - * @param pubkeyBuffer buffer to be used for the public key - * @param pubkeyOffset offset into pubkeyBuffer that can be used for the public key - * @param outputBuffer buffer to be used for the secret output - * @param outputOffset offset into the outputBuffer - * @param corruption (EC_Consts.CORRUPTION_* | ...) + * @param privatePair + * @param pubkey + * @param pubkeyOffset + * @param pubkeyLength + * @param outpuBuffer + * @param outputOffset + * @param corruption * @return */ - public short testANY(KeyPair privatePair, KeyPair publicPair, byte[] pubkeyBuffer, short pubkeyOffset, byte[] outputBuffer, short outputOffset, short corruption) { - short ecdhLength = testECDH(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); - if (sw == ISO7816.SW_NO_ERROR) - return ecdhLength; - return testECDHC(privatePair, publicPair, pubkeyBuffer, pubkeyOffset, outputBuffer, outputOffset, corruption); - } + public short testKA_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outpuBuffer, short outputOffset, short corruption) { + short length = 0; + try { + sw = AppletUtil.kaCheck(ecKeyAgreement); + sw = AppletUtil.keypairCheck(privatePair); - public short testANY_direct(KeyPair privatePair, byte[] pubkey, short pubkeyOffset, short pubkeyLength, byte[] outputBuffer, short outputOffset, short corruption) { - short ecdhLength = testECDH_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption); - if (sw == ISO7816.SW_NO_ERROR) - return ecdhLength; - return testECDHC_direct(privatePair, pubkey, pubkeyOffset, pubkeyLength, outputBuffer, outputOffset, corruption); + ecKeyAgreement.init(privatePair.getPrivate()); + pubkeyLength = EC_Consts.corruptParameter(corruption, pubkey, pubkeyOffset, pubkeyLength); + length = ecKeyAgreement.generateSecret(pubkey, pubkeyOffset, pubkeyLength, outpuBuffer, outputOffset); + } catch (CardRuntimeException ce) { + sw = ce.getReason(); + } + return length; } /** @@ -227,32 +130,31 @@ public class ECKeyTester { return length; } - public KeyAgreement getECDH() { - return ecdhKeyAgreement; + public KeyAgreement getKA() { + return ecKeyAgreement; } - public KeyAgreement getECDHC() { - return ecdhcKeyAgreement; + public Signature getSig() { + return ecdsaSignature; } - public Signature getECDSA() { - return ecdsaSignature; + public boolean hasKA() { + return ecKeyAgreement != null; } - public boolean hasECDH() { - return ecdhKeyAgreement != null; + public boolean hasSig() { + return ecdsaSignature != null; } - public boolean hasECDHC() { - return ecdhcKeyAgreement != null; + public short getKaType() { + return kaType; } - public boolean hasECDSA() { - return ecdsaSignature != null; + public short getSigType() { + return sigType; } public short getSW() { return sw; } - } diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java index ecf97f2..20e3f05 100644 --- a/src/cz/crcs/ectester/applet/ECTesterApplet.java +++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java @@ -26,11 +26,7 @@ package cz.crcs.ectester.applet; import javacard.framework.*; -import javacard.security.ECPrivateKey; -import javacard.security.ECPublicKey; -import javacard.security.KeyAgreement; -import javacard.security.KeyPair; -import javacard.security.RandomData; +import javacard.security.*; import javacardx.apdu.ExtendedLength; /** @@ -55,10 +51,11 @@ public class ECTesterApplet extends Applet implements ExtendedLength { public static final byte INS_ECDH_DIRECT = (byte) 0x71; public static final byte INS_ECDSA = (byte) 0x72; public static final byte INS_CLEANUP = (byte) 0x73; - public static final byte INS_SUPPORT = (byte) 0x74; + //public static final byte INS_SUPPORT = (byte) 0x74; public static final byte INS_ALLOCATE_KA = (byte) 0x75; - - + public static final byte INS_ALLOCATE_SIG = (byte) 0x76; + + // PARAMETERS for P1 and P2 public static final byte KEYPAIR_LOCAL = (byte) 0x01; public static final byte KEYPAIR_REMOTE = (byte) 0x02; @@ -72,10 +69,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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_KA_UNSUPPORTED = (short) 0x0ee7; + public static final short SW_OBJECT_NULL = (short) 0x0ee6; + - // Class javacard.security.KeyAgreement // javacard.security.KeyAgreement Fields: public static final byte KeyAgreement_ALG_EC_SVDP_DH = 1; @@ -86,8 +82,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength { public static final byte KeyAgreement_ALG_EC_SVDP_DHC_PLAIN = 4; public static final byte KeyAgreement_ALG_EC_PACE_GM = 5; public static final byte KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY = 6; - public static final byte KeyAgreement_ALG_DH_PLAIN = 7; + // Class javacard.security.Signature + // javacard.security.Signature Fields: + public static final byte Signature_ALG_ECDSA_SHA = 17; + public static final byte Signature_ALG_ECDSA_SHA_256 = 33; + public static final byte Signature_ALG_ECDSA_SHA_384 = 34; + public static final byte Signature_ALG_ECDSA_SHA_224 = 37; + public static final byte Signature_ALG_ECDSA_SHA_512 = 38; private static final short ARRAY_LENGTH = (short) 0xff; private static final short APDU_MAX_LENGTH = (short) 1024; @@ -98,13 +100,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength { // 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; @@ -133,11 +131,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength { keyGenerator = new ECKeyGenerator(); keyTester = new ECKeyTester(); - ecdhSW = keyTester.allocateECDH(KeyAgreement.ALG_EC_SVDP_DH); - ecdhcSW = keyTester.allocateECDHC(KeyAgreement.ALG_EC_SVDP_DHC); - //ecdhSW = keyTester.allocateECDH((byte) 3); - //ecdhcSW = keyTester.allocateECDHC((byte) 4); - ecdsaSW = keyTester.allocateECDSA(); } register(); } @@ -163,9 +156,12 @@ public class ECTesterApplet extends Applet implements ExtendedLength { short length = 0; switch (ins) { - case INS_ALLOCATE_KA: + case INS_ALLOCATE_KA: length = insAllocateKA(apdu); break; + case INS_ALLOCATE_SIG: + length = insAllocateSig(apdu); + break; case INS_ALLOCATE: length = insAllocate(apdu); break; @@ -196,9 +192,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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); @@ -208,9 +201,9 @@ public class ECTesterApplet extends Applet implements ExtendedLength { apdu.setOutgoingAndSend((short) 0, length); } else ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); } - + /** - * Allocates KeyAgreement object. returns allocate SW + * Allocates KeyAgreement object, returns allocate SW. * * @param apdu DATA = byte KeyAgreementType * @return length of response @@ -218,35 +211,25 @@ public class ECTesterApplet extends Applet implements ExtendedLength { private short insAllocateKA(APDU apdu) { short cdata = apdu.getOffsetCdata(); byte kaType = apduArray[cdata]; -/* - short sw = SW_KA_UNSUPPORTED; - switch (kaType) { - case KeyAgreement_ALG_EC_SVDP_DH: // no break - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN: - case KeyAgreement_ALG_EC_PACE_GM: - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY: - sw = keyTester.allocateECDH(kaType); - break; - case KeyAgreement_ALG_EC_SVDP_DHC: - case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN: - sw = keyTester.allocateECDHC(kaType); - break; - default: - sw = SW_KA_UNSUPPORTED; - break; - } -*/ - // Allocate given type into both DH and DHC objects - short sw = keyTester.allocateECDH(kaType); - short offset = 0; - Util.setShort(apdu.getBuffer(), offset, sw); - offset += 2; - - //sw = keyTester.allocateECDHC(kaType); - Util.setShort(apdu.getBuffer(), offset, sw); - offset += 2; - return offset; - } + short sw = keyTester.allocateKA(kaType); + Util.setShort(apdu.getBuffer(), (short) 0, sw); + return 2; + } + + /** + * Allocates a Signature object, returns allocate SW. + * + * @param apdu DATA = byte SignatureType + * @return length of response + */ + private short insAllocateSig(APDU apdu) { + short cdata = apdu.getOffsetCdata(); + byte sigType = apduArray[cdata]; + short sw = keyTester.allocateSig(sigType); + Util.setShort(apdu.getBuffer(), (short) 0, sw); + return 2; + } + /** * Allocates local and remote keyPairs. * returns allocate SWs @@ -422,13 +405,15 @@ public class ECTesterApplet extends Applet implements ExtendedLength { } /** + * Performs ECDH, directly between the privkey specified in P1(local/remote) and the raw data * * @param apdu P1 = byte privkey (KEYPAIR_*) - * @return P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) + * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) * DATA = short corruption (EC_Consts.CORRUPTION_* | ...) * 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]; @@ -447,7 +432,8 @@ public class ECTesterApplet extends Applet implements ExtendedLength { * * @param apdu P1 = byte keyPair (KEYPAIR_*) * P2 = byte export (EXPORT_TRUE || EXPORT_FALSE) - * DATA = short dataLength (00 = random data generated, !00 = data length) + * DATA = byte sigType + * short dataLength (00 = random data generated, !00 = data length) * byte[] data * @return length of response */ @@ -455,13 +441,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength { byte keyPair = apduArray[ISO7816.OFFSET_P1]; byte export = apduArray[ISO7816.OFFSET_P2]; short cdata = apdu.getOffsetCdata(); + byte sigType = apduArray[cdata]; short len = 0; if ((keyPair & KEYPAIR_LOCAL) != 0) { - len += ecdsa(localKeypair, export, apduArray, cdata, apdu.getBuffer(), (short) 0); + len += ecdsa(localKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), (short) 0); } if ((keyPair & KEYPAIR_REMOTE) != 0) { - len += ecdsa(remoteKeypair, export, apduArray, cdata, apdu.getBuffer(), len); + len += ecdsa(remoteKeypair, sigType, export, apduArray, (short) (cdata + 1), apdu.getBuffer(), len); } return len; @@ -480,19 +467,6 @@ public class ECTesterApplet extends Applet implements ExtendedLength { } /** - * 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 @@ -623,7 +597,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { * @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 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 @@ -635,23 +609,14 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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); + if (keyTester.getKaType() == type) { + secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption); + } else { + short allocateSW = keyTester.allocateKA(type); + if (allocateSW == ISO7816.SW_NO_ERROR) { + secretLength = keyTester.testKA(priv, pub, ramArray, (short) 0, ramArray2, (short) 0, corruption); + } } - Util.setShort(outBuffer, outOffset, keyTester.getSW()); length += 2; @@ -671,21 +636,13 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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); + if (keyTester.getKaType() == type) { + secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, corruption); + } else { + short allocateSW = keyTester.allocateKA(type); + if (allocateSW == ISO7816.SW_NO_ERROR) { + secretLength = keyTester.testKA_direct(priv, apduArray, keyOffset, keyLength, ramArray2, (short) 0, corruption); + } } Util.setShort(outBuffer, outOffset, keyTester.getSW()); @@ -702,6 +659,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { /** * @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 @@ -709,7 +667,7 @@ public class ECTesterApplet extends Applet implements ExtendedLength { * @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) { + 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); @@ -721,7 +679,15 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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); + 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; @@ -753,30 +719,4 @@ public class ECTesterApplet extends Applet implements ExtendedLength { 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; - } } diff --git a/src/cz/crcs/ectester/applet/EC_Consts.java b/src/cz/crcs/ectester/applet/EC_Consts.java index 04cd55e..4581fd6 100644 --- a/src/cz/crcs/ectester/applet/EC_Consts.java +++ b/src/cz/crcs/ectester/applet/EC_Consts.java @@ -59,13 +59,6 @@ public class EC_Consts { public static final byte KEY_PRIVATE = 0x02; public static final byte KEY_BOTH = KEY_PUBLIC | KEY_PRIVATE; - - // Key Agreement test identifiers - public static final byte KA_ECDH = 0x01; - public static final byte KA_ECDHC = 0x02; - public static final byte KA_BOTH = KA_ECDH | KA_ECDHC; - public static final byte KA_ANY = 0x04; - public static RandomData randomData = null; // secp112r1 @@ -1009,7 +1002,7 @@ public class EC_Consts { public static final byte CURVE_default = (byte) 0; public static final byte CURVE_external = (byte) 0xff; - // SECP recommended curves over FP + // SECG recommended curves over FP public static final byte CURVE_secp112r1 = (byte) 1; public static final byte CURVE_secp128r1 = (byte) 2; public static final byte CURVE_secp160r1 = (byte) 3; @@ -1021,7 +1014,7 @@ public class EC_Consts { public static final byte FP_CURVES = (byte) 8; - // SECP recommended curves over F2M + // SECG recommended curves over F2M public static final byte CURVE_sect163r1 = (byte) 9; public static final byte CURVE_sect233r1 = (byte) 10; public static final byte CURVE_sect283r1 = (byte) 11; @@ -1033,6 +1026,25 @@ public class EC_Consts { public static final short[] FP_SIZES = new short[]{112, 128, 160, 192, 224, 256, 384, 521}; public static final short[] F2M_SIZES = new short[]{163, 233, 283, 409, 571}; + public static final byte[] KA_TYPES = new byte[]{ + ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, + //ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_KDF, //duplicate + ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC, + //ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_KDF, //duplicate + ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN, + ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN, + ECTesterApplet.KeyAgreement_ALG_EC_PACE_GM, + ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY + }; + + public static final byte[] SIG_TYPES = new byte[]{ + ECTesterApplet.Signature_ALG_ECDSA_SHA, + ECTesterApplet.Signature_ALG_ECDSA_SHA_224, + ECTesterApplet.Signature_ALG_ECDSA_SHA_256, + ECTesterApplet.Signature_ALG_ECDSA_SHA_384, + ECTesterApplet.Signature_ALG_ECDSA_SHA_512 + }; + public static byte getCurve(short keyLength, byte keyClass) { if (keyClass == KeyPair.ALG_EC_FP) { switch (keyLength) { diff --git a/src/cz/crcs/ectester/common/cli/Argument.java b/src/cz/crcs/ectester/common/cli/Argument.java new file mode 100644 index 0000000..e9b6688 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/Argument.java @@ -0,0 +1,29 @@ +package cz.crcs.ectester.common.cli; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class Argument { + private String name; + private String desc; + private boolean required; + + public Argument(String name, String desc, boolean isRequired) { + this.name = name; + this.desc = desc; + this.required = isRequired; + } + + + public String getName() { + return name; + } + + public String getDesc() { + return desc; + } + + public boolean isRequired() { + return required; + } +} diff --git a/src/cz/crcs/ectester/common/cli/CLITools.java b/src/cz/crcs/ectester/common/cli/CLITools.java new file mode 100644 index 0000000..91f121f --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/CLITools.java @@ -0,0 +1,140 @@ +package cz.crcs.ectester.common.cli; + +import cz.crcs.ectester.common.ec.EC_Category; +import cz.crcs.ectester.common.ec.EC_Data; +import cz.crcs.ectester.data.EC_Store; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CLITools { + + /** + * Print help. + */ + public static void help(String prog, String header, Options options, String footer, boolean usage) { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + help.printHelp(prog, header, options, footer, usage); + } + + private static void help(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts, int depth) { + if (opts.getOptions().size() > 0) { + help.printOptions(pw, HelpFormatter.DEFAULT_WIDTH, opts, HelpFormatter.DEFAULT_LEFT_PAD + depth, HelpFormatter.DEFAULT_DESC_PAD); + } + if (cli instanceof TreeParser) { + TreeParser tp = (TreeParser) cli; + for (Argument arg : tp.getArgs()) { + String argname = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]"; + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + (depth + 1) + "s" + argname + " " + arg.getDesc(), " ")); + } + tp.getParsers().forEach((key, value) -> { + pw.println(); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, String.format("%" + depth + "s" + key + ":", " ")); + CLITools.help(help, pw, value.getParser(), value.getOptions(), depth + 1); + }); + } + } + + private static void usage(HelpFormatter help, PrintWriter pw, CommandLineParser cli, Options opts) { + StringWriter sw = new StringWriter(); + PrintWriter upw = new PrintWriter(sw); + help.printUsage(upw, HelpFormatter.DEFAULT_WIDTH, "", opts); + if (cli instanceof TreeParser) { + upw.print(" "); + TreeParser tp = (TreeParser) cli; + String[] keys = tp.getParsers().keySet().toArray(new String[tp.getParsers().size()]); + if (keys.length > 0 && !tp.isRequired()) { + upw.print("[ "); + } + + for (int i = 0; i < keys.length; ++i) { + String key = keys[i]; + ParserOptions value = tp.getParsers().get(key); + upw.print("(" + key); + usage(help, upw, value.getParser(), value.getOptions()); + upw.print(")"); + if (i != keys.length - 1) { + upw.print(" | "); + } + } + + if (keys.length > 0 && !tp.isRequired()) { + upw.print(" ]"); + } + + Argument[] args = tp.getArgs().toArray(new Argument[tp.getArgs().size()]); + if (args.length > 0) { + String[] argss = new String[tp.getArgs().size()]; + for (int i = 0; i < args.length; ++i) { + Argument arg = args[i]; + argss[i] = arg.isRequired() ? "<" + arg.getName() + ">" : "[" + arg.getName() + "]"; + } + upw.print(" " + String.join(" ", argss)); + } + } + pw.println(sw.toString().replaceAll("usage:( )?", "").replace("\n", "")); + } + + /** + * Print tree help. + */ + public static void help(String prog, String header, Options baseOpts, TreeParser baseParser, String footer, boolean printUsage) { + HelpFormatter help = new HelpFormatter(); + help.setOptionComparator(null); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, header); + if (printUsage) { + StringWriter uw = new StringWriter(); + PrintWriter upw = new PrintWriter(uw); + usage(help, upw, baseParser, baseOpts); + pw.print("usage: " + prog); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, uw.toString()); + upw.close(); + pw.println(); + } + help(help, pw, baseParser, baseOpts, 1); + help.printWrapped(pw, HelpFormatter.DEFAULT_WIDTH, footer); + System.out.println(sw.toString()); + } + + /** + * Print version info. + */ + public static void version(String description, String license) { + System.out.println(description); + System.out.println(license); + } + + /** + * List categories and named curves. + */ + public static void listNamed(EC_Store dataStore, String named) { + Map<String, EC_Category> categories = dataStore.getCategories(); + if (named == null) { + // print all categories, briefly + for (EC_Category cat : categories.values()) { + System.out.println(cat); + } + } else if (categories.containsKey(named)) { + // print given category + System.out.println(categories.get(named)); + } else { + // print given object + EC_Data object = dataStore.getObject(EC_Data.class, named); + if (object != null) { + System.out.println(object); + } else { + System.err.println("Named object " + named + " not found!"); + } + } + } +} diff --git a/src/cz/crcs/ectester/common/cli/ParserOptions.java b/src/cz/crcs/ectester/common/cli/ParserOptions.java new file mode 100644 index 0000000..ee2097e --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/ParserOptions.java @@ -0,0 +1,38 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.Options; + +import java.util.Collections; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class ParserOptions { + private CommandLineParser parser; + private Options options; + private List<Argument> arguments; + + public ParserOptions(CommandLineParser parser, Options options) { + this.parser = parser; + this.options = options; + } + + public ParserOptions(CommandLineParser parser, Options options, List<Argument> arguments) { + this(parser, options); + this.arguments = arguments; + } + + public CommandLineParser getParser() { + return parser; + } + + public Options getOptions() { + return options; + } + + public List<Argument> getArguments() { + return Collections.unmodifiableList(arguments); + } +} diff --git a/src/cz/crcs/ectester/common/cli/TreeCommandLine.java b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java new file mode 100644 index 0000000..6a044d2 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/TreeCommandLine.java @@ -0,0 +1,178 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.ParseException; + +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.function.BiFunction; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TreeCommandLine extends CommandLine { + private String name = ""; + private TreeCommandLine next; + private CommandLine cli; + + public TreeCommandLine(CommandLine cli, TreeCommandLine next) { + this.cli = cli; + this.next = next; + } + + public TreeCommandLine(String name, CommandLine cli, TreeCommandLine next) { + this(cli, next); + this.name = name; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getNextName() { + if (next != null) { + return next.getName(); + } + return null; + } + + public TreeCommandLine getNext() { + return next; + } + + public boolean isNext(String next) { + return Objects.equals(getNextName(), next); + } + + public CommandLine getThis() { + return cli; + } + + public int getDepth() { + if (next == null) { + return 0; + } + return next.getDepth() + 1; + } + + private <T> T getOption(String opt, BiFunction<CommandLine, String, T> getter, T defaultValue) { + if (opt.contains(".")) { + String[] parts = opt.split("\\.", 2); + if (next != null && parts[0].equals(next.getName())) { + T result = getter.apply(next, parts[1]); + if (result != null) + return result; + return defaultValue; + } + return defaultValue; + } + return getter.apply(cli, opt); + } + + @Override + public boolean hasOption(String opt) { + return getOption(opt, CommandLine::hasOption, false); + } + + @Override + public boolean hasOption(char opt) { + return cli.hasOption(opt); + } + + @Override + public Object getParsedOptionValue(String opt) throws ParseException { + if (opt.contains(".")) { + String[] parts = opt.split("\\.", 2); + if (next != null && parts[0].equals(next.getName())) { + return next.getParsedOptionValue(parts[1]); + } + return null; + } + return cli.getParsedOptionValue(opt); + } + + @Override + public Object getOptionObject(char opt) { + return cli.getOptionObject(opt); + } + + @Override + public String getOptionValue(String opt) { + return getOption(opt, CommandLine::getOptionValue, null); + } + + @Override + public String getOptionValue(char opt) { + return cli.getOptionValue(opt); + } + + @Override + public String[] getOptionValues(String opt) { + return getOption(opt, CommandLine::getOptionValues, null); + } + + @Override + public String[] getOptionValues(char opt) { + return cli.getOptionValues(opt); + } + + @Override + public String getOptionValue(String opt, String defaultValue) { + return getOption(opt, CommandLine::getOptionValue, defaultValue); + } + + @Override + public String getOptionValue(char opt, String defaultValue) { + return cli.getOptionValue(opt, defaultValue); + } + + @Override + public Properties getOptionProperties(String opt) { + return getOption(opt, CommandLine::getOptionProperties, new Properties()); + } + + @Override + public Iterator<Option> iterator() { + return cli.iterator(); + } + + @Override + public Option[] getOptions() { + return cli.getOptions(); + } + + public boolean hasArg(int index) { + return getArg(index) != null; + } + + public String getArg(int index) { + if (next != null) { + return next.getArg(index); + } + String[] args = cli.getArgs(); + if (index >= args.length) { + return null; + } + if (index < 0 && -index > args.length) { + return null; + } + return index < 0 ? args[args.length + index] : args[index]; + } + + @Override + public String[] getArgs() { + return cli.getArgs(); + } + + @Override + public List<String> getArgList() { + return cli.getArgList(); + } +} diff --git a/src/cz/crcs/ectester/common/cli/TreeParser.java b/src/cz/crcs/ectester/common/cli/TreeParser.java new file mode 100644 index 0000000..f1a1980 --- /dev/null +++ b/src/cz/crcs/ectester/common/cli/TreeParser.java @@ -0,0 +1,128 @@ +package cz.crcs.ectester.common.cli; + +import org.apache.commons.cli.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TreeParser implements CommandLineParser { + private Map<String, ParserOptions> parsers; + private boolean required; + private List<Argument> args = Collections.emptyList(); + + public TreeParser(Map<String, ParserOptions> parsers, boolean required) { + this.parsers = parsers; + this.required = required; + } + + public TreeParser(Map<String, ParserOptions> parsers, boolean required, List<Argument> args) { + this(parsers, required); + this.args = args; + } + + public Map<String, ParserOptions> getParsers() { + return Collections.unmodifiableMap(parsers); + } + + public boolean isRequired() { + return required; + } + + public List<Argument> getArgs() { + return Collections.unmodifiableList(args); + } + + @Override + public TreeCommandLine parse(Options options, String[] arguments) throws ParseException { + return this.parse(options, arguments, null); + } + + public TreeCommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException { + return this.parse(options, arguments, properties, false); + } + + @Override + public TreeCommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException { + return this.parse(options, arguments, null, stopAtNonOption); + } + + public TreeCommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) throws ParseException { + DefaultParser thisParser = new DefaultParser(); + CommandLine cli = thisParser.parse(options, arguments, properties, true); + + CommandLine subCli = null; + String[] cliArgs = cli.getArgs(); + String sub = null; + if (cliArgs.length != 0) { + sub = cliArgs[0]; + + List<String> matches = new LinkedList<>(); + String finalSub = sub; + for (Map.Entry<String, ParserOptions> entry : parsers.entrySet()) { + if (entry.getKey().equalsIgnoreCase(finalSub)) { + matches.clear(); + matches.add(finalSub); + break; + } else if (entry.getKey().startsWith(finalSub)) { + matches.add(entry.getKey()); + } + } + + if (matches.size() == 1) { + sub = matches.get(0); + ParserOptions subparser = parsers.get(sub); + String[] remainingArgs = new String[cliArgs.length - 1]; + System.arraycopy(cliArgs, 1, remainingArgs, 0, cliArgs.length - 1); + subCli = subparser.getParser().parse(subparser.getOptions(), remainingArgs, true); + } else if (matches.size() > 1) { + throw new AmbiguousOptionException(sub, matches); + } + } else { + if (required) { + throw new MissingOptionException(new ArrayList(parsers.keySet())); + } + } + + int maxArgs = args.size(); + long requiredArgs = args.stream().filter(Argument::isRequired).count(); + String reqArgs = String.join(" ", args.stream().filter(Argument::isRequired).map(Argument::getName).collect(Collectors.toList())); + + if (subCli instanceof TreeCommandLine) { + TreeCommandLine subTreeCli = (TreeCommandLine) subCli; + + TreeCommandLine lastCli = subTreeCli; + while (lastCli.getNext() != null) { + lastCli = lastCli.getNext(); + } + + if (lastCli.getArgs().length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } else if (lastCli.getArgs().length > maxArgs) { + throw new MissingArgumentException("Too many arguments."); + } + + subTreeCli.setName(sub); + return new TreeCommandLine(cli, subTreeCli); + } else if (subCli != null) { + if (subCli.getArgs().length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } else if (subCli.getArgs().length > maxArgs) { + throw new MissingArgumentException("Too many arguments."); + } + + TreeCommandLine subTreeCli = new TreeCommandLine(sub, subCli, null); + return new TreeCommandLine(cli, subTreeCli); + } else { + if (cliArgs.length < requiredArgs) { + throw new MissingArgumentException("Not enough arguments: " + reqArgs); + } else if (cliArgs.length > maxArgs) { + throw new MissingArgumentException("Too many arguments."); + } + + return new TreeCommandLine(cli, null); + } + } +} diff --git a/src/cz/crcs/ectester/reader/ec/EC_Category.java b/src/cz/crcs/ectester/common/ec/EC_Category.java index 41cbad8..32a788d 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Category.java +++ b/src/cz/crcs/ectester/common/ec/EC_Category.java @@ -1,4 +1,4 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; import java.util.Collections; import java.util.Map; diff --git a/src/cz/crcs/ectester/common/ec/EC_Curve.java b/src/cz/crcs/ectester/common/ec/EC_Curve.java new file mode 100644 index 0000000..173fd29 --- /dev/null +++ b/src/cz/crcs/ectester/common/ec/EC_Curve.java @@ -0,0 +1,132 @@ +package cz.crcs.ectester.common.ec; + +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.util.ByteUtil; +import javacard.security.KeyPair; + +import java.math.BigInteger; +import java.security.spec.*; + +/** + * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class EC_Curve extends EC_Params { + private short bits; + private byte field; + private String desc; + + /** + * @param bits + * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M + */ + public EC_Curve(short bits, byte field) { + super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M); + this.bits = bits; + this.field = field; + } + + public EC_Curve(String id, short bits, byte field) { + this(bits, field); + this.id = id; + } + + public EC_Curve(String id, short bits, byte field, String desc) { + this(id, bits, field); + this.desc = desc; + } + + public short getBits() { + return bits; + } + + public byte getField() { + return field; + } + + public String getDesc() { + return desc; + } + + @Override + public String toString() { + return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); + } + + public ECParameterSpec toSpec() { + ECField field; + if (this.field == KeyPair.ALG_EC_FP) { + field = new ECFieldFp(new BigInteger(1, getData(0))); + } else { + byte[][] fieldData = getParam(EC_Consts.PARAMETER_F2M); + int m = ByteUtil.getShort(fieldData[0], 0); + int e1 = ByteUtil.getShort(fieldData[1], 0); + int e2 = ByteUtil.getShort(fieldData[2], 0); + int e3 = ByteUtil.getShort(fieldData[3], 0); + int[] powers = new int[]{e1, e2, e3}; + field = new ECFieldF2m(m, powers); + } + + BigInteger a = new BigInteger(1, getParam(EC_Consts.PARAMETER_A)[0]); + BigInteger b = new BigInteger(1, getParam(EC_Consts.PARAMETER_B)[0]); + + EllipticCurve curve = new EllipticCurve(field, a, b); + + byte[][] G = getParam(EC_Consts.PARAMETER_G); + BigInteger gx = new BigInteger(1, G[0]); + BigInteger gy = new BigInteger(1, G[1]); + ECPoint generator = new ECPoint(gx, gy); + + BigInteger n = new BigInteger(1, getParam(EC_Consts.PARAMETER_R)[0]); + + int h = ByteUtil.getShort(getParam(EC_Consts.PARAMETER_K)[0], 0); + + return new ECParameterSpec(curve, generator, n, h); + } + + public static EC_Curve fromSpec(ECParameterSpec spec) { + EllipticCurve curve = spec.getCurve(); + ECField field = curve.getField(); + + short bits = (short) field.getFieldSize(); + byte[][] params; + int paramIndex = 0; + byte fieldType; + if (field instanceof ECFieldFp) { + ECFieldFp primeField = (ECFieldFp) field; + params = new byte[7][]; + params[paramIndex++] = primeField.getP().toByteArray(); + fieldType = KeyPair.ALG_EC_FP; + } else if (field instanceof ECFieldF2m) { + ECFieldF2m binaryField = (ECFieldF2m) field; + params = new byte[10][]; + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex++], 0, (short) binaryField.getM()); + int[] powers = binaryField.getMidTermsOfReductionPolynomial(); + for (int i = 0; i < 3; ++i) { + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex++], 0, (short) powers[i]); + } + fieldType = KeyPair.ALG_EC_F2M; + } else { + throw new IllegalArgumentException("ECParameterSpec with an unknown field."); + } + + ECPoint generator = spec.getGenerator(); + + params[paramIndex++] = curve.getA().toByteArray(); + params[paramIndex++] = curve.getB().toByteArray(); + + params[paramIndex++] = generator.getAffineX().toByteArray(); + params[paramIndex++] = generator.getAffineY().toByteArray(); + + params[paramIndex++] = spec.getOrder().toByteArray(); + params[paramIndex] = new byte[2]; + ByteUtil.setShort(params[paramIndex], 0, (short) spec.getCofactor()); + + EC_Curve result = new EC_Curve(bits, fieldType); + result.readByteArray(params); + return result; + } +} diff --git a/src/cz/crcs/ectester/reader/ec/EC_Data.java b/src/cz/crcs/ectester/common/ec/EC_Data.java index 0ceddef..c048ef7 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Data.java +++ b/src/cz/crcs/ectester/common/ec/EC_Data.java @@ -1,6 +1,6 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.util.ByteUtil; import java.io.*; import java.util.*; @@ -8,9 +8,10 @@ import java.util.regex.Pattern; /** * A list of byte arrays for holding EC data. - * + * <p> * The data can be read from a byte array via <code>readBytes()</code>, from a CSV via <code>readCSV()</code>. * The data can be exported to a byte array via <code>flatten()</code> or to a string array via <code>expand()</code>. + * * @author Jan Jancar johny@neuromancer.sk */ public abstract class EC_Data { @@ -55,19 +56,19 @@ public abstract class EC_Data { return data; } - public boolean hasData() { - return data != null; + public byte[] getData(int index) { + return data[index]; } - public byte[] getParam(int index) { - return data[index]; + public boolean hasData() { + return data != null; } public byte[] flatten() { ByteArrayOutputStream out = new ByteArrayOutputStream(); for (byte[] param : data) { byte[] length = new byte[2]; - Util.setShort(length, 0, (short) param.length); + ByteUtil.setShort(length, 0, (short) param.length); out.write(length, 0, 2); out.write(param, 0, param.length); @@ -79,7 +80,7 @@ public abstract class EC_Data { public String[] expand() { List<String> out = new ArrayList<>(count); for (byte[] param : data) { - out.add(Util.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(param, false)); } return out.toArray(new String[out.size()]); @@ -97,9 +98,9 @@ public abstract class EC_Data { private static byte[] parse(String param) { byte[] data; if (param.startsWith("0x") || param.startsWith("0X")) { - data = Util.hexToBytes(param.substring(2)); + data = ByteUtil.hexToBytes(param.substring(2)); } else { - data = Util.hexToBytes(param); + data = ByteUtil.hexToBytes(param); } if (data == null) return new byte[0]; @@ -141,12 +142,16 @@ public abstract class EC_Data { } public boolean readBytes(byte[] bytes) { + if (bytes == null) { + return false; + } + int offset = 0; for (int i = 0; i < count; i++) { if (bytes.length - offset < 2) { return false; } - short paramLength = Util.getShort(bytes, offset); + short paramLength = ByteUtil.getShort(bytes, offset); offset += 2; if (bytes.length < offset + paramLength) { return false; @@ -158,6 +163,18 @@ public abstract class EC_Data { return true; } + public boolean readByteArray(byte[][] bytes) { + if (bytes == null || count != bytes.length) { + return false; + } + + for (int i = 0; i < count; ++i) { + data[i] = new byte[bytes[i].length]; + System.arraycopy(bytes[i], 0, data[i], 0, bytes[i].length); + } + return true; + } + public void writeCSV(OutputStream out) throws IOException { Writer w = new OutputStreamWriter(out); w.write(String.join(",", expand())); diff --git a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java b/src/cz/crcs/ectester/common/ec/EC_KAResult.java index 4a67bbe..8a5fcb4 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_KAResult.java +++ b/src/cz/crcs/ectester/common/ec/EC_KAResult.java @@ -1,6 +1,6 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.util.CardUtil; /** * A result of EC based Key agreement operation. @@ -8,15 +8,14 @@ import cz.crcs.ectester.reader.Util; * @author Jan Jancar johny@neuromancer.sk */ public class EC_KAResult extends EC_Data { - - private byte ka; + private String ka; private String curve; private String oneKey; private String otherKey; private String desc; - public EC_KAResult(byte ka, String curve, String oneKey, String otherKey) { + public EC_KAResult(String ka, String curve, String oneKey, String otherKey) { super(1); this.ka = ka; this.curve = curve; @@ -24,20 +23,24 @@ public class EC_KAResult extends EC_Data { this.otherKey = otherKey; } - public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey) { + public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey) { this(ka, curve, oneKey, otherKey); this.id = id; } - public EC_KAResult(String id, byte ka, String curve, String oneKey, String otherKey, String desc) { + public EC_KAResult(String id, String ka, String curve, String oneKey, String otherKey, String desc) { this(id, ka, curve, oneKey, otherKey); this.desc = desc; } - public byte getKA() { + public String getKA() { return ka; } + public byte getJavaCardKA() { + return CardUtil.getKA(ka); + } + public String getCurve() { return curve; } @@ -56,8 +59,7 @@ public class EC_KAResult extends EC_Data { @Override public String toString() { - String algo = Util.getKA(ka); - return "<" + getId() + "> " + algo + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); + return "<" + getId() + "> " + ka + " result over " + curve + ", " + oneKey + " + " + otherKey + (desc == null ? "" : ": " + desc); } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/common/ec/EC_Key.java index 5077d5b..a34b0e7 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Key.java +++ b/src/cz/crcs/ectester/common/ec/EC_Key.java @@ -1,4 +1,4 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; import cz.crcs.ectester.applet.EC_Consts; diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/common/ec/EC_Keypair.java index 2643346..53632cd 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java +++ b/src/cz/crcs/ectester/common/ec/EC_Keypair.java @@ -1,4 +1,4 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; import cz.crcs.ectester.applet.EC_Consts; diff --git a/src/cz/crcs/ectester/reader/ec/EC_Params.java b/src/cz/crcs/ectester/common/ec/EC_Params.java index 6fb164b..1c066e7 100644 --- a/src/cz/crcs/ectester/reader/ec/EC_Params.java +++ b/src/cz/crcs/ectester/common/ec/EC_Params.java @@ -1,7 +1,7 @@ -package cz.crcs.ectester.reader.ec; +package cz.crcs.ectester.common.ec; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.util.ByteUtil; import java.io.ByteArrayOutputStream; import java.util.ArrayList; @@ -44,6 +44,49 @@ public class EC_Params extends EC_Data { return params; } + public byte[][] getParam(short param) { + if (!hasParam(param)) { + return null; + } + if (Integer.bitCount(param) != 1) { + return null; + } + short paramMask = EC_Consts.PARAMETER_FP; + byte[][] result = null; + int i = 0; + while (paramMask <= EC_Consts.PARAMETER_S) { + short masked = (short) (this.params & param & paramMask); + short shallow = (short) (this.params & paramMask); + if (masked != 0) { + if (masked == EC_Consts.PARAMETER_F2M) { + result = new byte[4][]; + result[0] = data[i].clone(); + result[1] = data[i+1].clone(); + result[2] = data[i+2].clone(); + result[3] = data[i+3].clone(); + break; + } + if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { + result = new byte[2][]; + result[0] = data[i].clone(); + result[1] = data[i+1].clone(); + break; + } + result = new byte[1][]; + result[0] = data[i].clone(); + } + if (shallow == EC_Consts.PARAMETER_F2M) { + i += 4; + } else if (shallow == EC_Consts.PARAMETER_G || shallow == EC_Consts.PARAMETER_W) { + i += 2; + } else if (shallow != 0) { + i++; + } + paramMask = (short) (paramMask << 1); + } + return result; + } + public boolean hasParam(short param) { return (params & param) != 0; } @@ -82,12 +125,12 @@ public class EC_Params extends EC_Data { byte[] param = data[i]; if (masked == EC_Consts.PARAMETER_F2M) { //add m, e_1, e_2, e_3 - param = Util.concatenate(param, data[i + 1]); - if (!Util.allValue(data[i + 2], (byte) 0)) { - param = Util.concatenate(param, data[i + 2]); + param = ByteUtil.concatenate(param, data[i + 1]); + if (!ByteUtil.allValue(data[i + 2], (byte) 0)) { + param = ByteUtil.concatenate(param, data[i + 2]); } - if (!Util.allValue(data[i + 3], (byte) 0)) { - param = Util.concatenate(param, data[i + 3]); + if (!ByteUtil.allValue(data[i + 3], (byte) 0)) { + param = ByteUtil.concatenate(param, data[i + 3]); } if (!(param.length == 4 || param.length == 8)) throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)"); @@ -95,14 +138,14 @@ public class EC_Params extends EC_Data { if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { //read another param (the y coord) and put into X962 format. byte[] y = data[i + 1]; - param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works! + param = ByteUtil.concatenate(new byte[]{4}, param, y); //<- ugly but works! } if (param.length == 0) throw new RuntimeException("Empty parameter read?"); //write length byte[] length = new byte[2]; - Util.setShort(length, 0, (short) param.length); + ByteUtil.setShort(length, 0, (short) param.length); out.write(length, 0, 2); //write data out.write(param, 0, param.length); @@ -132,15 +175,15 @@ public class EC_Params extends EC_Data { byte[] param = data[index]; if (masked == EC_Consts.PARAMETER_F2M) { for (int i = 0; i < 4; ++i) { - out.add(Util.bytesToHex(data[index + i], false)); + out.add(ByteUtil.bytesToHex(data[index + i], false)); } index += 4; } else if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) { - out.add(Util.bytesToHex(param, false)); - out.add(Util.bytesToHex(data[index + 1], false)); + out.add(ByteUtil.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(data[index + 1], false)); index += 2; } else { - out.add(Util.bytesToHex(param, false)); + out.add(ByteUtil.bytesToHex(param, false)); index++; } } diff --git a/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java new file mode 100644 index 0000000..29eb671 --- /dev/null +++ b/src/cz/crcs/ectester/common/output/BaseTextTestWriter.java @@ -0,0 +1,82 @@ +package cz.crcs.ectester.common.output; + +import cz.crcs.ectester.common.test.*; + +import java.io.PrintStream; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class BaseTextTestWriter implements TestWriter { + private PrintStream output; + + public static int BASE_WIDTH = 90; + + public BaseTextTestWriter(PrintStream output) { + this.output = output; + } + + @Override + public void begin(TestSuite suite) { + output.println("═══ Running test suite: " + suite.getName() + " ═══"); + output.println("═══ " + suite.getDescription()); + output.print(deviceString(suite)); + } + + protected abstract String testableString(Testable t); + + protected abstract String deviceString(TestSuite suite); + + private String testString(Test t, String prefix) { + if (!t.hasRun()) { + return null; + } + boolean compound = t instanceof CompoundTest; + + StringBuilder out = new StringBuilder(); + out.append(t.ok() ? " OK " : "NOK "); + out.append(compound ? "┳ " : "━ "); + int width = BASE_WIDTH - (prefix.length() + out.length()); + String widthSpec = "%-" + String.valueOf(width) + "s"; + out.append(String.format(widthSpec, t.getDescription())); + out.append(" ┃ "); + out.append(String.format("%-9s", t.getResultValue().name())); + out.append(" ┃ "); + + if (compound) { + CompoundTest test = (CompoundTest) t; + out.append(test.getResultCause()); + out.append(System.lineSeparator()); + Test[] tests = test.getTests(); + for (int i = 0; i < tests.length; ++i) { + if (i == tests.length - 1) { + out.append(prefix).append(" ┗ "); + out.append(testString(tests[i], prefix + " ")); + } else { + out.append(prefix).append(" ┣ "); + out.append(testString(tests[i], prefix + " ┃ ")); + } + + if (i != tests.length - 1) { + out.append(System.lineSeparator()); + } + } + } else { + SimpleTest test = (SimpleTest) t; + out.append(testableString(test.getTestable())); + } + return out.toString(); + } + + @Override + public void outputTest(Test t) { + if (!t.hasRun()) + return; + output.println(testString(t, "")); + output.flush(); + } + + @Override + public void end() { + } +} diff --git a/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java new file mode 100644 index 0000000..f3e9411 --- /dev/null +++ b/src/cz/crcs/ectester/common/output/BaseXMLTestWriter.java @@ -0,0 +1,103 @@ +package cz.crcs.ectester.common.output; + +import cz.crcs.ectester.common.test.*; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.OutputStream; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class BaseXMLTestWriter implements TestWriter { + private OutputStream output; + private DocumentBuilder db; + protected Document doc; + private Node root; + + public BaseXMLTestWriter(OutputStream output) throws ParserConfigurationException { + this.output = output; + this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + } + + @Override + public void begin(TestSuite suite) { + doc = db.newDocument(); + Element rootElem = doc.createElement("testSuite"); + rootElem.setAttribute("name", suite.getName()); + rootElem.setAttribute("desc", suite.getDescription()); + + root = rootElem; + doc.appendChild(root); + root.appendChild(deviceElement(suite)); + } + + protected abstract Element testableElement(Testable t); + + protected abstract Element deviceElement(TestSuite suite); + + private Element testElement(Test t) { + Element testElem; + if (t instanceof CompoundTest) { + CompoundTest test = (CompoundTest) t; + testElem = doc.createElement("test"); + testElem.setAttribute("type", "compound"); + for (Test innerTest : test.getTests()) { + testElem.appendChild(testElement(innerTest)); + } + } else { + SimpleTest test = (SimpleTest) t; + testElem = testableElement(test.getTestable()); + } + + Element description = doc.createElement("desc"); + description.setTextContent(t.getDescription()); + testElem.appendChild(description); + + Element result = doc.createElement("result"); + Element ok = doc.createElement("ok"); + ok.setTextContent(String.valueOf(t.ok())); + Element value = doc.createElement("value"); + value.setTextContent(t.getResultValue().name()); + Element cause = doc.createElement("cause"); + cause.setTextContent(t.getResultCause()); + result.appendChild(ok); + result.appendChild(value); + result.appendChild(cause); + testElem.appendChild(result); + + return testElem; + } + + @Override + public void outputTest(Test t) { + if (!t.hasRun()) + return; + root.appendChild(testElement(t)); + } + + @Override + public void end() { + try { + DOMSource domSource = new DOMSource(doc); + StreamResult result = new StreamResult(output); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + transformer.transform(domSource, result); + } catch (TransformerException e) { + e.printStackTrace(); + } + } +} diff --git a/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java new file mode 100644 index 0000000..0769e83 --- /dev/null +++ b/src/cz/crcs/ectester/common/output/BaseYAMLTestWriter.java @@ -0,0 +1,91 @@ +package cz.crcs.ectester.common.output; + +import cz.crcs.ectester.common.test.*; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.PrintStream; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class BaseYAMLTestWriter implements TestWriter { + private PrintStream output; + private Map<String, Object> testRun; + private Map<String, String> testSuite; + protected List<Object> tests; + + public BaseYAMLTestWriter(PrintStream output) { + this.output = output; + } + + @Override + public void begin(TestSuite suite) { + output.println("---"); + testRun = new HashMap<>(); + testSuite = new HashMap<>(); + tests = new LinkedList<>(); + testSuite.put("name", suite.getName()); + testSuite.put("desc", suite.getDescription()); + + testRun.put("suite", testSuite); + testRun.put("device", deviceObject(suite)); + testRun.put("tests", tests); + } + + abstract protected Map<String, Object> testableObject(Testable t); + + abstract protected Map<String, Object> deviceObject(TestSuite suite); + + private Map<String, Object> testObject(Test t) { + Map<String, Object> testObj; + if (t instanceof CompoundTest) { + CompoundTest test = (CompoundTest) t; + testObj = new HashMap<>(); + testObj.put("type", "compound"); + List<Map<String, Object>> innerTests = new LinkedList<>(); + for (Test innerTest : test.getTests()) { + innerTests.add(testObject(innerTest)); + } + testObj.put("tests", innerTests); + } else { + SimpleTest test = (SimpleTest) t; + testObj = testableObject(test.getTestable()); + } + + testObj.put("desc", t.getDescription()); + Map<String, Object> result = new HashMap<>(); + result.put("ok", t.ok()); + result.put("value", t.getResultValue().name()); + result.put("cause", t.getResultCause()); + testObj.put("result", result); + + return testObj; + } + + @Override + public void outputTest(Test t) { + if (!t.hasRun()) + return; + tests.add(testObject(t)); + } + + @Override + public void end() { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setPrettyFlow(true); + Yaml yaml = new Yaml(options); + + Map<String, Object> result = new HashMap<>(); + result.put("testRun", testRun); + String out = yaml.dump(result); + + output.println(out); + output.println("---"); + } +} diff --git a/src/cz/crcs/ectester/reader/output/OutputLogger.java b/src/cz/crcs/ectester/common/output/OutputLogger.java index bf47a1f..09b8f73 100644 --- a/src/cz/crcs/ectester/reader/output/OutputLogger.java +++ b/src/cz/crcs/ectester/common/output/OutputLogger.java @@ -1,4 +1,4 @@ -package cz.crcs.ectester.reader.output; +package cz.crcs.ectester.common.output; import java.io.*; import java.util.LinkedList; diff --git a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java b/src/cz/crcs/ectester/common/output/TeeOutputStream.java index 2a1af99..2401fce 100644 --- a/src/cz/crcs/ectester/reader/output/TeeOutputStream.java +++ b/src/cz/crcs/ectester/common/output/TeeOutputStream.java @@ -1,4 +1,4 @@ -package cz.crcs.ectester.reader.output; +package cz.crcs.ectester.common.output; import java.io.IOException; import java.io.OutputStream; diff --git a/src/cz/crcs/ectester/reader/output/TestWriter.java b/src/cz/crcs/ectester/common/output/TestWriter.java index 74c76fb..0ecfd5a 100644 --- a/src/cz/crcs/ectester/reader/output/TestWriter.java +++ b/src/cz/crcs/ectester/common/output/TestWriter.java @@ -1,7 +1,7 @@ -package cz.crcs.ectester.reader.output; +package cz.crcs.ectester.common.output; -import cz.crcs.ectester.reader.test.Test; -import cz.crcs.ectester.reader.test.TestSuite; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.test.TestSuite; /** * @author Jan Jancar johny@neuromancer.sk diff --git a/src/cz/crcs/ectester/common/test/BaseTestable.java b/src/cz/crcs/ectester/common/test/BaseTestable.java new file mode 100644 index 0000000..a4b9a00 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/BaseTestable.java @@ -0,0 +1,32 @@ +package cz.crcs.ectester.common.test; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class BaseTestable implements Testable { + protected boolean hasRun; + protected boolean ok; + protected boolean error; + + @Override + public boolean hasRun() { + return hasRun; + } + + @Override + public boolean ok() { + return ok; + } + + @Override + public boolean error() { + return error; + } + + @Override + public void reset() { + hasRun = false; + ok = false; + error = false; + } +} diff --git a/src/cz/crcs/ectester/common/test/CompoundTest.java b/src/cz/crcs/ectester/common/test/CompoundTest.java new file mode 100644 index 0000000..10ecf9c --- /dev/null +++ b/src/cz/crcs/ectester/common/test/CompoundTest.java @@ -0,0 +1,111 @@ +package cz.crcs.ectester.common.test; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; + +/** + * A compound test that runs many Tests and has a Result dependent on all/some of their Results. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public class CompoundTest extends Test { + private Function<Test[], Result> callback; + private Test[] tests; + private String description; + + private CompoundTest(Function<Test[], Result> callback, Test... tests) { + this.callback = callback; + this.tests = Arrays.stream(tests).filter(Objects::nonNull).toArray(Test[]::new); + } + + private CompoundTest(Function<Test[], Result> callback, String descripiton, Test... tests) { + this(callback, tests); + this.description = descripiton; + } + + public static CompoundTest function(Function<Test[], Result> callback, Test... tests) { + return new CompoundTest(callback, tests); + } + + public static CompoundTest function(Function<Test[], Result> callback, String description, Test... tests) { + return new CompoundTest(callback, description, tests); + } + + public static CompoundTest all(Result.ExpectedValue what, Test... all) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (!Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.FAILURE, "Some sub-tests did not have the expected result."); + } + } + return new Result(Result.Value.SUCCESS, "All sub-tests had the expected result."); + }, all); + } + + public static CompoundTest all(Result.ExpectedValue what, String description, Test... all) { + CompoundTest result = CompoundTest.all(what, all); + result.setDescription(description); + return result; + } + + public static CompoundTest any(Result.ExpectedValue what, Test... any) { + return new CompoundTest((tests) -> { + for (Test test : tests) { + if (Result.Value.fromExpected(what, test.ok()).ok()) { + return new Result(Result.Value.SUCCESS, "Some sub-tests did have the expected result."); + } + } + return new Result(Result.Value.FAILURE, "None of the sub-tests had the expected result."); + }, any); + } + + public static CompoundTest any(Result.ExpectedValue what, String description, Test... any) { + CompoundTest result = CompoundTest.any(what, any); + result.setDescription(description); + return result; + } + + public static CompoundTest mask(Result.ExpectedValue[] results, Test... masked) { + return new CompoundTest((tests) -> { + for (int i = 0; i < results.length; ++i) { + if (!Result.Value.fromExpected(results[i], tests[i].ok()).ok()) { + return new Result(Result.Value.FAILURE, "Some sub-tests did not match the result mask."); + } + } + return new Result(Result.Value.SUCCESS, "All sub-tests matched the expected mask."); + }, masked); + } + + public static CompoundTest mask(Result.ExpectedValue[] results, String description, Test... masked) { + CompoundTest result = CompoundTest.mask(results, masked); + result.setDescription(description); + return result; + } + + public Test[] getTests() { + return tests; + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + for (Test test : tests) { + test.run(); + } + + result = callback.apply(tests); + this.hasRun = true; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/src/cz/crcs/ectester/reader/test/Result.java b/src/cz/crcs/ectester/common/test/Result.java index 82f0f32..11fcb4d 100644 --- a/src/cz/crcs/ectester/reader/test/Result.java +++ b/src/cz/crcs/ectester/common/test/Result.java @@ -1,6 +1,8 @@ -package cz.crcs.ectester.reader.test; +package cz.crcs.ectester.common.test; /** + * A Result of a Test. Has a Value and an optional String cause. + * * @author Jan Jancar johny@neuromancer.sk */ public class Result { @@ -44,7 +46,7 @@ public class Result { } /** - * + * A result value of a Test. */ public enum Value { SUCCESS(true), @@ -84,7 +86,7 @@ public class Result { } /** - * + * A possible expected value result of a Test. */ public enum ExpectedValue { SUCCESS, diff --git a/src/cz/crcs/ectester/common/test/SimpleTest.java b/src/cz/crcs/ectester/common/test/SimpleTest.java new file mode 100644 index 0000000..f68320a --- /dev/null +++ b/src/cz/crcs/ectester/common/test/SimpleTest.java @@ -0,0 +1,19 @@ +package cz.crcs.ectester.common.test; + +/** + * @param <T> + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class SimpleTest<T extends BaseTestable> extends Test { + protected T testable; + protected TestCallback<T> callback; + + public SimpleTest(T testable, TestCallback<T> callback) { + this.testable = testable; + this.callback = callback; + } + + public T getTestable() { + return testable; + } +} diff --git a/src/cz/crcs/ectester/common/test/Test.java b/src/cz/crcs/ectester/common/test/Test.java new file mode 100644 index 0000000..3d0baf6 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/Test.java @@ -0,0 +1,66 @@ +package cz.crcs.ectester.common.test; + +import static cz.crcs.ectester.common.test.Result.Value; + +/** + * An abstract test that can be run and has a Result. + * + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class Test implements Testable { + protected boolean hasRun; + protected Result result; + + public Result getResult() { + if (!hasRun) { + return null; + } + return result; + } + + public Value getResultValue() { + if (!hasRun) { + return null; + } + return result.getValue(); + } + + public String getResultCause() { + if (!hasRun) { + return null; + } + return result.getCause(); + } + + public boolean ok() { + if (!hasRun) { + return true; + } + return result.ok(); + } + + @Override + public boolean error() { + if (!hasRun) { + return false; + } + return result.compareTo(Value.ERROR); + } + + @Override + public boolean hasRun() { + return hasRun; + } + + @Override + public void reset() { + hasRun = false; + result = null; + } + + public abstract String getDescription(); + + @Override + public abstract void run() throws TestException; + +} diff --git a/src/cz/crcs/ectester/common/test/TestCallback.java b/src/cz/crcs/ectester/common/test/TestCallback.java new file mode 100644 index 0000000..ce6000b --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestCallback.java @@ -0,0 +1,12 @@ +package cz.crcs.ectester.common.test; + +import java.util.function.Function; + +/** + * + * @author Jan Jancar johny@neuromancer.sk + * @param <T> + */ +public abstract class TestCallback<T extends Testable> implements Function<T, Result> { + +} diff --git a/src/cz/crcs/ectester/common/test/TestException.java b/src/cz/crcs/ectester/common/test/TestException.java new file mode 100644 index 0000000..008e9f6 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestException.java @@ -0,0 +1,13 @@ +package cz.crcs.ectester.common.test; + +/** + * A TestException is an Exception that can be thrown during the running of a Testable, + * or a TestSuite. It means that the Testable/TestSuite encountered an unexpected error + * during it's run which points to an error in ECTester or it's runtime environment.cd + * @author Jan Jancar johny@neuromancer.sk + */ +public class TestException extends Exception { + public TestException(Throwable e) { + super(e); + } +} diff --git a/src/cz/crcs/ectester/common/test/TestSuite.java b/src/cz/crcs/ectester/common/test/TestSuite.java new file mode 100644 index 0000000..f4f30ee --- /dev/null +++ b/src/cz/crcs/ectester/common/test/TestSuite.java @@ -0,0 +1,56 @@ +package cz.crcs.ectester.common.test; + +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.data.EC_Store; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class TestSuite { + protected String name; + protected String description; + protected TestWriter writer; + + public TestSuite(TestWriter writer, String name, String description) { + this.writer = writer; + this.name = name; + this.description = description; + } + + public void run() throws TestException { + writer.begin(this); + try { + runTests(); + } catch (Exception e) { + throw new TestException(e); + } + writer.end(); + } + + protected Test runTest(Test t) throws TestException { + t.run(); + return t; + } + + protected Test doTest(Test t) throws TestException { + t.run(); + writer.outputTest(t); + return t; + } + + protected abstract void runTests() throws Exception; + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/cz/crcs/ectester/common/test/Testable.java b/src/cz/crcs/ectester/common/test/Testable.java new file mode 100644 index 0000000..33c9485 --- /dev/null +++ b/src/cz/crcs/ectester/common/test/Testable.java @@ -0,0 +1,33 @@ +package cz.crcs.ectester.common.test; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public interface Testable { + /** + * @return Whether this Testable was OK. + */ + boolean ok(); + + /** + * @return Whether an error happened. + */ + boolean error(); + + /** + * @return Whether this runnable was run. + */ + boolean hasRun(); + + /** + * + */ + void reset(); + + /** + * Run this Runnable. + * + * @throws TestException If an unexpected exception/error is encountered. + */ + void run() throws TestException; +} diff --git a/src/cz/crcs/ectester/common/util/ByteUtil.java b/src/cz/crcs/ectester/common/util/ByteUtil.java new file mode 100644 index 0000000..90c6eaa --- /dev/null +++ b/src/cz/crcs/ectester/common/util/ByteUtil.java @@ -0,0 +1,128 @@ +package cz.crcs.ectester.common.util; + +/** + * Utility class, some byte/hex manipulation, convenient byte[] methods. + * + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class ByteUtil { + public static short getShort(byte[] array, int offset) { + return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); + } + + public static void setShort(byte[] array, int offset, short value) { + array[offset + 1] = (byte) (value & 0xFF); + array[offset] = (byte) ((value >> 8) & 0xFF); + } + + public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { + for (int i = 0; i < length; ++i) { + byte a = one[i + oneOffset]; + byte b = other[i + otherOffset]; + if (a != b) { + return i; + } + } + return length; + } + + public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { + return diffBytes(one, oneOffset, other, otherOffset, length) == length; + } + + public static boolean allValue(byte[] array, byte value) { + for (byte a : array) { + if (a != value) + return false; + } + return true; + } + + public static byte[] hexToBytes(String hex) { + return hexToBytes(hex, true); + } + + public static byte[] hexToBytes(String hex, boolean bigEndian) { + hex = hex.replace(" ", ""); + int len = hex.length(); + StringBuilder sb = new StringBuilder(); + + if (len % 2 == 1) { + sb.append("0"); + ++len; + } + + if (bigEndian) { + sb.append(hex); + } else { + for (int i = 0; i < len / 2; ++i) { + if (sb.length() >= 2) { + sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2)); + } else { + sb.append(hex.substring(2 * i, 2 * i + 2)); + } + + } + } + + String data = sb.toString(); + byte[] result = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4) + + (Character.digit(data.charAt(i + 1), 16))); + } + return result; + } + + public static String byteToHex(byte data) { + return String.format("%02x", data); + } + + public static String bytesToHex(byte[] data) { + return bytesToHex(data, true); + } + + public static String bytesToHex(byte[] data, boolean addSpace) { + if (data == null) { + return ""; + } + return bytesToHex(data, 0, data.length, addSpace); + } + + public static String bytesToHex(byte[] data, int offset, int len) { + return bytesToHex(data, offset, len, true); + } + + public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) { + if (data == null) { + return ""; + } + StringBuilder buf = new StringBuilder(); + for (int i = offset; i < (offset + len); i++) { + buf.append(byteToHex(data[i])); + if (addSpace && i != (offset + len - 1)) { + buf.append(" "); + } + } + return (buf.toString()); + } + + public static byte[] concatenate(byte[]... arrays) { + int len = 0; + for (byte[] array : arrays) { + if (array == null) + continue; + len += array.length; + } + byte[] out = new byte[len]; + int offset = 0; + for (byte[] array : arrays) { + if (array == null || array.length == 0) + continue; + System.arraycopy(array, 0, out, offset, array.length); + offset += array.length; + } + return out; + } +} diff --git a/src/cz/crcs/ectester/common/util/CardUtil.java b/src/cz/crcs/ectester/common/util/CardUtil.java new file mode 100644 index 0000000..8285d8b --- /dev/null +++ b/src/cz/crcs/ectester/common/util/CardUtil.java @@ -0,0 +1,272 @@ +package cz.crcs.ectester.common.util; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import javacard.framework.ISO7816; +import javacard.security.CryptoException; + +import static cz.crcs.ectester.applet.ECTesterApplet.*; + +/** + * @author Petr Svenda petr@svenda.com + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardUtil { + public static byte getKA(String name) { + switch (name) { + case "DH": + case "ECDH": + return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; + case "DHC": + case "ECDHC": + return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC; + default: + return ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; + } + } + + public static String getSWSource(short sw) { + switch (sw) { + case ISO7816.SW_NO_ERROR: + case ISO7816.SW_APPLET_SELECT_FAILED: + case ISO7816.SW_BYTES_REMAINING_00: + case ISO7816.SW_CLA_NOT_SUPPORTED: + case ISO7816.SW_COMMAND_NOT_ALLOWED: + case ISO7816.SW_CONDITIONS_NOT_SATISFIED: + case ISO7816.SW_CORRECT_LENGTH_00: + case ISO7816.SW_DATA_INVALID: + case ISO7816.SW_FILE_FULL: + case ISO7816.SW_FILE_INVALID: + case ISO7816.SW_FILE_NOT_FOUND: + case ISO7816.SW_FUNC_NOT_SUPPORTED: + case ISO7816.SW_INCORRECT_P1P2: + case ISO7816.SW_INS_NOT_SUPPORTED: + case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: + case ISO7816.SW_RECORD_NOT_FOUND: + case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: + case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: + case ISO7816.SW_UNKNOWN: + case ISO7816.SW_WARNING_STATE_UNCHANGED: + case ISO7816.SW_WRONG_DATA: + case ISO7816.SW_WRONG_LENGTH: + case ISO7816.SW_WRONG_P1P2: + return "ISO"; + case CryptoException.ILLEGAL_VALUE: + case CryptoException.UNINITIALIZED_KEY: + case CryptoException.NO_SUCH_ALGORITHM: + case CryptoException.INVALID_INIT: + case CryptoException.ILLEGAL_USE: + return "CryptoException"; + case ECTesterApplet.SW_SIG_VERIFY_FAIL: + case ECTesterApplet.SW_DH_DHC_MISMATCH: + case ECTesterApplet.SW_KEYPAIR_NULL: + case ECTesterApplet.SW_KA_NULL: + case ECTesterApplet.SW_SIGNATURE_NULL: + case ECTesterApplet.SW_OBJECT_NULL: + return "ECTesterApplet"; + default: + return "?"; + } + } + + public static String getSW(short sw) { + switch (sw) { + case ISO7816.SW_APPLET_SELECT_FAILED: + return "APPLET_SELECT_FAILED"; + case ISO7816.SW_BYTES_REMAINING_00: + return "BYTES_REMAINING"; + case ISO7816.SW_CLA_NOT_SUPPORTED: + return "CLA_NOT_SUPPORTED"; + case ISO7816.SW_COMMAND_NOT_ALLOWED: + return "COMMAND_NOT_ALLOWED"; + case ISO7816.SW_CONDITIONS_NOT_SATISFIED: + return "CONDITIONS_NOT_SATISFIED"; + case ISO7816.SW_CORRECT_LENGTH_00: + return "CORRECT_LENGTH"; + case ISO7816.SW_DATA_INVALID: + return "DATA_INVALID"; + case ISO7816.SW_FILE_FULL: + return "FILE_FULL"; + case ISO7816.SW_FILE_INVALID: + return "FILE_INVALID"; + case ISO7816.SW_FILE_NOT_FOUND: + return "FILE_NOT_FOUND"; + case ISO7816.SW_FUNC_NOT_SUPPORTED: + return "FUNC_NOT_SUPPORTED"; + case ISO7816.SW_INCORRECT_P1P2: + return "INCORRECT_P1P2"; + case ISO7816.SW_INS_NOT_SUPPORTED: + return "INS_NOT_SUPPORTED"; + case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: + return "LOGICAL_CHANNEL_NOT_SUPPORTED"; + case ISO7816.SW_RECORD_NOT_FOUND: + return "RECORD_NOT_FOUND"; + case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: + return "SECURE_MESSAGING_NOT_SUPPORTED"; + case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: + return "SECURITY_STATUS_NOT_SATISFIED"; + case ISO7816.SW_UNKNOWN: + return "UNKNOWN"; + case ISO7816.SW_WARNING_STATE_UNCHANGED: + return "WARNING_STATE_UNCHANGED"; + case ISO7816.SW_WRONG_DATA: + return "WRONG_DATA"; + case ISO7816.SW_WRONG_LENGTH: + return "WRONG_LENGTH"; + case ISO7816.SW_WRONG_P1P2: + return "WRONG_P1P2"; + case CryptoException.ILLEGAL_VALUE: + return "ILLEGAL_VALUE"; + case CryptoException.UNINITIALIZED_KEY: + return "UNINITIALIZED_KEY"; + case CryptoException.NO_SUCH_ALGORITHM: + return "NO_SUCH_ALG"; + case CryptoException.INVALID_INIT: + return "INVALID_INIT"; + case CryptoException.ILLEGAL_USE: + return "ILLEGAL_USE"; + case ECTesterApplet.SW_SIG_VERIFY_FAIL: + return "SIG_VERIFY_FAIL"; + case ECTesterApplet.SW_DH_DHC_MISMATCH: + return "DH_DHC_MISMATCH"; + case ECTesterApplet.SW_KEYPAIR_NULL: + return "KEYPAIR_NULL"; + case ECTesterApplet.SW_KA_NULL: + return "KA_NULL"; + case ECTesterApplet.SW_SIGNATURE_NULL: + return "SIGNATURE_NULL"; + case ECTesterApplet.SW_OBJECT_NULL: + return "OBJECT_NULL"; + default: + return "unknown"; + } + } + + public static String getSWString(short sw) { + if (sw == ISO7816.SW_NO_ERROR) { + return "OK (0x9000)"; + } else { + String str = getSW(sw); + return String.format("fail (%s, 0x%04x)", str, sw); + } + } + + public static String getCorruption(short corruptionType) { + switch (corruptionType) { + case EC_Consts.CORRUPTION_NONE: + return "NONE"; + case EC_Consts.CORRUPTION_FIXED: + return "FIXED"; + case EC_Consts.CORRUPTION_ONE: + return "ONE"; + case EC_Consts.CORRUPTION_ZERO: + return "ZERO"; + case EC_Consts.CORRUPTION_ONEBYTERANDOM: + return "ONE_BYTE_RANDOM"; + case EC_Consts.CORRUPTION_FULLRANDOM: + return "FULL_RANDOM"; + case EC_Consts.CORRUPTION_INCREMENT: + return "INCREMENT"; + case EC_Consts.CORRUPTION_INFINITY: + return "INFINITY"; + case EC_Consts.CORRUPTION_COMPRESS: + return "COMPRESSED"; + case EC_Consts.CORRUPTION_MAX: + return "MAX"; + default: + return "unknown"; + } + } + + public static String getKATypeString(byte kaType) { + switch (kaType) { + case KeyAgreement_ALG_EC_SVDP_DH: + return "ALG_EC_SVDP_DH"; + case KeyAgreement_ALG_EC_SVDP_DH_PLAIN: + return "ALG_EC_SVDP_DH_PLAIN"; + case KeyAgreement_ALG_EC_PACE_GM: + return "ALG_EC_PACE_GM"; + case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY: + return "ALG_EC_SVDP_DH_PLAIN_XY"; + case KeyAgreement_ALG_EC_SVDP_DHC: + return "ALG_EC_SVDP_DHC"; + case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN: + return "ALG_EC_SVDP_DHC_PLAIN"; + default: + return "unknown"; + } + } + + public static byte getKAType(String kaTypeString) { + switch (kaTypeString) { + case "ALG_EC_SVDP_DH": + return KeyAgreement_ALG_EC_SVDP_DH; + case "ALG_EC_SVDP_DH_PLAIN": + return KeyAgreement_ALG_EC_SVDP_DH_PLAIN; + case "ALG_EC_PACE_GM": + return KeyAgreement_ALG_EC_PACE_GM; + case "ALG_EC_SVDP_DH_PLAIN_XY": + return KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY; + case "ALG_EC_SVDP_DHC": + return KeyAgreement_ALG_EC_SVDP_DHC; + case "ALG_EC_SVDP_DHC_PLAIN": + return KeyAgreement_ALG_EC_SVDP_DHC_PLAIN; + default: + return 0; + } + } + + public static byte parseKAType(String kaTypeString) { + byte kaType; + try { + kaType = Byte.parseByte(kaTypeString); + } catch (NumberFormatException nfex) { + kaType = getKAType(kaTypeString); + } + return kaType; + } + + public static String getSigTypeString(byte sigType) { + switch (sigType) { + case Signature_ALG_ECDSA_SHA: + return "ALG_ECDSA_SHA"; + case Signature_ALG_ECDSA_SHA_224: + return "ALG_ECDSA_SHA_224"; + case Signature_ALG_ECDSA_SHA_256: + return "ALG_ECDSA_SHA_256"; + case Signature_ALG_ECDSA_SHA_384: + return "ALG_ECDSA_SHA_384"; + case Signature_ALG_ECDSA_SHA_512: + return "ALG_ECDSA_SHA_512"; + default: + return "unknown"; + } + } + + public static byte getSigType(String sigTypeString) { + switch (sigTypeString) { + case "ALG_ECDSA_SHA": + return Signature_ALG_ECDSA_SHA; + case "ALG_ECDSA_SHA_224": + return Signature_ALG_ECDSA_SHA_224; + case "ALG_ECDSA_SHA_256": + return Signature_ALG_ECDSA_SHA_256; + case "ALG_ECDSA_SHA_384": + return Signature_ALG_ECDSA_SHA_384; + case "ALG_ECDSA_SHA_512": + return Signature_ALG_ECDSA_SHA_512; + default: + return 0; + } + } + + public static byte parseSigType(String sigTypeString) { + byte sigType; + try { + sigType = Byte.parseByte(sigTypeString); + } catch (NumberFormatException nfex) { + sigType = getSigType(sigTypeString); + } + return sigType; + } +} diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java new file mode 100644 index 0000000..973b813 --- /dev/null +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -0,0 +1,172 @@ +package cz.crcs.ectester.common.util; + +import java.math.BigInteger; +import java.security.spec.*; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class ECUtil { + + public static byte[] toByteArray(BigInteger what, int bits) { + byte[] raw = what.toByteArray(); + int bytes = (bits + 7) / 8; + if (raw.length < bytes) { + byte[] result = new byte[bytes]; + System.arraycopy(raw, 0, result, bytes - raw.length, raw.length); + return result; + } + if (bytes < raw.length) { + byte[] result = new byte[bytes]; + System.arraycopy(raw, raw.length - bytes, result, 0, bytes); + return result; + } + return raw; + } + + public static byte[] toX962Compressed(ECPoint point, int bits) { + if (point.equals(ECPoint.POINT_INFINITY)) { + return new byte[]{0}; + } + byte[] x = toByteArray(point.getAffineX(), bits); + byte marker = (byte) (0x02 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue()); + return ByteUtil.concatenate(new byte[]{marker}, x); + } + + public static byte[] toX962Compressed(ECPoint point, EllipticCurve curve) { + return toX962Compressed(point, curve.getField().getFieldSize()); + } + + public static byte[] toX962Compressed(ECPoint point, ECParameterSpec spec) { + return toX962Compressed(point, spec.getCurve()); + } + + public static byte[] toX962Uncompressed(ECPoint point, int bits) { + if (point.equals(ECPoint.POINT_INFINITY)) { + return new byte[]{0}; + } + byte[] x = toByteArray(point.getAffineX(), bits); + byte[] y = toByteArray(point.getAffineY(), bits); + return ByteUtil.concatenate(new byte[]{0x04}, x, y); + } + + public static byte[] toX962Uncompressed(ECPoint point, EllipticCurve curve) { + return toX962Uncompressed(point, curve.getField().getFieldSize()); + } + + public static byte[] toX962Uncompressed(ECPoint point, ECParameterSpec spec) { + return toX962Uncompressed(point, spec.getCurve()); + } + + public static byte[] toX962Hybrid(ECPoint point, int bits) { + if (point.equals(ECPoint.POINT_INFINITY)) { + return new byte[]{0}; + } + byte[] x = toByteArray(point.getAffineX(), bits); + byte[] y = toByteArray(point.getAffineY(), bits); + byte marker = (byte) (0x06 | point.getAffineY().mod(BigInteger.valueOf(2)).byteValue()); + return ByteUtil.concatenate(new byte[]{marker}, x, y); + } + + public static byte[] toX962Hybrid(ECPoint point, EllipticCurve curve) { + return toX962Hybrid(point, curve.getField().getFieldSize()); + } + + public static byte[] toX962Hybrid(ECPoint point, ECParameterSpec spec) { + return toX962Hybrid(point, spec.getCurve()); + } + + private static boolean isResidue(BigInteger a, BigInteger p) { + BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); + BigInteger result = a.modPow(exponent, p); + return result.intValueExact() == 1; + } + + private static BigInteger modSqrt(BigInteger a, BigInteger p) { + BigInteger q = p.subtract(BigInteger.ONE); + int s = 0; + while (q.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) { + q = q.divide(BigInteger.valueOf(2)); + s++; + } + + BigInteger z = BigInteger.ONE; + do { + z = z.add(BigInteger.ONE); + } while (isResidue(z, p)); + + BigInteger m = BigInteger.valueOf(s); + BigInteger c = z.modPow(q, p); + BigInteger t = a.modPow(q, p); + BigInteger rExponent = q.add(BigInteger.ONE).divide(BigInteger.valueOf(2)); + BigInteger r = a.modPow(rExponent, p); + + while (!t.equals(BigInteger.ONE)) { + int i = 0; + BigInteger exponent; + do { + exponent = BigInteger.valueOf(2).pow(++i); + } while (!t.modPow(exponent, p).equals(BigInteger.ONE)); + + BigInteger twoExponent = m.subtract(BigInteger.valueOf(i + 1)); + BigInteger b = c.modPow(BigInteger.valueOf(2).modPow(twoExponent, p), p); + m = BigInteger.valueOf(i); + c = b.modPow(BigInteger.valueOf(2), p); + t = t.multiply(c).mod(p); + r = r.multiply(b).mod(p); + } + return r; + } + + public static ECPoint fromX962(byte[] data, EllipticCurve curve) { + if (data == null) { + return null; + } + if (data[0] == 0x04 || data[0] == 0x06 || data[0] == 0x07) { + int len = (data.length - 1) / 2; + byte[] xbytes = new byte[len]; + System.arraycopy(data, 1, xbytes, 0, len); + byte[] ybytes = new byte[len]; + System.arraycopy(data, 1 + len, ybytes, 0, len); + return new ECPoint(new BigInteger(1, xbytes), new BigInteger(1, ybytes)); + } else if (data[0] == 0x02 || data[0] == 0x03) { + if (curve == null) { + throw new IllegalArgumentException(); + } + byte[] xbytes = new byte[data.length - 1]; + System.arraycopy(data, 1, xbytes, 0, data.length - 1); + BigInteger x = new BigInteger(1, xbytes); + BigInteger a = curve.getA(); + BigInteger b = curve.getB(); + + ECField field = curve.getField(); + if (field instanceof ECFieldFp) { + BigInteger p = ((ECFieldFp) field).getP(); + BigInteger alpha = x.modPow(BigInteger.valueOf(3), p); + alpha = alpha.add(x.multiply(a)); + alpha = alpha.add(b); + + BigInteger beta = modSqrt(alpha, p); + if (beta.getLowestSetBit() == 0) { + // rightmost bit is one + if (data[0] == 0x02) { + beta = beta.negate(); + } + } else { + // rightmost bit is zero + if (data[0] == 0x03) { + beta = beta.negate(); + } + } + + return new ECPoint(x, beta); + } else if (field instanceof ECFieldF2m) { + //TODO + throw new UnsupportedOperationException(); + } + return null; + } else { + throw new IllegalArgumentException(); + } + } +} diff --git a/src/cz/crcs/ectester/data/EC_Store.java b/src/cz/crcs/ectester/data/EC_Store.java index 9b1f5bb..e4ba40c 100644 --- a/src/cz/crcs/ectester/data/EC_Store.java +++ b/src/cz/crcs/ectester/data/EC_Store.java @@ -1,7 +1,6 @@ package cz.crcs.ectester.data; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.ec.*; +import cz.crcs.ectester.common.ec.*; import javacard.security.KeyPair; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -30,12 +29,11 @@ import java.util.TreeMap; * @author Jan Jancar johny@neuromancer.sk */ public class EC_Store { - private DocumentBuilder db; - private Map<String, EC_Category> categories; + private static EC_Store instance; - public EC_Store() throws IOException { + private EC_Store() { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { @@ -84,7 +82,7 @@ public class EC_Store { }); parse(); - } catch (ParserConfigurationException | SAXException e) { + } catch (ParserConfigurationException | SAXException | IOException e) { e.printStackTrace(); } } @@ -217,25 +215,7 @@ public class EC_Store { descs = descc.item(0).getTextContent(); } - byte kab = EC_Consts.KA_ANY; - switch (ka.getTextContent()) { - case "DH": - case "ECDH": - kab = EC_Consts.KA_ECDH; - break; - case "DHC": - case "ECDHC": - kab = EC_Consts.KA_ECDHC; - break; - case "ANY": - kab = EC_Consts.KA_ANY; - break; - case "BOTH": - kab = EC_Consts.KA_BOTH; - break; - } - - EC_KAResult kaResult = new EC_KAResult(id.getTextContent(), kab, curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs); + EC_KAResult kaResult = new EC_KAResult(id.getTextContent(), ka.getTextContent(), curve.getTextContent(), onekey.getTextContent(), otherkey.getTextContent(), descs); InputStream csv = parseDataElement(dir, elem); if (!kaResult.readCSV(csv)) { @@ -339,4 +319,11 @@ public class EC_Store { return getObject(objClass, query.substring(0, split), query.substring(split + 1)); } + public static EC_Store getInstance() { + if (instance == null) { + instance = new EC_Store(); + } + return instance; + } + } diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml index 750fa8c..f123b6a 100644 --- a/src/cz/crcs/ectester/data/categories.xml +++ b/src/cz/crcs/ectester/data/categories.xml @@ -47,8 +47,18 @@ <desc></desc> </category> <category> + <name>twist</name> + <directory>twist</directory> + <desc></desc> + </category> + <category> <name>test</name> <directory>test</directory> <desc>Test vectors</desc> </category> + <category> + <name>x962</name> + <directory>x962</directory> + <desc>ANSI X9.62 example curves.</desc> + </category> </categories>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/nist/b163.csv b/src/cz/crcs/ectester/data/nist/b163.csv index 9259308..85b777b 100644 --- a/src/cz/crcs/ectester/data/nist/b163.csv +++ b/src/cz/crcs/ectester/data/nist/b163.csv @@ -1 +1 @@ -00a3,0007,0006,0003,000000000000000000000000000000000000000001,020a601907b8c953ca1481eb10512f78744a3205fd,03f0eba16286a2d57ea0991168d4994637e8343e36,00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,040000000000000000000292fe77e70c12a4234c33,2
\ No newline at end of file +0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x020a601907b8c953ca1481eb10512f78744a3205fd,0x03f0eba16286a2d57ea0991168d4994637e8343e36,0x00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,0x040000000000000000000292fe77e70c12a4234c33,0x2 diff --git a/src/cz/crcs/ectester/data/nist/b233.csv b/src/cz/crcs/ectester/data/nist/b233.csv index 79f0e85..a9c2711 100644 --- a/src/cz/crcs/ectester/data/nist/b233.csv +++ b/src/cz/crcs/ectester/data/nist/b233.csv @@ -1 +1 @@ -00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000001,0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,1000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,2
\ No newline at end of file +0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000001,0x0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,0x00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,0x01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,0x1000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,0x2 diff --git a/src/cz/crcs/ectester/data/nist/b283.csv b/src/cz/crcs/ectester/data/nist/b283.csv index 88506b3..06cc151 100644 --- a/src/cz/crcs/ectester/data/nist/b283.csv +++ b/src/cz/crcs/ectester/data/nist/b283.csv @@ -1 +1 @@ -011b,000c,0007,0005,00000000000000000000000000000000000000000000000000000000000000000000001,27b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,5f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,3676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,3ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,2
\ No newline at end of file +0x011b,0x000c,0x0007,0x0005,0x00000000000000000000000000000000000000000000000000000000000000000000001,0x27b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,0x5f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,0x3676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,0x3ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,0x2 diff --git a/src/cz/crcs/ectester/data/nist/b409.csv b/src/cz/crcs/ectester/data/nist/b409.csv index ed5ef5b..66523a7 100644 --- a/src/cz/crcs/ectester/data/nist/b409.csv +++ b/src/cz/crcs/ectester/data/nist/b409.csv @@ -1,9 +1 @@ -0199,0057,0000,0000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,15d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,10000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,2 - - - - - - - - +0x0199,0x0057,0x0000,0x0000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,0x15d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0x061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,0x10000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,0x2 diff --git a/src/cz/crcs/ectester/data/nist/b571.csv b/src/cz/crcs/ectester/data/nist/b571.csv index c0bef32..7d824c4 100644 --- a/src/cz/crcs/ectester/data/nist/b571.csv +++ b/src/cz/crcs/ectester/data/nist/b571.csv @@ -1 +1 @@ -023b,000a,0005,0002,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,2f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,2
\ No newline at end of file +0x023b,0x000a,0x0005,0x0002,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x2f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0x303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,0x37bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,0x3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,0x2 diff --git a/src/cz/crcs/ectester/data/nist/k163.csv b/src/cz/crcs/ectester/data/nist/k163.csv index 21c2f5f..e35fbda 100644 --- a/src/cz/crcs/ectester/data/nist/k163.csv +++ b/src/cz/crcs/ectester/data/nist/k163.csv @@ -1 +1 @@ -00a3,0007,0006,0003,000000000000000000000000000000000000000001,000000000000000000000000000000000000000001,02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0289070fb05d38ff58321f2e800536d538ccdaa3d9,04000000000000000000020108a2e0cc0d99f8a5ef,2
\ No newline at end of file +0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x000000000000000000000000000000000000000001,0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0x0289070fb05d38ff58321f2e800536d538ccdaa3d9,0x04000000000000000000020108a2e0cc0d99f8a5ef,0x2 diff --git a/src/cz/crcs/ectester/data/nist/k233.csv b/src/cz/crcs/ectester/data/nist/k233.csv index 45e3c49..a429d81 100644 --- a/src/cz/crcs/ectester/data/nist/k233.csv +++ b/src/cz/crcs/ectester/data/nist/k233.csv @@ -1 +1 @@ -00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,4
\ No newline at end of file +0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,0x01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,0x8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,0x4 diff --git a/src/cz/crcs/ectester/data/nist/k283.csv b/src/cz/crcs/ectester/data/nist/k283.csv index b0e2800..32dcc3e 100644 --- a/src/cz/crcs/ectester/data/nist/k283.csv +++ b/src/cz/crcs/ectester/data/nist/k283.csv @@ -1 +1 @@ -011b,000c,0007,0005,00000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000001,503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,1ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,1ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,4
\ No newline at end of file +0x011b,0x000c,0x0007,0x0005,0x00000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000001,0x503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,0x1ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,0x1ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,0x4 diff --git a/src/cz/crcs/ectester/data/nist/k409.csv b/src/cz/crcs/ectester/data/nist/k409.csv index fc44b82..119754a 100644 --- a/src/cz/crcs/ectester/data/nist/k409.csv +++ b/src/cz/crcs/ectester/data/nist/k409.csv @@ -1 +1 @@ -0199,0057,0000,0000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,1e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,4
\ No newline at end of file +0x0199,0x0057,0x0000,0x0000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,0x1e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,0x7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,0x4 diff --git a/src/cz/crcs/ectester/data/nist/k571.csv b/src/cz/crcs/ectester/data/nist/k571.csv index 5660f6a..7fb1431 100644 --- a/src/cz/crcs/ectester/data/nist/k571.csv +++ b/src/cz/crcs/ectester/data/nist/k571.csv @@ -1 +1 @@ -023b,000a,0005,0002,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,20000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,4
\ No newline at end of file +0x023b,0x000a,0x0005,0x0002,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x26eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0x349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,0x20000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect163k1.csv b/src/cz/crcs/ectester/data/secg/sect163k1.csv index 21c2f5f..e35fbda 100644 --- a/src/cz/crcs/ectester/data/secg/sect163k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect163k1.csv @@ -1 +1 @@ -00a3,0007,0006,0003,000000000000000000000000000000000000000001,000000000000000000000000000000000000000001,02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0289070fb05d38ff58321f2e800536d538ccdaa3d9,04000000000000000000020108a2e0cc0d99f8a5ef,2
\ No newline at end of file +0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x000000000000000000000000000000000000000001,0x02fe13c0537bbc11acaa07d793de4e6d5e5c94eee8,0x0289070fb05d38ff58321f2e800536d538ccdaa3d9,0x04000000000000000000020108a2e0cc0d99f8a5ef,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect163r1.csv b/src/cz/crcs/ectester/data/secg/sect163r1.csv index a537e6f..fa7a328 100644 --- a/src/cz/crcs/ectester/data/secg/sect163r1.csv +++ b/src/cz/crcs/ectester/data/secg/sect163r1.csv @@ -1 +1 @@ -00a3,0007,0006,0003,07b6882caaefa84f9554ff8428bd88e246d2782ae2,0713612dcddcb40aab946bda29ca91f73af958afd9,0369979697ab43897789566789567f787a7876a654,00435edb42efafb2989d51fefce3c80988f41ff883,03ffffffffffffffffffff48aab689c29ca710279b,2
\ No newline at end of file +0x00a3,0x0007,0x0006,0x0003,0x07b6882caaefa84f9554ff8428bd88e246d2782ae2,0x0713612dcddcb40aab946bda29ca91f73af958afd9,0x0369979697ab43897789566789567f787a7876a654,0x00435edb42efafb2989d51fefce3c80988f41ff883,0x03ffffffffffffffffffff48aab689c29ca710279b,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect163r2.csv b/src/cz/crcs/ectester/data/secg/sect163r2.csv index 9259308..85b777b 100644 --- a/src/cz/crcs/ectester/data/secg/sect163r2.csv +++ b/src/cz/crcs/ectester/data/secg/sect163r2.csv @@ -1 +1 @@ -00a3,0007,0006,0003,000000000000000000000000000000000000000001,020a601907b8c953ca1481eb10512f78744a3205fd,03f0eba16286a2d57ea0991168d4994637e8343e36,00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,040000000000000000000292fe77e70c12a4234c33,2
\ No newline at end of file +0x00a3,0x0007,0x0006,0x0003,0x000000000000000000000000000000000000000001,0x020a601907b8c953ca1481eb10512f78744a3205fd,0x03f0eba16286a2d57ea0991168d4994637e8343e36,0x00d51fbc6c71a0094fa2cdd545b11c5c0c797324f1,0x040000000000000000000292fe77e70c12a4234c33,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect233k1.csv b/src/cz/crcs/ectester/data/secg/sect233k1.csv index 45e3c49..a429d81 100644 --- a/src/cz/crcs/ectester/data/secg/sect233k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect233k1.csv @@ -1 +1 @@ -00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,4
\ No newline at end of file +0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x017232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126,0x01db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3,0x8000000000000000000000000000069d5bb915bcd46efb1ad5f173abdf,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect233r1.csv b/src/cz/crcs/ectester/data/secg/sect233r1.csv index 8f27bc2..faba42b 100644 --- a/src/cz/crcs/ectester/data/secg/sect233r1.csv +++ b/src/cz/crcs/ectester/data/secg/sect233r1.csv @@ -1 +1 @@ -00e9,004a,0000,0000,000000000000000000000000000000000000000000000000000000000001,0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,2
\ No newline at end of file +0x00e9,0x004a,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000001,0x0066647ede6c332c7f8c0923bb58213b333b20e9ce4281fe115f7d8f90ad,0x00fac9dfcbac8313bb2139f1bb755fef65bc391f8b36f8f8eb7371fd558b,0x01006a08a41903350678e58528bebf8a0beff867a7ca36716f7e01f81052,0x01000000000000000000000000000013e974e72f8a6922031d2603cfe0d7,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect239k1.csv b/src/cz/crcs/ectester/data/secg/sect239k1.csv index 187316f..8b2e58a 100644 --- a/src/cz/crcs/ectester/data/secg/sect239k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect239k1.csv @@ -1 +1 @@ -00ef,009e,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc,76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca,2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5,4
\ No newline at end of file +0x00ef,0x009e,0x0000,0x0000,0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001,0x29a0b6a887a983e9730988a68727a8b2d126c44cc2cc7b2a6555193035dc,0x76310804f12e549bdb011c103089e73510acb275fc312a5dc6b76553f0ca,0x2000000000000000000000000000005a79fec67cb6e91f1c1da800e478a5,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect283k1.csv b/src/cz/crcs/ectester/data/secg/sect283k1.csv index fde7306..9a3a8f6 100644 --- a/src/cz/crcs/ectester/data/secg/sect283k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect283k1.csv @@ -1 +1 @@ -011b,000c,0007,0005,000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000001,0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,4 +0x011b,0x000c,0x0007,0x0005,0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001,0x0503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836,0x01ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259,0x01ffffffffffffffffffffffffffffffffffe9ae2ed07577265dff7f94451e061e163c61,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect283r1.csv b/src/cz/crcs/ectester/data/secg/sect283r1.csv index ff75b55..68c17f6 100644 --- a/src/cz/crcs/ectester/data/secg/sect283r1.csv +++ b/src/cz/crcs/ectester/data/secg/sect283r1.csv @@ -1 +1 @@ -011b,000c,0007,0005,000000000000000000000000000000000000000000000000000000000000000000000001,027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,2
\ No newline at end of file +0x011b,0x000c,0x0007,0x0005,0x000000000000000000000000000000000000000000000000000000000000000000000001,0x027b680ac8b8596da5a4af8a19a0303fca97fd7645309fa2a581485af6263e313b79a2f5,0x05f939258db7dd90e1934f8c70b0dfec2eed25b8557eac9c80e2e198f8cdbecd86b12053,0x03676854fe24141cb98fe6d4b20d02b4516ff702350eddb0826779c813f0df45be8112f4,0x03ffffffffffffffffffffffffffffffffffef90399660fc938a90165b042a7cefadb307,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect409k1.csv b/src/cz/crcs/ectester/data/secg/sect409k1.csv index 4c88afb..e39e076 100644 --- a/src/cz/crcs/ectester/data/secg/sect409k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect409k1.csv @@ -1 +1 @@ -0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,4
\ No newline at end of file +0x0199,0x0057,0x0000,0x0000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x0060f05f658f49c1ad3ab1890f7184210efd0987e307c84c27accfb8f9f67cc2c460189eb5aaaa62ee222eb1b35540cfe9023746,0x01e369050b7c4e42acba1dacbf04299c3460782f918ea427e6325165e9ea10e3da5f6c42e9c55215aa9ca27a5863ec48d8e0286b,0x7ffffffffffffffffffffffffffffffffffffffffffffffffffe5f83b2d4ea20400ec4557d5ed3e3e7ca5b4b5c83b8e01e5fcf,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect409r1.csv b/src/cz/crcs/ectester/data/secg/sect409r1.csv index b3d72d6..727fb25 100644 --- a/src/cz/crcs/ectester/data/secg/sect409r1.csv +++ b/src/cz/crcs/ectester/data/secg/sect409r1.csv @@ -1 +1 @@ -0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,2
\ No newline at end of file +0x0199,0x0057,0x0000,0x0000,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x0021a5c2c8ee9feb5c4b9a753b7b476b7fd6422ef1f3dd674761fa99d6ac27c8a9a197b272822f6cd57a55aa4f50ae317b13545f,0x015d4860d088ddb3496b0c6064756260441cde4af1771d4db01ffe5b34e59703dc255a868a1180515603aeab60794e54bb7996a7,0x0061b1cfab6be5f32bbfa78324ed106a7636b9c5a7bd198d0158aa4f5488d08f38514f1fdf4b4f40d2181b3681c364ba0273c706,0x010000000000000000000000000000000000000000000000000001e2aad6a612f33307be5fa47c3c9e052f838164cd37d9a21173,0x2 diff --git a/src/cz/crcs/ectester/data/secg/sect571k1.csv b/src/cz/crcs/ectester/data/secg/sect571k1.csv index 72488e5..0c94778 100644 --- a/src/cz/crcs/ectester/data/secg/sect571k1.csv +++ b/src/cz/crcs/ectester/data/secg/sect571k1.csv @@ -1 +1 @@ -023b,000a,0005,0002,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,4
\ No newline at end of file +0x023b,0x000a,0x0005,0x0002,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x026eb7a859923fbc82189631f8103fe4ac9ca2970012d5d46024804801841ca44370958493b205e647da304db4ceb08cbbd1ba39494776fb988b47174dca88c7e2945283a01c8972,0x0349dc807f4fbf374f4aeade3bca95314dd58cec9f307a54ffc61efc006d8a2c9d4979c0ac44aea74fbebbb9f772aedcb620b01a7ba7af1b320430c8591984f601cd4c143ef1c7a3,0x020000000000000000000000000000000000000000000000000000000000000000000000131850e1f19a63e4b391a8db917f4138b630d84be5d639381e91deb45cfe778f637c1001,0x4 diff --git a/src/cz/crcs/ectester/data/secg/sect571r1.csv b/src/cz/crcs/ectester/data/secg/sect571r1.csv index 4bba9a0..739cbb0 100644 --- a/src/cz/crcs/ectester/data/secg/sect571r1.csv +++ b/src/cz/crcs/ectester/data/secg/sect571r1.csv @@ -1 +1 @@ -023b,000a,0005,0002,000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,2
\ No newline at end of file +0x023b,0x000a,0x0005,0x0002,0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0x02f40e7e2221f295de297117b7f3d62f5c6a97ffcb8ceff1cd6ba8ce4a9a18ad84ffabbd8efa59332be7ad6756a66e294afd185a78ff12aa520e4de739baca0c7ffeff7f2955727a,0x0303001d34b856296c16c0d40d3cd7750a93d1d2955fa80aa5f40fc8db7b2abdbde53950f4c0d293cdd711a35b67fb1499ae60038614f1394abfa3b4c850d927e1e7769c8eec2d19,0x037bf27342da639b6dccfffeb73d69d78c6c27a6009cbbca1980f8533921e8a684423e43bab08a576291af8f461bb2a8b3531d2f0485c19b16e2f1516e23dd3c1a4827af1b8ac15b,0x03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe661ce18ff55987308059b186823851ec7dd9ca1161de93d5174d66e8382e9bb2fe84e47,0x2 diff --git a/src/cz/crcs/ectester/data/twist/keys.xml b/src/cz/crcs/ectester/data/twist/keys.xml new file mode 100644 index 0000000..1acbc31 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/keys.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE keys [ + <!ENTITY k163 SYSTEM "twist/nist/k163.xml"> + <!ENTITY k233 SYSTEM "twist/nist/k233.xml"> + <!ENTITY k283 SYSTEM "twist/nist/k283.xml"> + <!ENTITY b163 SYSTEM "twist/nist/b163.xml"> + <!ENTITY b233 SYSTEM "twist/nist/b233.xml"> + <!ENTITY b283 SYSTEM "twist/nist/b283.xml"> + + <!ENTITY secp112r1 SYSTEM "twist/secg/secp112r1.xml"> + <!ENTITY secp112r2 SYSTEM "twist/secg/secp112r2.xml"> + <!ENTITY secp128r1 SYSTEM "twist/secg/secp128r1.xml"> + <!ENTITY secp128r2 SYSTEM "twist/secg/secp128r2.xml"> + <!ENTITY secp160k1 SYSTEM "twist/secg/secp160k1.xml"> + <!ENTITY secp160r1 SYSTEM "twist/secg/secp160r1.xml"> + <!ENTITY secp160r2 SYSTEM "twist/secg/secp160r2.xml"> + <!ENTITY secp192k1 SYSTEM "twist/secg/secp192k1.xml"> + <!ENTITY secp192r1 SYSTEM "twist/secg/secp192r1.xml"> + <!ENTITY secp224r1 SYSTEM "twist/secg/secp224r1.xml"> + <!ENTITY secp256k1 SYSTEM "twist/secg/secp256k1.xml"> + <!ENTITY secp256r1 SYSTEM "twist/secg/secp256r1.xml"> + <!ENTITY secp384r1 SYSTEM "twist/secg/secp384r1.xml"> + <!ENTITY secp521r1 SYSTEM "twist/secg/secp521r1.xml"> + ]> +<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../schema.xsd" + category="twist" + desc=""> + &k163; + &k233; + &k283; + &b163; + &b233; + &b283; + + &secp112r1; + &secp112r2; + &secp128r1; + &secp128r2; + &secp160k1; + &secp160r1; + &secp160r2; + &secp192k1; + &secp192r1; + &secp224r1; + &secp256k1; + &secp256r1; + &secp384r1; + &secp521r1; +</keys>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/twist/nist/b163.xml b/src/cz/crcs/ectester/data/twist/nist/b163.xml new file mode 100644 index 0000000..03690ac --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/b163.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>b163/0</id> + <inline>0x000000000000000000000000000000000000000000,0x02c25b85badf8927593d21c366da89c03969f34da5</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>b163/1</id> + <inline>0x03a98eb9fc1007f0a2b0e8de7da23cc6a7f7dd76b1,0x019971752926a2aca5407bffbf2a73f3f884b97127</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0x1f</desc> +</pubkey> +<pubkey> + <id>b163/2</id> + <inline>0x023ae22e69bac70ca24078fdf63753eaf6cb89e857,0x03674a33443dc657c24685eb761ab7efbb63a8adbc</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0x38b</desc> +</pubkey> +<pubkey> + <id>b163/3</id> + <inline>0x04feb095cf083a783cac4107305889efa9f401cc27,0x0403abb00aa4712e4b9120391d59745e9fbad39db3</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0x1208485</desc> +</pubkey> +<pubkey> + <id>b163/4</id> + <inline>0x00a72a640e05acc0e6c6956ab5be24240b92623add,0x031dfc8af709b3db0a05126f17a7b4d703de503475</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0xb78fc77</desc> +</pubkey> +<pubkey> + <id>b163/5</id> + <inline>0x031b5fc734d73023a06e4fe1b7921811221c6d1b2a,0x05432357b4a42a7b8f51b04dfab95a5ecf03547500</inline> + <curve>nist/B-163</curve> + <desc>twist order = 0x5c4bf9b1205a07afbe718429</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/b233.xml b/src/cz/crcs/ectester/data/twist/nist/b233.xml new file mode 100644 index 0000000..7a0b579 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/b233.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>b233/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000,0x0187f85627b97874e747ee31e06d71caaeea52f21253e5f946d061da9138</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>b233/1</id> + <inline>0x01143eef5ed49cf4b4c552259589988a019e98418c012194a255e9186870,0x01f8070b0ef657563e5d584ce23fc58ef70265d4178d78717c6acebb8c78</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>b233/2</id> + <inline>0x01c8185b4f7d07a7eca7deb9f2adcd3c9402461f8679cbc9618ad1d82be3,0x002d17d4fa7eafbf4f6238b94ddc95f6a56384a4028f50e7de1838c21c8c</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x11b</desc> +</pubkey> +<pubkey> + <id>b233/3</id> + <inline>0x01af53fdcb81b561803cb01ba4d384fa3ef7633b1c0dfb35f0e437ffc201,0x012a092d0b600cc59c2234ae65261513eee7a085428b2b42e96253b1143e</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x21d</desc> +</pubkey> +<pubkey> + <id>b233/4</id> + <inline>0x01f4b2e29d7a3796e3aa4a6b3ff40805d322292acefd80149ff954d75e04,0x00df2f3258674f799c4dcc8cef118abb4c00abf0c1f10144b47af7a6f41b</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x22dba0b9</desc> +</pubkey> +<pubkey> + <id>b233/5</id> + <inline>0x01b6b9ce48a1428cb554a76a3f659d8b443ebee6b5619c88100bf3f83bb1,0x00dcafc85dfc3758e99736abe5ed2c4f03cbed5a3b478c9e233b976f7258</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x2a7504c0fda95a2311</desc> +</pubkey> +<pubkey> + <id>b233/6</id> + <inline>0x015cc90c0fdc2fc5fefddf1e9890627f87250b74fbaacd77feb761085d59,0x00059ccb49d156720dd3bcd75438225df9f9e84e7ffc0fc0dda02a647613</inline> + <curve>nist/B-233</curve> + <desc>twist order = 0x1e53fa33649df4ef97d6b29ded5a7</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/b283.xml b/src/cz/crcs/ectester/data/twist/nist/b283.xml new file mode 100644 index 0000000..7f57585 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/b283.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>b283/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x072bcc9c5792b1ebe81983089fb6f835a2fd220a304424ca17c082ae17442aede9b9b3f6</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>b283/1</id> + <inline>0x0297e6d1f2b857a79f5dc85c2f1259d5d801c61a4d0a4312a04f65f09a887a7b93cf7ae1,0x051963c38ac61f05fef93707abcfbda7bc0f39eacddb2bdd3077f19c0e65c8be66ecb30e</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>b283/2</id> + <inline>0x022b522e9e120300e74563dee496f8feb64209b858abd5da50f31c92ae4a1eee751c92d6,0x012647d0d771016622e899c2a54afad773907e42e15d45e1db3e4fb0ae6a6df2934dba63</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x13</desc> +</pubkey> +<pubkey> + <id>b283/3</id> + <inline>0x02597a5336d18d9effde2820bed7352dccc8824abc81cde80914ea3cd072da55e9f91368,0x04a6d2c92a1ee699cda25dafa88191ef34218e9ea5c996d37e9ce507c318e7649b3b02d9</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x1623ab619</desc> +</pubkey> +<pubkey> + <id>b283/4</id> + <inline>0x01b011689cef74d9b2be4e8fb548eeabe31a678f560fc7b893c330b3939da9451a0cff78,0x022fd9ba4762f742a18e299f035a837b0525d7030e6b061eaa9242237d0767e7c28b608d</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x2a4aa67aaaf5413fb</desc> +</pubkey> +<pubkey> + <id>b283/5</id> + <inline>0x06ac85dce72aa795b5b90d43849dec9d4ee0ffc4d41f87fe8d48de2ac3cf84dfc5c20263,0x008e5147dba15ff3cb287457b3f41d32ca6c074df014f85033368d982c1670907d6afa05</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x25a8cdb1f2e470f3ac1ba7</desc> +</pubkey> +<pubkey> + <id>b283/6</id> + <inline>0x0132803a996ebd53ffa3553fc994b583cdb9514e4476c79336acf72f82ac36add519e655,0x004d30604436960af06b2eab63027ca8f59ca105f505afcd3413e1e72f5fb9c0f29d3a20</inline> + <curve>nist/B-283</curve> + <desc>twist order = 0x606749a9c147da03ad3f37</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/k163.xml b/src/cz/crcs/ectester/data/twist/nist/k163.xml new file mode 100644 index 0000000..31040c0 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/k163.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>k163/0</id> + <inline>0x000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000001</inline> + <curve>nist/K-163</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>k163/1</id> + <inline>0x04410857858628f16bd3ef77fce6732525d6d75f6c,0x00c51e38c5eb613ff4c8b594d754a218f30e8b1c39</inline> + <curve>nist/K-163</curve> + <desc>twist order = 0x28d</desc> +</pubkey> +<pubkey> + <id>k163/2</id> + <inline>0x004c291913c2e75103b38481fbda3830850ee4c026,0x0403ff8ccadf20f12e10e40b8eed4872d4c128aaa2</inline> + <curve>nist/K-163</curve> + <desc>twist order = 0x1979</desc> +</pubkey> +<pubkey> + <id>k163/3</id> + <inline>0x03868f9f75e8d0056c6e1aabed4a3df1437a56b386,0x07473bb4e85044c95af468d5374da860c4e563159c</inline> + <curve>nist/K-163</curve> + <desc>twist order = 0x7926bec180108d</desc> +</pubkey> +<pubkey> + <id>k163/4</id> + <inline>0x0162deb07d5848fc45fd580549a6f17fecea1b7497,0x0297440c5cfd9e8fe781004db92f9f106b9d33235f</inline> + <curve>nist/K-163</curve> + <desc>twist order = 0x10a6989de57d15c65ba229</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/k233.xml b/src/cz/crcs/ectester/data/twist/nist/k233.xml new file mode 100644 index 0000000..6354ff9 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/k233.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>k233/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>k233/1</id> + <inline>0x01f5c35c89f8294442218a24a7e62ce3dac66c3ee5e9d2b70aaf51f520b2,0x001328eb45743dd96c4deaaa299b5394abfec9852e73a1e051a745fa95d8</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0x1686d</desc> +</pubkey> +<pubkey> + <id>k233/2</id> + <inline>0x00959e63a797bf3b2ea48d328ea3a9985da6bc95f296d1fc5e8cf17c257c,0x0070034f2e503a97be8766dd6db086870eea2e3fcb02260e9fcc0df8704c</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0x6d8a417</desc> +</pubkey> +<pubkey> + <id>k233/3</id> + <inline>0x00103cf39b9ffa6da7ef9f19f601daf698148663f6e0ae3b4ae2dca53782,0x013c1241644b61fb8c811287c2277c863eb0c31287e30d57d99169b1f509</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0x7c02977</desc> +</pubkey> +<pubkey> + <id>k233/4</id> + <inline>0x003d84c97077988af52d6d825080c0c79276fc168e092260d67b5d4ca3a3,0x01d3fa5b63a25a8f08828117edb78a1ab31724ecfc74d4fc2c4b7ea00703</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0x46403a035013f70d</desc> +</pubkey> +<pubkey> + <id>k233/5</id> + <inline>0x01a053f3903f7b9e7e5c8784b01e43fd427b7264781b1e6c7a8755065a38,0x01ed5e24cd66d3d42b4a869aee65bff9506a8cdbc9f3c3c86543ba14db12</inline> + <curve>nist/K-233</curve> + <desc>twist order = 0xc7cb3894752e561e6abf871db</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/k283.xml b/src/cz/crcs/ectester/data/twist/nist/k283.xml new file mode 100644 index 0000000..48a2dd9 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/k283.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>k283/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001</inline> + <curve>nist/K-283</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>k283/1</id> + <inline>0x02707778aaa47f7a075be036522a6c2998ce118bf7e6314f342ba399dbc3572750791e4d,0x0568810a78107353690d1429cb7f4f408650cbf112d096907f563971baafad1b36436ec2</inline> + <curve>nist/K-283</curve> + <desc>twist order = 0x400000000000000000000000000000000002ca3a25f1511b3440100d775c3f3c3d3873f</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/p192.xml b/src/cz/crcs/ectester/data/twist/nist/p192.xml new file mode 100644 index 0000000..d1fdf49 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/p192.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>p192/0</id> + <inline>0x489ba2a146ac0e7bb9f008fb780005e48d3588893c7ebca9,0x7caac0b203223010fb59940946a12e35d227fcb3ee6c9afc</inline> + <curve>nist/P-192</curve> + <desc>twist order = 0x17</desc> +</pubkey> +<pubkey> + <id>p192/1</id> + <inline>0xfaebaecd2737a6c22b5023d236ad48ab9acacb2cac075379,0x43810e9a10dabc2f835af837ac83fc4f0225773f3a84103f</inline> + <curve>nist/P-192</curve> + <desc>twist order = 0x231acce82af76d32ca5d526f</desc> +</pubkey> +<pubkey> + <id>p192/2</id> + <inline>0x7af6e161dcb8cd7852d5102ab42974af5179706d4616cce0,0xa3177747f0de49227575d2afc449187ab546e9ab827fcac9</inline> + <curve>nist/P-192</curve> + <desc>twist order = 0x512b1bfde874086edba50007</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/p224.xml b/src/cz/crcs/ectester/data/twist/nist/p224.xml new file mode 100644 index 0000000..3ae34ff --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/p224.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>p224/0</id> + <inline>0x90427f4a141f94c26f98d40060292350fcace2356961ef27dda08d7b,0x58877d4992c377c33459aa0caeb0526881326f201beb519fc11aadc8</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>p224/1</id> + <inline>0x7f87c1db4213f1032c251a514e324f4360390476e0f7cd025547df58,0x2498f43e46af6fa0ad6480cfd61fb40caa78e349db0766a8760ff021</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0xb</desc> +</pubkey> +<pubkey> + <id>p224/2</id> + <inline>0x2a2d61174fd561e9da2f279b96f7a69ae50a78d87f09674f465c9184,0xc9c7232ca8a50587181d8c96204c1eec6e976bcbd58e3c7181dbb2a7</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0x2f</desc> +</pubkey> +<pubkey> + <id>p224/3</id> + <inline>0x15da8f68bfe51bc75f0cd892f7400c3d5ce5a9c6da126171527767cc,0x0cee3612475887d31963b62c69580191d1158df3f0c0305765175c9c</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0x2e0273</desc> +</pubkey> +<pubkey> + <id>p224/4</id> + <inline>0xbd813fcdea2281a452733516e4e2625fac96573c41f3b37c56d0d1d7,0x351de92e6b06928fec37ee0ffd03606fecc5022edc1a72453c433ef4</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0x268160f</desc> +</pubkey> +<pubkey> + <id>p224/5</id> + <inline>0x2a379d972d016116067b5bf2c23937b6182b4dc6bf8aa0625eb58b9f,0xb9ec1e372728d3334a762e5d64faca1e0cd47f46c3e5402ff14cb140</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0xf3bac7aa52cf</desc> +</pubkey> +<pubkey> + <id>p224/6</id> + <inline>0xc5e229bfc9f4e0992ecf51a3c354e6aac1a4673056bee9a673beae5a,0x73a2e7d530b13c281d460ea2d2c3bddb49a8eb3446b9308ec64d5a70</inline> + <curve>nist/P-224</curve> + <desc>twist order = 0x22340ff0f7eba57b33ac73e28a14d1</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/p256.xml b/src/cz/crcs/ectester/data/twist/nist/p256.xml new file mode 100644 index 0000000..2e1c55e --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/p256.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>p256/0</id> + <inline>0x92787586fc8a5d065a2a754e229a66ea3c845c8d5f7120792ee3aacee88ca01c,0xee95a42047d9eae3bb007aa7aed3a87ee6986df813f6c76d8f19866a1b1f9c20</inline> + <curve>nist/P-256</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>p256/1</id> + <inline>0x40d27c77cf9fb36e49a850b1ae7357c9ab3f1d917d52ba3edb648bd33354d3da,0xd30662382d8440919f4decbc58c6d9ca8745d39cdd71c26063fd2fa8bcbb69f7</inline> + <curve>nist/P-256</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>p256/2</id> + <inline>0x33961ae81d08958d1dbc42bdadb05e7cb7bdda383b1c49e18c3a2f5908c833a2,0xc4a96d4f905a1d7e32d4c82d6e79f1ef7047d09bf1d1518be2c65d13815306fe</inline> + <curve>nist/P-256</curve> + <desc>twist order = 0xd</desc> +</pubkey> +<pubkey> + <id>p256/3</id> + <inline>0x21fa3bf4b7d23dea73a1751d3b02dd8724a2a5a0ae9b28fdd98b8ef18bb610f5,0x7d933ab51ac8bc7e5d3c5a44d9875c64a080eba393c6492e4e5ce2367f133dd1</inline> + <curve>nist/P-256</curve> + <desc>twist order = 0xb3</desc> +</pubkey> +<pubkey> + <id>p256/4</id> + <inline>0x3819da45c7b025be543fd40ec49b2613891c12f2ae2daf014396c70270eff92c,0xbec84d62254dbc67864ced51966d4f419ad5b1ec9ee1d72cce291a8a034518da</inline> + <curve>nist/P-256</curve> + <desc>twist order = 0x1e0a75640070a738557cc30f68bd56eaea65c94f98411d17ac4e16ece1a47</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/p384.xml b/src/cz/crcs/ectester/data/twist/nist/p384.xml new file mode 100644 index 0000000..8e0d2b6 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/p384.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>p384/0</id> + <inline>0x77e3431a4d6b9d63985798eb41188f9af7eb6c0f38745d360bf82b5c2c162cb8393adf2dbc4d5531c49322d9c7b4c9cd,0x2b38ea158d3c980e9b3618cfe42599dd9d78e630ac83c66673949121ca6c8997fbf5e08c060076f3fa60d6dec8ac8624</inline> + <curve>nist/P-384</curve> + <desc>twist order = 0x1000000000000000000000000000000000000000000000000389cb27e0bc8d21ea7e5f24bb74f58851313e697333ad68d</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/nist/p521.xml b/src/cz/crcs/ectester/data/twist/nist/p521.xml new file mode 100644 index 0000000..1564c80 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/nist/p521.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>p521/0</id> + <inline>0x01a0c6f0e5b2c6948218fb8d1e913d750ace27674e59ec0a45f8f5883518c65c401af5a2275b7c2c74e717f5b64c48056f1440de1d48ef0825086f12db4f862e4467,0x00c93c77edf1cac8bab534a28c49446113a22833e05658b69f73658d7867b43c94f58d52e17b726e3f6d0b5847d91980509250210c4e1c73eeec72e185529c1450b0</inline> + <curve>nist/P-521</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>p521/1</id> + <inline>0x00e84fb16849133c2e4c24e7efc4df752ed9f01204aa692342bc619a8a9ccdd1b058996f3896790d0ee1b7c480cb117cc0b9272c116c6f544b99dca9d441976c69c0,0x00e6d2c8adb57c81db0bead3d225ee900c81e049d0e36bf20bf421f5620449b1638f2b1998f3e1ffbee369a74bc4833d01f45b46388755ba16abf67c5f7f53ac9110</inline> + <curve>nist/P-521</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>p521/2</id> + <inline>0x0161cb810a7d7f9092d518ed483208f202cf5a984e98ff50f94b13e04bf94be942c91a007cff215d55bf124912b8620312bc94e813d7956e3821b45da439f0b0e8e7,0x005194f315423bcacf38ea558ff344daedf9a51a81b0a9ef27f1d687c8d1b6952b60b6486fc2c3d394749fb00e4921a5cfced55c1fe821e8b80279f6cec89ba1ac1f</inline> + <curve>nist/P-521</curve> + <desc>twist order = 0x4277ffb</desc> +</pubkey> +<pubkey> + <id>p521/3</id> + <inline>0x01c133c394ad86829a9252e4d5e266c3d2830eb9b899e2cb16b815a5c7050c3bc53c415296339d33427087bdef04c0ae2d8f7d63d4a41176bd76d3c07cbd1ecfd1ee,0x01fee0c7535c40e01f2c12ee2a6ae1e54cafc147c3b491602da1f278b46c6ae3c04705b3bb3c72af70aaf3d4c684411ede8694d7a21b3734ce43ecc2b4a1ee2efee7</inline> + <curve>nist/P-521</curve> + <desc>twist order = 0x25e6d2cd</desc> +</pubkey> +<pubkey> + <id>p521/4</id> + <inline>0x01232e18498e6cafe2572ec0b511376cf0d4844ec3b94472fb53346d7d9611726065cc922b3d2132117c99bce0ff8bc7f51bb30c6909a53b7c8a88e81807c31a1999,0x0112ada376c25bdc96440e0e2bf936377b287e885a08e6e1b5aa54f9b269cce4ed6ca6e6e44bd6d8e092e4864b278951648e897682096488e2a36036e989b1af7b24</inline> + <curve>nist/P-521</curve> + <desc>twist order = 0x17c8b8fa594c0fc63a5c0043ab498c1762d92f18fdfe2fea8f074695615d886d81bf930a0ac77d01bf9dd8c1a1ae121dab4e860c5dc18e265de3</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml new file mode 100644 index 0000000..bea215a --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp112r1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp112r1/0</id> + <inline>0x873a74a2da300cab1c8761d8f67b,0x46e03cbcc61d00aa9fe5a8077494</inline> + <curve>secg/secp112r1</curve> + <desc>twist order = 0x8a5</desc> +</pubkey> +<pubkey> + <id>secp112r1/1</id> + <inline>0x218f000fe41ffd98b55fc9b756c7,0x62a1bd48c034935e4367f392fbaa</inline> + <curve>secg/secp112r1</curve> + <desc>twist order = 0x1835</desc> +</pubkey> +<pubkey> + <id>secp112r1/2</id> + <inline>0xadf84193c633787f17ff7c789296,0x19b5613c0ee78be5954a104fad0b</inline> + <curve>secg/secp112r1</curve> + <desc>twist order = 0x11167</desc> +</pubkey> +<pubkey> + <id>secp112r1/3</id> + <inline>0x4b3b746903493367fd076f6e73bb,0x030545f11165bac7cbf381c48879</inline> + <curve>secg/secp112r1</curve> + <desc>twist order = 0x44015</desc> +</pubkey> +<pubkey> + <id>secp112r1/4</id> + <inline>0x51132c4c92342942c8027b71890e,0x43beab4961a59cf10d1b30531f5a</inline> + <curve>secg/secp112r1</curve> + <desc>twist order = 0x3b273570eb27b9</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml new file mode 100644 index 0000000..f1d0fee --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp112r2.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp112r2/0</id> + <inline>0x48edb7418c08127bdd779ac7e5f7,0x0000000000000000000000000000</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>secp112r2/1</id> + <inline>0x4a1cb7539a8401269dbff6acf404,0xc21acfb8b7b32712febd4e61633f</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0x17</desc> +</pubkey> +<pubkey> + <id>secp112r2/2</id> + <inline>0xc8faf44b8d4853737ccf82806b75,0xcce630f92e9c95bf26e0f4a070fe</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0xd3</desc> +</pubkey> +<pubkey> + <id>secp112r2/3</id> + <inline>0x14590ab5b3753e82b3d0b57ce706,0x233b3204fdedbaf31c5dceb86285</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0x35e63</desc> +</pubkey> +<pubkey> + <id>secp112r2/4</id> + <inline>0x8ae76a4a40729732096d3c5207e5,0x629a89669d42e3871f1820cb97a5</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0x73c27</desc> +</pubkey> +<pubkey> + <id>secp112r2/5</id> + <inline>0xa86117a59016f257c4397d388a65,0x67ead9fb333257074be723a5f46b</inline> + <curve>secg/secp112r2</curve> + <desc>twist order = 0x1e6727ac61bb6633</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml new file mode 100644 index 0000000..e9bf07b --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp128r1.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp128r1/0</id> + <inline>0x7ad6f2458364dc3bc253564a0f55f047,0x24ca1c658f7572c87528e6b9db2b6a76</inline> + <curve>secg/secp128r1</curve> + <desc>twist order = 0x29</desc> +</pubkey> +<pubkey> + <id>secp128r1/1</id> + <inline>0xd831601d766cc45f62eb7cf7937ee642,0xf9e0a4e6fec14da13d27d248a190d230</inline> + <curve>secg/secp128r1</curve> + <desc>twist order = 0xc0034f</desc> +</pubkey> +<pubkey> + <id>secp128r1/2</id> + <inline>0x8867a9a49ff8c47c6d10d32783cd69b0,0xc2d9ae698d287ecdadce470328485477</inline> + <curve>secg/secp128r1</curve> + <desc>twist order = 0x56a1f8d</desc> +</pubkey> +<pubkey> + <id>secp128r1/3</id> + <inline>0xeb842468d2d732452a3044e8558fbf60,0x35022342302a1fc4f2bbd4ddca43892d</inline> + <curve>secg/secp128r1</curve> + <desc>twist order = 0x18996f4e0882951e9d1</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml new file mode 100644 index 0000000..fdd9028 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp128r2.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp128r2/0</id> + <inline>0x64a89794638df343c17a48c6e926de14,0x00000000000000000000000000000000</inline> + <curve>secg/secp128r2</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>secp128r2/1</id> + <inline>0xd2d9721cd218b8d0a9dc8101e053a834,0x8111cc843d9d6090ec34cfe2ea360eb6</inline> + <curve>secg/secp128r2</curve> + <desc>twist order = 0x3cb</desc> +</pubkey> +<pubkey> + <id>secp128r2/2</id> + <inline>0x88ba57155e8f2050626d2a02a34b4efd,0x8f97d0b54e869e605b7fb7ae97819d1d</inline> + <curve>secg/secp128r2</curve> + <desc>twist order = 0x10df9252a726c184278bf55634b577</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml new file mode 100644 index 0000000..8d1cc53 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp160k1.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp160k1/0</id> + <inline>0x0000000000000000000000000000000000000000,0xc1fd26fdc8681a7ba7f699610a62c328cde65ba0</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>secp160k1/1</id> + <inline>0x261f4b383910221b95b8064ffd1667c136652295,0x84bb1bf6e9d6beebcb0b3525e99df9124bb14e40</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>secp160k1/2</id> + <inline>0x5ad5c6cd4067ee20b4984eb2132c9742d15d15e2,0x2de572e579ea7b539f0234a6a2f875966dc4b249</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0xd</desc> +</pubkey> +<pubkey> + <id>secp160k1/3</id> + <inline>0x12a1d4d6314698fa80a153de7849173ba3840012,0x34dec5c8c38ec56f7cdf8f1e44f54606a49e5213</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0x5fc5</desc> +</pubkey> +<pubkey> + <id>secp160k1/4</id> + <inline>0x836557a9441a4591e3b35c4b86c4b4a964887b4c,0xd5491a1f264c3f115223731855ce2ed837c15bf0</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0x25807</desc> +</pubkey> +<pubkey> + <id>secp160k1/5</id> + <inline>0x1c959049e8e689783335f711f7a928d4200890c2,0xd0846962412aa16de740be64dadca13bb0c50758</inline> + <curve>secg/secp160k1</curve> + <desc>twist order = 0x271c756a728aed5671cf8cb4b33771</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml new file mode 100644 index 0000000..dece980 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp160r1.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp160r1/0</id> + <inline>0xdfe49462b5a10a4cf944801e93a444d4951c54f4,0x9ef1de44c53a4814eb31f616175922327cd2e112</inline> + <curve>secg/secp160r1</curve> + <desc>twist order = 0x20b</desc> +</pubkey> +<pubkey> + <id>secp160r1/1</id> + <inline>0x5cf0cd60ea345232884895f01b4e1760927f5d94,0x0bb00af378e1f0f69589a2da5b8fd6b2669b5402</inline> + <curve>secg/secp160r1</curve> + <desc>twist order = 0x2c29d39e9</desc> +</pubkey> +<pubkey> + <id>secp160r1/2</id> + <inline>0xeb8957704438337bbddb0d6ce1e28b635d5db134,0x631bad39571cfea33639a76c774e46fecaadc9b1</inline> + <curve>secg/secp160r1</curve> + <desc>twist order = 0x2d65dd7cc36e3baf234efd9dea9ae3</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml b/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml new file mode 100644 index 0000000..bdb8a03 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp160r2.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp160r2/0</id> + <inline>0x33581bd94e113c8b34fec9c60b9031675b9c8b68,0x987cd809e044f8ab7f3757bbd06ecc01550f3868</inline> + <curve>secg/secp160r2</curve> + <desc>twist order = 0xa3</desc> +</pubkey> +<pubkey> + <id>secp160r2/1</id> + <inline>0x8318469fc335f235b8d8fc4fbcd61282b9521fb7,0xcf52bc6053b4cea8117431dcb68db2110dd87e63</inline> + <curve>secg/secp160r2</curve> + <desc>twist order = 0x1c9</desc> +</pubkey> +<pubkey> + <id>secp160r2/2</id> + <inline>0x615ace506803fd5f06a323ce45319a3ca5aadcf0,0xbb4f76d2db8189c07a10487fb32b206a38ba2e89</inline> + <curve>secg/secp160r2</curve> + <desc>twist order = 0x355</desc> +</pubkey> +<pubkey> + <id>secp160r2/3</id> + <inline>0x3178dfd1f5c334184521d055a043a2349f35f67e,0x98c2395fd272532476f2c6d5ddb2c9a579b84699</inline> + <curve>secg/secp160r2</curve> + <desc>twist order = 0x78d</desc> +</pubkey> +<pubkey> + <id>secp160r2/4</id> + <inline>0x0e17d26c2ebf81b5e1c695438abe9eb3edd96f6b,0x2502f5d59f731f0cca5b8449fde15b713f82f36c</inline> + <curve>secg/secp160r2</curve> + <desc>twist order = 0x8f3af9a6f25d7b73940da6f6ebd3137</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml new file mode 100644 index 0000000..457a414 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp192k1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp192k1/0</id> + <inline>0x000000000000000000000000000000000000000000000000,0x50f36a853090dc8aaeab4e45e31a9476899ac91c98622974</inline> + <curve>secg/secp192k1</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>secp192k1/1</id> + <inline>0xc1ee9eeacca70968c68149d7ea884f4d2081c7f135a3c0db,0xcd1fcc8fa5650d5b63c2e4e3529845200fe959e2bf7aa743</inline> + <curve>secg/secp192k1</curve> + <desc>twist order = 0x175</desc> +</pubkey> +<pubkey> + <id>secp192k1/2</id> + <inline>0xa5e8d7e243f29335b7f9067cc2a99334e5504dab66de2b61,0xe488e628f21a0d13439c912ad6dd6a4c017deb6d1bd9ac91</inline> + <curve>secg/secp192k1</curve> + <desc>twist order = 0xdc3f</desc> +</pubkey> +<pubkey> + <id>secp192k1/3</id> + <inline>0xc3ad3754b5199729816ba49f459caa03c63e8580f66c03a9,0xce4bc350ed04ecb8634147d9a9cd1cf6d06268fdc6a11fdd</inline> + <curve>secg/secp192k1</curve> + <desc>twist order = 0x24e7164b</desc> +</pubkey> +<pubkey> + <id>secp192k1/4</id> + <inline>0x14fc875f81ce7d409013996fa7d8d75dab7b750f41e7aeee,0xb16e153045429ab589746734c0fb13ad11a81ef95e41cdad</inline> + <curve>secg/secp192k1</curve> + <desc>twist order = 0x1d83dac42196d3629c6baf0247e0157a469</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml new file mode 100644 index 0000000..16ba7db --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp192r1.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp192r1/0</id> + <inline>0x23142b001b0b474409a0d4c8815e7ade529ae9eff7c5b95b,0xa1629eaae43dab352219bf25ff6e12f4936864615eb89078</inline> + <curve>secg/secp192r1</curve> + <desc>twist order = 0x17</desc> +</pubkey> +<pubkey> + <id>secp192r1/1</id> + <inline>0xc0a1f79357e0d708a855fe30e2fc032486e3b26d8fe1a5c0,0x51d01bb8aadd9b41863ece85c2b600a0107f812d4460e9d9</inline> + <curve>secg/secp192r1</curve> + <desc>twist order = 0x231acce82af76d32ca5d526f</desc> +</pubkey> +<pubkey> + <id>secp192r1/2</id> + <inline>0x45cc2ab6dba52cbfd5860d0e61a3decfee82e0b1c64bd094,0xbf8b1707363dc155b16233478b0555b1815a295338522b80</inline> + <curve>secg/secp192r1</curve> + <desc>twist order = 0x512b1bfde874086edba50007</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml new file mode 100644 index 0000000..ee6782e --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp224r1.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp224r1/0</id> + <inline>0x5d60f43a069cfe3a7c365b782bd8ef722e29efed9f8e782d98da9523,0xc790eaae79a6ea2fbe7bcd6c430c54362a834b3a6628008347264d89</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>secp224r1/1</id> + <inline>0xcd1095d23b17e6cfbd1c59476bd60751bb743a42ab8673414cfaf3e7,0x89b8deb522b178eb7a8ad262ce9e99a472797448d598ce64a2116b03</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0xb</desc> +</pubkey> +<pubkey> + <id>secp224r1/2</id> + <inline>0xe442f9e86c386800f2ae5982f3be77c833663e8b673121fed69282f4,0x2a94e1cd72999b32a6b1fc71328b63bb4857f045a4acda509991145b</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0x2f</desc> +</pubkey> +<pubkey> + <id>secp224r1/3</id> + <inline>0x25c4b228af197210904546d9f6dda2385b9a0a0cbe2211af65341cb9,0x3f5c565a48b1b8d05adbc9ca94ade61e0e45cc9e9f1248c963d5784c</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0x2e0273</desc> +</pubkey> +<pubkey> + <id>secp224r1/4</id> + <inline>0x5e7b261f83fa2b59e6bf4c7c9edf8e9c6ad418f4e9b3f9cec09f66d9,0x59033a890a85f95fc514abfa27e01bb010c3699f9430057b7235c1fd</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0x268160f</desc> +</pubkey> +<pubkey> + <id>secp224r1/5</id> + <inline>0x8d9a10823de47bc73a12ae57fe97a34373ae59f16d61a3b82a46f68e,0x622fd6f6069294c902a82d3583d88816675e44fcafa47a0a433990a6</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0xf3bac7aa52cf</desc> +</pubkey> +<pubkey> + <id>secp224r1/6</id> + <inline>0x99bfcc79f6c38a9b3d773506f827eccde507531d2886af8770f69f43,0x0e4e90ae87d71816c2bef3d55f0dfe7b54c16f9aadd8ea3b56e9663b</inline> + <curve>secg/secp224r1</curve> + <desc>twist order = 0x22340ff0f7eba57b33ac73e28a14d1</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml b/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml new file mode 100644 index 0000000..467641e --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp256k1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp256k1/0</id> + <inline>0x1f5f34663a612761136c07de53d91039f82644aa7706e90b37ac2dc5154d79ed,0xb32d76a9b3c7a9fac50c6da11a9953d11b262206cf26f33a9feb20a6bb1bb70c</inline> + <curve>secg/secp256k1</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>secp256k1/1</id> + <inline>0x9537931b68257bb2ef5782a3df24719668c70029522ba296c076996231e5c790,0x236617decf9b2f14223d798de8de3bca791fe36603a312e572048e89609379d4</inline> + <curve>secg/secp256k1</curve> + <desc>twist order = 0xd</desc> +</pubkey> +<pubkey> + <id>secp256k1/2</id> + <inline>0xaa45c03ebb0dd5ef1eb604802b97cef9694d5b9f37b253a475be99927dc28d55,0xb6762cffb2eacc3504b6c2e25908c4b9af12a62450fab97690c137a1102d64d4</inline> + <curve>secg/secp256k1</curve> + <desc>twist order = 0xcf7</desc> +</pubkey> +<pubkey> + <id>secp256k1/3</id> + <inline>0x4c5029ee7f3f340b328d6db4e6195a21a43ddc42152137922e7ed27a2723ff87,0x2309f5db4cb59337fabd8ca6b1b8866fd3a96429c4aec311e315983bf3b6864f</inline> + <curve>secg/secp256k1</curve> + <desc>twist order = 0x586f</desc> +</pubkey> +<pubkey> + <id>secp256k1/4</id> + <inline>0x4234a6acce09563862bc78f46c93dbb9e8ca3579ec58d08f273911178ae88e25,0x5d3e9733e02e6b94f297d8d5905265d1ddfeacb2633f0db3fd255d0177d2de46</inline> + <curve>secg/secp256k1</curve> + <desc>twist order = 0x99ee564ea5d84f508913936a761b0d5d792a426a7779817ae2f5b67</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml new file mode 100644 index 0000000..b385548 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp256r1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp256r1/0</id> + <inline>0xd43dd5ce6c8e557e282bdc3535609e72bc46c1f91c166c63fc298b5a2ef64ea5,0x53cdb347774d9feef822754c289a8a7aab6e4bf5168a5155b0c25016f6ff47ad</inline> + <curve>secg/secp256r1</curve> + <desc>twist order = 0x3</desc> +</pubkey> +<pubkey> + <id>secp256r1/1</id> + <inline>0x44b4e6293d9efcb1b655b7f90b81dabceb5925a258780aa22381292af84e4615,0x39efc0650cd2289cb1d6c2bd2bd7139f4f4c97e43f536c47b7782e5e5b627428</inline> + <curve>secg/secp256r1</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>secp256r1/2</id> + <inline>0x588e38eb7a4adf969daea9e2beabe2616ac8c0a7a52d920f10ed1d2f81986b6e,0x3b728114a2421a73d047338f60a324ee1b25d81f8f207ba762765b45576d009d</inline> + <curve>secg/secp256r1</curve> + <desc>twist order = 0xd</desc> +</pubkey> +<pubkey> + <id>secp256r1/3</id> + <inline>0x0d8e8d6f9b9bec935475145bde3b80b76884b57d136afe327d80e13677a915f5,0x6bc1fc461c4dcec55a6ceadb7950aaffb5621ea428b13e7091b1d7a90642b270</inline> + <curve>secg/secp256r1</curve> + <desc>twist order = 0xb3</desc> +</pubkey> +<pubkey> + <id>secp256r1/4</id> + <inline>0x84cdc23c802dd6ae90ae1257884709fc522206adf114b8f0ea715e0dc77d2bad,0x92a4b98b60c8204cbdf947839663229d2fd36184504ff0e308eaa1761c138d7a</inline> + <curve>secg/secp256r1</curve> + <desc>twist order = 0x1e0a75640070a738557cc30f68bd56eaea65c94f98411d17ac4e16ece1a47</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml new file mode 100644 index 0000000..2ddbe9b --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp384r1.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp384r1/0</id> + <inline>0xe623940e96d6ce70b3a3185b1b49560532daafbc36f8fcc9167500b186682ac19c1bc959c0b9ae6e2f620449358c9367,0x97c91ddd90946df34ee5c540a04175d45a5ebad666439b8384ec64cd95b2f0a438bedfc36ca80a7d7e9a38a7c26925bf</inline> + <curve>secg/secp384r1</curve> + <desc>twist order = 0x1000000000000000000000000000000000000000000000000389cb27e0bc8d21ea7e5f24bb74f58851313e697333ad68d</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml b/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml new file mode 100644 index 0000000..105efa3 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/secp521r1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>secp521r1/0</id> + <inline>0x0099cfe88fe446b8eaeefc4094833b1ab0853c7bc4d906aef04d9f57be2de53e3678551217b736cd26d1b217dcb806c747f17e29bee7490161f86726d59f2129c16b,0x0079651e0bf51bd1bd86a1f520c528705862589c5b78843d523be3e980e93ef3ddf3366175a1567b88d54689e6bfcafee863ad3d93411d54ca3db6ad2ce27eae309d</inline> + <curve>secg/secp521r1</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>secp521r1/1</id> + <inline>0x0140ba8e264bfcbc2dae3e498236fdb502cdbcd053476d148143bb0a38f72d4bb4d0c53b971cd36ba19f0a35cfb6af2f82c1a9bc5978873e0edf753282e11fdfd045,0x0041833aebb70b75c471c35ca5cdbbdfb8c64dd10f2e977e254f081e2566e8010e80d69ff11cf3140561586e917070d2a0443d3f3eba20688f0e48e4132d0eb0a5b4</inline> + <curve>secg/secp521r1</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>secp521r1/2</id> + <inline>0x00925139c9b4c7788add3ec38be6c9799dcd4794f9f3e708bd66130b2d21abc953035a3bd6cbae7fc2cc02b0be12cd0b0fbfe0d190844bb3e346899f6c03908bb73b,0x006a86cb7307e9901bcf819e1cf2deecc0e2a35b0cb06998ec1e354267294a17f872179cad4f80e79ad06fd4200cbf142d18779a8e4633824265a0cae30aacd38418</inline> + <curve>secg/secp521r1</curve> + <desc>twist order = 0x4277ffb</desc> +</pubkey> +<pubkey> + <id>secp521r1/3</id> + <inline>0x013dec992b39d75718ca8ea86f481bec0d4717e18b86f0716e807374317bf4bd93cd036f6969d2d85e19f2b9a375c0c5cc3a46af11048671bb9c8aac21bd8a02bb9d,0x01f629b94eadd014680a318a29a743585e7b8a9a315accccf7dcd8b2f6d012f301eeb2477fb8c822b07f09cc2089c3be07896502cbf1e86f72635718dd2ae3004c65</inline> + <curve>secg/secp521r1</curve> + <desc>twist order = 0x25e6d2cd</desc> +</pubkey> +<pubkey> + <id>secp521r1/4</id> + <inline>0x013189c93b04b69426269fbadbee6379a6752ca1cbbe972ca1f14edbb4fefdc437bd96912266a83fb0482b6a291d74326a1d2b6a170f0cd24896e93323049fea281d,0x01a05a94d5e7481d42d3af74994f6f7bfacd231123cd6abcd31e3e99c571a84d032aeee65aa3fff8cda497aa77900910a897188f87fc4d502162349ec1d2345a307e</inline> + <curve>secg/secp521r1</curve> + <desc>twist order = 0x17c8b8fa594c0fc63a5c0043ab498c1762d92f18fdfe2fea8f074695615d886d81bf930a0ac77d01bf9dd8c1a1ae121dab4e860c5dc18e265de3</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml new file mode 100644 index 0000000..754e8e6 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect163k1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect163k1/0</id> + <inline>0x000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000001</inline> + <curve>secg/sect163k1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect163k1/1</id> + <inline>0x05f78762dcf07272474326134cd9afb8ec82b6b9af,0x05ae3cb5265210c388e0fb9787c7dc7c40ef03acae</inline> + <curve>secg/sect163k1</curve> + <desc>twist order = 0x28d</desc> +</pubkey> +<pubkey> + <id>sect163k1/2</id> + <inline>0x01626b92c13b6eaf8a07353707e3ee25b69d56b403,0x0066a86e6fd8c5fa73245eef10159b5b428efface3</inline> + <curve>secg/sect163k1</curve> + <desc>twist order = 0x1979</desc> +</pubkey> +<pubkey> + <id>sect163k1/3</id> + <inline>0x072da789cdf1e91288880d47aade6d19206a3eef8b,0x006405496db1049f579e035d9047f554152d215933</inline> + <curve>secg/sect163k1</curve> + <desc>twist order = 0x7926bec180108d</desc> +</pubkey> +<pubkey> + <id>sect163k1/4</id> + <inline>0x059f4674675ce9134f7c6095e57f0f2da73b303ab0,0x03cdd4b8e4efa8c96ed4b2b349f6e1b47bc33f145c</inline> + <curve>secg/sect163k1</curve> + <desc>twist order = 0x10a6989de57d15c65ba229</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml new file mode 100644 index 0000000..dd7d798 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect163r1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect163r1/0</id> + <inline>0x000000000000000000000000000000000000000000,0x009917a2556e1856bc7ea9a472cd01bfb889b95835</inline> + <curve>secg/sect163r1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect163r1/1</id> + <inline>0x06deb836183f1f185aa782845b7e30b87aac87cc86,0x02a07ec119c487e132b464ea54e7f2264103fbf6f3</inline> + <curve>secg/sect163r1</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>sect163r1/2</id> + <inline>0x01dbb909b594a1b8db65b2de7cffe586d10ea658c8,0x031e430590c0ca5707f54a0463dbd329ca9088d1f2</inline> + <curve>secg/sect163r1</curve> + <desc>twist order = 0x923</desc> +</pubkey> +<pubkey> + <id>sect163r1/3</id> + <inline>0x029d7e51e1b8552d0fe88a48bcfb1913b4d0adac52,0x073688d2e575b20328f70560be4ba53b575498d23d</inline> + <curve>secg/sect163r1</curve> + <desc>twist order = 0xcd4110cf690bd</desc> +</pubkey> +<pubkey> + <id>sect163r1/4</id> + <inline>0x010175375db66e9ce0060fc3785804ebe2d96b8a3a,0x04d4cc08f4975602d69520023bb0505fe701339146</inline> + <curve>secg/sect163r1</curve> + <desc>twist order = 0x9fc0d375facf703681f32693</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml b/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml new file mode 100644 index 0000000..421887d --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect163r2.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect163r2/0</id> + <inline>0x000000000000000000000000000000000000000000,0x02c25b85badf8927593d21c366da89c03969f34da5</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect163r2/1</id> + <inline>0x0176fb3d1e1035f04de3297dafb0033baeee694e97,0x0602840f8148fc8afc1f695df529e4dd48337243a4</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0x1f</desc> +</pubkey> +<pubkey> + <id>sect163r2/2</id> + <inline>0x017d5799f3c55c7f0941240a0030cd1f6a4077e627,0x02a19d01c1bd140363e68414e8f35a9fdf8a5345ea</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0x38b</desc> +</pubkey> +<pubkey> + <id>sect163r2/3</id> + <inline>0x01aff9f7655201dc4800b811f5c983d4ca9933b947,0x07bdfdfc15dc948a4dc91d8565a69659c6c88bf5f3</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0x1208485</desc> +</pubkey> +<pubkey> + <id>sect163r2/4</id> + <inline>0x0332053427eaa5d8f365c5306fb301be9627647e81,0x0696da25692ba254884fb945caa12fe68c05a0416c</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0xb78fc77</desc> +</pubkey> +<pubkey> + <id>sect163r2/5</id> + <inline>0x02556ec8322e21c3de7444a6fcdfff37629d657018,0x0324ab964dd8012423c2607dd9094393b60c725c10</inline> + <curve>secg/sect163r2</curve> + <desc>twist order = 0x5c4bf9b1205a07afbe718429</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml new file mode 100644 index 0000000..cf8524c --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect233k1.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect233k1/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect233k1/1</id> + <inline>0x014cdc219c9370a243ae5a9456fe5e3a421c7363727f3e4018c497e30705,0x01a88dbabe626a8941b5394278f7de54d63edfa7e70c15a815aa75bc5072</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0x1686d</desc> +</pubkey> +<pubkey> + <id>sect233k1/2</id> + <inline>0x00bba31978663bc010dc6620c8241e44417b1a56212b82d4d63751d234cf,0x01b3cda86c83bb59b8e3f3ba2d025adc35abd11acb19ba561491c34fd9c7</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0x6d8a417</desc> +</pubkey> +<pubkey> + <id>sect233k1/3</id> + <inline>0x01512cc87e6cd2a418857736c96688476b641b9d3a838eb4f9207751e021,0x01dc01ca001b69c64322a5d5c2cf81a9ae0ed04d8d10e8b06ccbcf9ef911</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0x7c02977</desc> +</pubkey> +<pubkey> + <id>sect233k1/4</id> + <inline>0x01c61af41b217ec78ffb3572df845fe33c8efecb2d05f2033c2824784e5b,0x0138f83ba05a3957721d5db5a5bd247ab02a4f6a3e1c2163027116996730</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0x46403a035013f70d</desc> +</pubkey> +<pubkey> + <id>sect233k1/5</id> + <inline>0x00e9f2cc9d6665352aa77575f3f7bd42642c924388b8c741134eeda9ccb7,0x01e74c2549cce5d6587a11dfd625e099f2519691653c80dbe335aa61c789</inline> + <curve>secg/sect233k1</curve> + <desc>twist order = 0xc7cb3894752e561e6abf871db</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml new file mode 100644 index 0000000..45eecf4 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect233r1.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect233r1/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000,0x0187f85627b97874e747ee31e06d71caaeea52f21253e5f946d061da9138</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect233r1/1</id> + <inline>0x00c5f754b03ae354c9cce8386a31436157eaa590a9cfb892dc40d56f66cf,0x01294608d589c250bed15f0e63887c961fa149c68881c1ec242e441ad1a3</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x5</desc> +</pubkey> +<pubkey> + <id>sect233r1/2</id> + <inline>0x0024806b9e973c082da34fadd43d94d6966e16b147450db7ddd6e5a3f4e2,0x0083fb9fa68aba9805c0a747897fd1bf12defaa7d8efee174060ac0ef3b0</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x11b</desc> +</pubkey> +<pubkey> + <id>sect233r1/3</id> + <inline>0x004bde91214e1b76dbe01fe34c68135178639f0453632209fd9da04d22fc,0x0030256812c97f8763815acc7fd00ca87d86cde0517ad2afc92b21c593d7</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x21d</desc> +</pubkey> +<pubkey> + <id>sect233r1/4</id> + <inline>0x00ca85e22408b271206c05630370c75c7c678392eb5ed54903ed3196eb5e,0x00c3e55b408782683364c3ea0191e4aaadc888f95c5d4a0e0e06e979f77c</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x22dba0b9</desc> +</pubkey> +<pubkey> + <id>sect233r1/5</id> + <inline>0x0159c22cd6ea5fe56041b75f3b21594ae94161363576338717d9b393ed85,0x00ec9f09736dbd80af6efd0f16419fd24982f9d5de455414057a6b57ac0c</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x2a7504c0fda95a2311</desc> +</pubkey> +<pubkey> + <id>sect233r1/6</id> + <inline>0x00fe6311a7ee2de94e57f9e632e184a8f9cc21d6a5865a820b6dd62371c3,0x0002dfd2fbdb68965f56f478b7a345950a5ef1e7a7f570962d389efc4612</inline> + <curve>secg/sect233r1</curve> + <desc>twist order = 0x1e53fa33649df4ef97d6b29ded5a7</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml new file mode 100644 index 0000000..bc17d4f --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect239k1.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect239k1/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000001</inline> + <curve>secg/sect239k1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect239k1/1</id> + <inline>0x027dc44bed0f67a40050ce79eea889f65a856864c1ece7ae4b2d05887b3b,0x330b3b1520d30c012146cd13e3af3d32ee02f0eaebacac36611bda4b9483</inline> + <curve>secg/sect239k1</curve> + <desc>twist order = 0x10771acb9</desc> +</pubkey> +<pubkey> + <id>sect239k1/2</id> + <inline>0x2253fa673642a0046615d33a2853062d60e5959144bd608385ad7f4a6686,0x728f3a8f45ff239c5f1ab44cec36278be6312571486cde0a4205a3afb20f</inline> + <curve>secg/sect239k1</curve> + <desc>twist order = 0x3eaaf7f039f</desc> +</pubkey> +<pubkey> + <id>sect239k1/3</id> + <inline>0x38b81ec85fcdcea4a29a8b0326fcf122eee852754476b8490bbb5362efeb,0x2b8e9442ffb0eb8be55636cf7f12bc5402a985e8f7ea89ff0233ddb76a1c</inline> + <curve>secg/sect239k1</curve> + <desc>twist order = 0x1e3607543aabf52e8d8f7</desc> +</pubkey> +<pubkey> + <id>sect239k1/4</id> + <inline>0x5dbc5cbd7a0c046aeabff4b2abb49fb58763ea2c7e4ca9507ed3d54f9af2,0x0a389cf9dc455db54fc3de75a361b408e2cb679cfb2e1fbed312ff09c048</inline> + <curve>secg/sect239k1</curve> + <desc>twist order = 0x868c9487ea27642c47f97</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml b/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml new file mode 100644 index 0000000..65ecb63 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect283k1.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect283k1/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x000000000000000000000000000000000000000000000000000000000000000000000001</inline> + <curve>secg/sect283k1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect283k1/1</id> + <inline>0x01f5a4ad35352d19e37108222909b2a7002516cdf68afb899e9fca4056f77e889d15a7d0,0x04464034359d8bbf2e34f3d0a863d50ea325b804d8882dbf7a36c56d3f782451320799aa</inline> + <curve>secg/sect283k1</curve> + <desc>twist order = 0x400000000000000000000000000000000002ca3a25f1511b3440100d775c3f3c3d3873f</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml b/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml new file mode 100644 index 0000000..e2913a0 --- /dev/null +++ b/src/cz/crcs/ectester/data/twist/secg/sect283r1.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<pubkey> + <id>sect283r1/0</id> + <inline>0x000000000000000000000000000000000000000000000000000000000000000000000000,0x072bcc9c5792b1ebe81983089fb6f835a2fd220a304424ca17c082ae17442aede9b9b3f6</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x2</desc> +</pubkey> +<pubkey> + <id>sect283r1/1</id> + <inline>0x0297e6d1f2b857a79f5dc85c2f1259d5d801c61a4d0a4312a04f65f09a887a7b93cf7ae1,0x051963c38ac61f05fef93707abcfbda7bc0f39eacddb2bdd3077f19c0e65c8be66ecb30e</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x7</desc> +</pubkey> +<pubkey> + <id>sect283r1/2</id> + <inline>0x06909a8eacbed1942bc0a6d606ad1ce284dd223d8ce569dba8525c5a5f799f137112c7ad,0x02e4300b6ce278700db70764e810c1a8d4645b57db3d3974027a1a106598ceba86a61ab5</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x13</desc> +</pubkey> +<pubkey> + <id>sect283r1/3</id> + <inline>0x01287256c9848e3bd11dddf8f34ecca845b535e84adfdf0154f0e7c4ae1a9f0e6719b9b2,0x0119bf5a2c413f730a1576f577873a6f0a603fd571084d584df0a12601b80fe9b607401f</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x1623ab619</desc> +</pubkey> +<pubkey> + <id>sect283r1/4</id> + <inline>0x0598a8e3f2a3e06680ab11b84a01d59adee54f329dfc2b65f8a517c2a5f03b8f1aedb021,0x02943952200eb1ab69c2ac5811d32ea4a528af7cc917d2f2883ca5ca55e464f673f5c2f0</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x2a4aa67aaaf5413fb</desc> +</pubkey> +<pubkey> + <id>sect283r1/5</id> + <inline>0x02e22724a4462bbca361607163bb9ab9926e8fe6859adb397e5eeb8d0972de359e37eebc,0x05b15d8c245bfd0c2ed3930a5742f747e12f4fe0e018ab32fc790711bfdb060514cf8400</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x25a8cdb1f2e470f3ac1ba7</desc> +</pubkey> +<pubkey> + <id>sect283r1/6</id> + <inline>0x032a8c3ac7583c8f599fe6cba343b26f66fe13906c96e11db396ad939d43b55260e5fcef,0x046a4cbc0d05bf6ebad4b5f2bfa6f1a486519ff332ebc49136067916f188af2f5bce0782</inline> + <curve>secg/sect283r1</curve> + <desc>twist order = 0x606749a9c147da03ad3f37</desc> +</pubkey> diff --git a/src/cz/crcs/ectester/data/wrong/wrongt163.csv b/src/cz/crcs/ectester/data/wrong/wrongt163.csv index 91fd70b..88b142e 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt163.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt163.csv @@ -1 +1 @@ -00a3,0002,0000,0000,55e202b98d7e864b2c9c560dc8f8b4047743a84ad,4cf310ee7a37cb2bacafa5e5a5ffcc8464a51162d,58ae9952e3b62978ccc1bfd060564b2620d154049,5ed1e3aa306f09a955feff97757bc4e599c64bb9f,2aaaaaaaaaaaaaaaaaaaaaaaaaabc02b61ca4c651,3
\ No newline at end of file +0x00a3,0x0002,0x0000,0x0000,0x55e202b98d7e864b2c9c560dc8f8b4047743a84ad,0x4cf310ee7a37cb2bacafa5e5a5ffcc8464a51162d,0x58ae9952e3b62978ccc1bfd060564b2620d154049,0x5ed1e3aa306f09a955feff97757bc4e599c64bb9f,0x2aaaaaaaaaaaaaaaaaaaaaaaaaabc02b61ca4c651,0x3 diff --git a/src/cz/crcs/ectester/data/wrong/wrongt233.csv b/src/cz/crcs/ectester/data/wrong/wrongt233.csv index 7e704b0..291cdfe 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt233.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt233.csv @@ -1 +1 @@ -00e9,0001,0000,0000,14228234ca1e8900adcfef49a037d560c8e2c2ed4227d4a2cda8703079d,18f33f0e925e6af86764a84dae2e09eeb0ce218e21ad9638eeb9d2e2600,182a21d656972aeca534df8f8e8c5aa0f553cde1e025a75610f10ae9db5,118732c490d8788716e9ac581c37c140116d12e2e9abd56262a1a255472,c59f46db5ba025578d418f86dc556bec9d212b740ab595b83abd008ec0,2
\ No newline at end of file +0x00e9,0x0001,0x0000,0x0000,0x14228234ca1e8900adcfef49a037d560c8e2c2ed4227d4a2cda8703079d,0x18f33f0e925e6af86764a84dae2e09eeb0ce218e21ad9638eeb9d2e2600,0x182a21d656972aeca534df8f8e8c5aa0f553cde1e025a75610f10ae9db5,0x118732c490d8788716e9ac581c37c140116d12e2e9abd56262a1a255472,0xc59f46db5ba025578d418f86dc556bec9d212b740ab595b83abd008ec0,0x2 diff --git a/src/cz/crcs/ectester/data/wrong/wrongt239.csv b/src/cz/crcs/ectester/data/wrong/wrongt239.csv index 51098b6..bef2e14 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt239.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt239.csv @@ -1 +1 @@ -00ef,0001,0000,0000,513e8b6997328b69d60decd7fa034c1b3bd862717164e7785eb06dcc5b88,63510c1cc1053a916b68f258e9d3f7c2ba054e4af05f3e4d61b3de772d2a,509d82beb7ef27b5b7421ac1e93ccffea76c4f0874991cf3facf0eab9ef6,42a9207ae1cc90d3d29c42a87f754321ccbeaed2e18957ce5a9b01f56812,28759505089d94226a73eefded3f7bf2f81673517715cb032daeddbb68f7,2
\ No newline at end of file +0x00ef,0x0001,0x0000,0x0000,0x513e8b6997328b69d60decd7fa034c1b3bd862717164e7785eb06dcc5b88,0x63510c1cc1053a916b68f258e9d3f7c2ba054e4af05f3e4d61b3de772d2a,0x509d82beb7ef27b5b7421ac1e93ccffea76c4f0874991cf3facf0eab9ef6,0x42a9207ae1cc90d3d29c42a87f754321ccbeaed2e18957ce5a9b01f56812,0x28759505089d94226a73eefded3f7bf2f81673517715cb032daeddbb68f7,0x2 diff --git a/src/cz/crcs/ectester/data/wrong/wrongt283.csv b/src/cz/crcs/ectester/data/wrong/wrongt283.csv index 0d412de..736fe15 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt283.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt283.csv @@ -1 +1 @@ -011b,0002,0000,0000,7e2a42c7f5af962ff0f58711703462947d0a4eb3555b123aa33088a9c566424f0126157,6f317d6314dd7069b6be8cfb5fd0c563b9dbb2f9b8ca2618dd8cd4e7d1a368452aa3c34,5beb9f0130f758148a16a5c65b9228836af1c7afbab4afeffed328ed04ec1bf015f9c16,68996bd05c007c329738a29893a6215c99fbfa460e143090d588d9b157c99843e91c976,2552bf070faa392ab3b7fa07e443e5a45dc9bb3e1a6fe44d1440fdde6752c90899d4197,3 +0x011b,0x0002,0x0000,0x0000,0x7e2a42c7f5af962ff0f58711703462947d0a4eb3555b123aa33088a9c566424f0126157,0x6f317d6314dd7069b6be8cfb5fd0c563b9dbb2f9b8ca2618dd8cd4e7d1a368452aa3c34,0x5beb9f0130f758148a16a5c65b9228836af1c7afbab4afeffed328ed04ec1bf015f9c16,0x68996bd05c007c329738a29893a6215c99fbfa460e143090d588d9b157c99843e91c976,0x2552bf070faa392ab3b7fa07e443e5a45dc9bb3e1a6fe44d1440fdde6752c90899d4197,0x3 diff --git a/src/cz/crcs/ectester/data/wrong/wrongt409.csv b/src/cz/crcs/ectester/data/wrong/wrongt409.csv index 97c8f95..fe7e040 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt409.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt409.csv @@ -1 +1 @@ -0199,0002,0000,0000,1cc6efad1333dd213e812bdc9909754ff20c102fb9c9a2a7fdbd23ca7d414bec401bc45532980dff9cc869b4622c7f5b65e2afb,1cfc909e058af6762da1c2d85ec911d4e393dcd4539aa6c6d755b3dfdf9c4c338c84b984f533479d2f2bb5169b4fae6a25159f6,1ef44edd1100313984d059e3ecae6c866d83bfb9931e616abafcb9f1461ec264509260b4c62a09f1f03595c404e530d467dc14c,1055f15e3b4272c3bf6ecaeb59204470b96111eb38eb395066b26fbae646ab57b7ae6cda5722a98b01aade1bcf3b6db950d2957,c3b9b6e10f6ed3a458388e94c4d567e1a2272bb996892a919e65a8da15c0907ac735eb2f9a7cee28ac90193dabd2408e232839,2 +0x0199,0x0002,0x0000,0x0000,0x1cc6efad1333dd213e812bdc9909754ff20c102fb9c9a2a7fdbd23ca7d414bec401bc45532980dff9cc869b4622c7f5b65e2afb,0x1cfc909e058af6762da1c2d85ec911d4e393dcd4539aa6c6d755b3dfdf9c4c338c84b984f533479d2f2bb5169b4fae6a25159f6,0x1ef44edd1100313984d059e3ecae6c866d83bfb9931e616abafcb9f1461ec264509260b4c62a09f1f03595c404e530d467dc14c,0x1055f15e3b4272c3bf6ecaeb59204470b96111eb38eb395066b26fbae646ab57b7ae6cda5722a98b01aade1bcf3b6db950d2957,0xc3b9b6e10f6ed3a458388e94c4d567e1a2272bb996892a919e65a8da15c0907ac735eb2f9a7cee28ac90193dabd2408e232839,0x2 diff --git a/src/cz/crcs/ectester/data/wrong/wrongt571.csv b/src/cz/crcs/ectester/data/wrong/wrongt571.csv index 9e61a8a..2fcd0df 100644 --- a/src/cz/crcs/ectester/data/wrong/wrongt571.csv +++ b/src/cz/crcs/ectester/data/wrong/wrongt571.csv @@ -1 +1 @@ -023b,0002,0000,0000,4d3b833ae38b91e89061c4fae9e38264f2e88b4969778aa935eeec50fd1d66a994589e835aeb590566f0adafba2c40c1866865e62cae00f1d235038139d8d25b32d842a7a8b03b0,736974cc00c08dfbd1d23a6bea984c1c1af6ceae0a8b48ecd84b8a4fedbb46d61ab94efa8f53e50b6aa0c0599c2121af733dc36c07ccb7762d210bef02aa8611fe464d369f8a923,4f3bb81214f966e73a2f64423738ab7cd642b871ce7fb0e5f302a3a658aafd68e25d38c432d5e48334a2c03f472defa43ca0933fd13c98138bab6d7ca228ab860c79cd9114d4549,6355104090026816f380b1b406e84f93e12cbaa9f23adcef1eab09bd0418f7906195b102daed369ba72b9370e24a12c7676263c20bf7c7f3018c7a84ee80f586cc8fb16dd526110,397cad72a3fefe82d79a96e18009f5f9b661a9fa2ee53a5eb9f4016d2deaf249e2969b9af649fa363f4c2d5ec837792d932748f7344a16f8ab4be63341812d1c4f52a7b3fa65757,2 +0x023b,0x0002,0x0000,0x0000,0x4d3b833ae38b91e89061c4fae9e38264f2e88b4969778aa935eeec50fd1d66a994589e835aeb590566f0adafba2c40c1866865e62cae00f1d235038139d8d25b32d842a7a8b03b0,0x736974cc00c08dfbd1d23a6bea984c1c1af6ceae0a8b48ecd84b8a4fedbb46d61ab94efa8f53e50b6aa0c0599c2121af733dc36c07ccb7762d210bef02aa8611fe464d369f8a923,0x4f3bb81214f966e73a2f64423738ab7cd642b871ce7fb0e5f302a3a658aafd68e25d38c432d5e48334a2c03f472defa43ca0933fd13c98138bab6d7ca228ab860c79cd9114d4549,0x6355104090026816f380b1b406e84f93e12cbaa9f23adcef1eab09bd0418f7906195b102daed369ba72b9370e24a12c7676263c20bf7c7f3018c7a84ee80f586cc8fb16dd526110,0x397cad72a3fefe82d79a96e18009f5f9b661a9fa2ee53a5eb9f4016d2deaf249e2969b9af649fa363f4c2d5ec837792d932748f7344a16f8ab4be63341812d1c4f52a7b3fa65757,0x2 diff --git a/src/cz/crcs/ectester/data/x962/curves.xml b/src/cz/crcs/ectester/data/x962/curves.xml new file mode 100644 index 0000000..eee64ad --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/curves.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8" ?> +<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../schema.xsd"> + <curve> + <id>prime192v1</id> + <bits>192</bits> + <field>prime</field> + <file>prime192v1.csv</file> + </curve> + <curve> + <id>prime192v2</id> + <bits>192</bits> + <field>prime</field> + <file>prime192v2.csv</file> + </curve> + <curve> + <id>prime192v3</id> + <bits>192</bits> + <field>prime</field> + <file>prime192v3.csv</file> + </curve> + + <curve> + <id>prime239v1</id> + <bits>239</bits> + <field>prime</field> + <file>prime239v1.csv</file> + </curve> + <curve> + <id>prime239v2</id> + <bits>239</bits> + <field>prime</field> + <file>prime239v2.csv</file> + </curve> + <curve> + <id>prime239v3</id> + <bits>239</bits> + <field>prime</field> + <file>prime239v3.csv</file> + </curve> + + <curve> + <id>prime256v1</id> + <bits>256</bits> + <field>prime</field> + <file>prime256v1.csv</file> + </curve> +</curves>
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v1.csv b/src/cz/crcs/ectester/data/x962/prime192v1.csv new file mode 100644 index 0000000..07f9154 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v1.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012,0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811,0xffffffffffffffffffffffff99def836146bc9b1b4d22831,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v2.csv b/src/cz/crcs/ectester/data/x962/prime192v2.csv new file mode 100644 index 0000000..ee6f1a2 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v2.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953,0xeea2bae7e1497842f2de7769cfe9c989c072ad696f48034a,0x6574d11d69b6ec7a672bb82a083df2f2b0847de970b2de15,0xfffffffffffffffffffffffe5fb1a724dc80418648d8dd31,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime192v3.csv b/src/cz/crcs/ectester/data/x962/prime192v3.csv new file mode 100644 index 0000000..f80fd5b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime192v3.csv @@ -0,0 +1 @@ +0xfffffffffffffffffffffffffffffffeffffffffffffffff,0xfffffffffffffffffffffffffffffffefffffffffffffffc,0x22123dc2395a05caa7423daeccc94760a7d462256bd56916,0x7d29778100c65a1da1783716588dce2b8b4aee8e228f1896,0x38a90f22637337334b49dcb66a6dc8f9978aca7648a943b0,0xffffffffffffffffffffffff7a62d031c83f4294f640ec13,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v1.csv b/src/cz/crcs/ectester/data/x962/prime239v1.csv new file mode 100644 index 0000000..c9d704b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v1.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a,0x0ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf,0x7debe8e4e90a5dae6e4054ca530ba04654b36818ce226b39fccb7b02f1ae,0x7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v2.csv b/src/cz/crcs/ectester/data/x962/prime239v2.csv new file mode 100644 index 0000000..100e60b --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v2.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c,0x38af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7,0x5b0125e4dbea0ec7206da0fc01d9b081329fb555de6ef460237dff8be4ba,0x7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime239v3.csv b/src/cz/crcs/ectester/data/x962/prime239v3.csv new file mode 100644 index 0000000..ce8b38a --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime239v3.csv @@ -0,0 +1 @@ +0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e,0x6768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a,0x1607e6898f390c06bc1d552bad226f3b6fcfe48b6e818499af18e3ed6cf3,0x7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/data/x962/prime256v1.csv b/src/cz/crcs/ectester/data/x962/prime256v1.csv new file mode 100644 index 0000000..c5a2440 --- /dev/null +++ b/src/cz/crcs/ectester/data/x962/prime256v1.csv @@ -0,0 +1 @@ +0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,0x1
\ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java index e11bcb3..1e42c52 100644 --- a/src/cz/crcs/ectester/reader/CardMngr.java +++ b/src/cz/crcs/ectester/reader/CardMngr.java @@ -2,11 +2,12 @@ package cz.crcs.ectester.reader; import com.licel.jcardsim.io.CAD; import com.licel.jcardsim.io.JavaxSmartCardInterface; +import cz.crcs.ectester.common.util.ByteUtil; import javacard.framework.AID; +import javacard.framework.ISO7816; import javax.smartcardio.*; -import java.util.List; -import java.util.Scanner; +import java.util.*; /** * @author Petr Svenda petr@svenda.com @@ -79,7 +80,7 @@ public class CardMngr { //reset the card if (verbose) - System.out.println(Util.bytesToHex(card.getATR().getBytes())); + System.out.println(ByteUtil.bytesToHex(card.getATR().getBytes())); cardFound = true; } @@ -108,7 +109,7 @@ public class CardMngr { try { card = terminal.connect("*"); ATR atr = card.getATR(); - System.out.println(terminalIndex + " : " + terminal.getName() + " - " + Util.bytesToHex(atr.getBytes())); + System.out.println(terminalIndex + " : " + terminal.getName() + " - " + ByteUtil.bytesToHex(atr.getBytes())); terminalIndex++; } catch (CardException ex) { ex.printStackTrace(System.out); @@ -164,50 +165,138 @@ public class CardMngr { } } - public byte[] getCPLCData() throws Exception { - byte[] data; + // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro + private static final byte CLA_GP = (byte) 0x80; + private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA; + private static final byte[] FETCH_GP_CPLC_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00}; + private static final byte[] FETCH_ISO_CPLC_APDU = {ISO7816.CLA_ISO7816, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00}; + private static final byte[] FETCH_GP_CARDDATA_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x00, (byte) 0x66, (byte) 0x00}; - // TODO: Modify to obtain CPLC data - byte apdu[] = new byte[HEADER_LENGTH]; - apdu[OFFSET_CLA] = (byte) 0x00; - apdu[OFFSET_INS] = (byte) 0x00; - apdu[OFFSET_P1] = (byte) 0x00; - apdu[OFFSET_P2] = (byte) 0x00; - apdu[OFFSET_LC] = (byte) 0x00; + public byte[] fetchCPLC() throws CardException { + // Try CPLC via GP + ResponseAPDU resp = send(FETCH_GP_CPLC_APDU); + // If GP CLA fails, try with ISO + if (resp.getSW() == (ISO7816.SW_CLA_NOT_SUPPORTED & 0xffff)) { + resp = send(FETCH_ISO_CPLC_APDU); + } + if (resp.getSW() == (ISO7816.SW_NO_ERROR & 0xffff)) { + return resp.getData(); + } + return null; + } - ResponseAPDU resp = send(apdu); - if (resp.getSW() != 0x9000) { // 0x9000 is "OK" - System.err.println("Fail to obtain card's response data"); - data = null; - } else { - byte temp[] = resp.getBytes(); - data = new byte[temp.length - 2]; - System.arraycopy(temp, 0, data, 0, temp.length - 2); - // Last two bytes are status word (also obtainable by resp.getSW()) - // Take a look at ISO7816_status_words.txt for common codes + public static final class CPLC { + public enum Field { + ICFabricator, + ICType, + OperatingSystemID, + OperatingSystemReleaseDate, + OperatingSystemReleaseLevel, + ICFabricationDate, + ICSerialNumber, + ICBatchIdentifier, + ICModuleFabricator, + ICModulePackagingDate, + ICCManufacturer, + ICEmbeddingDate, + ICPrePersonalizer, + ICPrePersonalizationEquipmentDate, + ICPrePersonalizationEquipmentID, + ICPersonalizer, + ICPersonalizationDate, + ICPersonalizationEquipmentID } - return data; - } + private Map<Field, byte[]> values = new TreeMap<>(); - public void probeCardCommands() throws Exception { - // TODO: modify to probe for instruction - for (int i = 0; i <= 0; i++) { - byte apdu[] = new byte[HEADER_LENGTH]; - apdu[OFFSET_CLA] = (byte) 0x00; - apdu[OFFSET_INS] = (byte) 0x00; - apdu[OFFSET_P1] = (byte) 0x00; - apdu[OFFSET_P2] = (byte) 0x00; - apdu[OFFSET_LC] = (byte) 0x00; + public CPLC(byte[] data) { + if (data == null) { + return; + } + if (data.length < 3 || data[2] != 0x2A) { + throw new IllegalArgumentException("CPLC must be 0x2A bytes long"); + } + //offset = TLVUtils.skipTag(data, offset, (short)0x9F7F); + short offset = 3; + values.put(Field.ICFabricator, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICType, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemID, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemReleaseDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.OperatingSystemReleaseLevel, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICFabricationDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICSerialNumber, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + values.put(Field.ICBatchIdentifier, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICModuleFabricator, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICModulePackagingDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICCManufacturer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICEmbeddingDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizationEquipmentDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPrePersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + values.put(Field.ICPersonalizer, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPersonalizationDate, Arrays.copyOfRange(data, offset, offset + 2)); + offset += 2; + values.put(Field.ICPersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4)); + offset += 4; + } - ResponseAPDU resp = send(apdu); + public Map<Field, byte[]> values() { + return values; + } + } - if (verbose) - System.out.println("Response: " + Integer.toHexString(resp.getSW())); + public CPLC getCPLC() throws CardException { + byte[] data = fetchCPLC(); + return new CPLC(data); + } - if (resp.getSW() != 0x6D00) { // Note: 0x6D00 is SW_INS_NOT_SUPPORTED - // something? - } + public static String mapCPLCField(CPLC.Field field, byte[] value) { + switch (field) { + case ICFabricator: + String id = ByteUtil.bytesToHex(value, false); + String fabricatorName = "unknown"; + if (id.equals("3060")) { + fabricatorName = "Renesas"; + } + if (id.equals("4090")) { + fabricatorName = "Infineon"; + } + if (id.equals("4180")) { + fabricatorName = "Atmel"; + } + if (id.equals("4250")) { + fabricatorName = "Samsung"; + } + if (id.equals("4790")) { + fabricatorName = "NXP"; + } + return id + " (" + fabricatorName + ")"; + default: + return ByteUtil.bytesToHex(value, false); + } + } + + public ATR getATR() { + if (simulate) { + return new ATR(simulator.getATR()); + } else { + return card.getATR(); } } @@ -226,7 +315,7 @@ public class CardMngr { System.out.println(">>>>"); System.out.println(apdu); - System.out.println(Util.bytesToHex(apdu.getBytes())); + System.out.println(ByteUtil.bytesToHex(apdu.getBytes())); } long elapsed = -System.nanoTime(); @@ -237,7 +326,7 @@ public class CardMngr { if (verbose) { System.out.println(responseAPDU); - System.out.println(Util.bytesToHex(responseAPDU.getBytes())); + System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes())); } if (responseAPDU.getSW1() == (byte) 0x61) { @@ -247,7 +336,7 @@ public class CardMngr { responseAPDU = channel.transmit(apduToSend); if (verbose) - System.out.println(Util.bytesToHex(responseAPDU.getBytes())); + System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes())); } if (verbose) { @@ -276,7 +365,7 @@ public class CardMngr { if (verbose) { System.out.println(">>>>"); System.out.println(apdu); - System.out.println(Util.bytesToHex(apdu.getBytes())); + System.out.println(ByteUtil.bytesToHex(apdu.getBytes())); } ResponseAPDU response = simulator.transmitCommand(apdu); @@ -284,7 +373,7 @@ public class CardMngr { if (verbose) { System.out.println(response); - System.out.println(Util.bytesToHex(responseBytes)); + System.out.println(ByteUtil.bytesToHex(responseBytes)); System.out.println("<<<<"); } diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTesterReader.java index 550e070..5e3a3fe 100644 --- a/src/cz/crcs/ectester/reader/ECTester.java +++ b/src/cz/crcs/ectester/reader/ECTesterReader.java @@ -23,12 +23,19 @@ package cz.crcs.ectester.reader; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.cli.CLITools; +import cz.crcs.ectester.common.ec.EC_Params; +import cz.crcs.ectester.common.output.OutputLogger; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Category; -import cz.crcs.ectester.reader.ec.EC_Data; -import cz.crcs.ectester.reader.ec.EC_Params; -import cz.crcs.ectester.reader.output.*; +import cz.crcs.ectester.reader.output.ResponseWriter; +import cz.crcs.ectester.reader.output.TextTestWriter; +import cz.crcs.ectester.reader.output.XMLTestWriter; +import cz.crcs.ectester.reader.output.YAMLTestWriter; import cz.crcs.ectester.reader.response.Response; import cz.crcs.ectester.reader.test.*; import javacard.security.KeyPair; @@ -38,9 +45,13 @@ import javax.smartcardio.CardException; import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.nio.file.Files; -import java.util.*; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Scanner; import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; +import static cz.crcs.ectester.applet.ECTesterApplet.Signature_ALG_ECDSA_SHA; /** * Reader part of ECTester, a tool for testing Elliptic curve support on javacards. @@ -49,18 +60,15 @@ import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH * @author Jan Jancar johny@neuromancer.sk * @version v0.1.0 */ -public class ECTester { - +public class ECTesterReader { private CardMngr cardManager; private OutputLogger logger; - private TestWriter testWriter; private ResponseWriter respWriter; - private EC_Store dataStore; private Config cfg; private Options opts = new Options(); private static final String VERSION = "v0.1.0"; - private static final String DESCRIPTION = "ECTester " + VERSION + ", a javacard Elliptic Curve Cryptograhy support tester/utility."; + private static final String DESCRIPTION = "ECTesterReader " + VERSION + ", a javacard Elliptic Curve Cryptography support tester/utility."; private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda <petr@svenda.com>"; private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; private static final String CLI_FOOTER = "\n" + LICENSE; @@ -76,11 +84,10 @@ public class ECTester { //if help, print and quit if (cli.hasOption("help")) { - help(); + CLITools.help("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true); return; } else if (cli.hasOption("version")) { - System.out.println(DESCRIPTION); - System.out.println(LICENSE); + CLITools.version(DESCRIPTION, LICENSE); return; } cfg = new Config(); @@ -90,10 +97,9 @@ public class ECTester { return; } - dataStore = new EC_Store(); //if list, print and quit if (cli.hasOption("list-named")) { - list(); + CLITools.listNamed(EC_Store.getInstance(), cli.getOptionValue("list-named")); return; } @@ -116,22 +122,7 @@ public class ECTester { // Setup logger, testWriter and respWriter logger = new OutputLogger(true, cfg.log); - if (cfg.format == null) { - testWriter = new TextTestWriter(logger.getPrintStream()); - } else { - switch (cfg.format) { - case "text": - testWriter = new TextTestWriter(logger.getPrintStream()); - break; - case "xml": - testWriter = new XMLTestWriter(logger.getOutputStream()); - break; - case "yaml": - case "yml": - testWriter = new YAMLTestWriter(logger.getPrintStream()); - break; - } - } + respWriter = new ResponseWriter(logger.getPrintStream()); //do action @@ -187,9 +178,10 @@ public class ECTester { System.err.println("File " + fnfe.getMessage() + " not found."); } catch (ParseException | IOException ex) { System.err.println(ex.getMessage()); - } catch (CardException ex) { + } catch (CardException | TestException ex) { if (logger != null) logger.println(ex.getMessage()); + ex.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } finally { @@ -213,8 +205,7 @@ public class ECTester { * -e / --export * -g / --generate [amount] * -t / --test [test_suite] - * -dh / --ecdh [count] - * -dhc / --ecdhc [count] + * -dh / --ecdh [count]] * -dsa / --ecdsa [count] * -ln / --list-named [obj] * @@ -248,6 +239,7 @@ public class ECTester { * -s / --simulate * -y / --yes * -ka/ --ka-type <type> + * -sig/--sig-type <type> */ OptionGroup actions = new OptionGroup(); actions.setRequired(true); @@ -256,9 +248,8 @@ public class ECTester { actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build()); actions.addOption(Option.builder("e").longOpt("export").desc("Export the defaut curve parameters of the card(if any).").build()); actions.addOption(Option.builder("g").longOpt("generate").desc("Generate [amount] of EC keys.").hasArg().argName("amount").optionalArg(true).build()); - actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build()); - actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do ECDH, [count] times.").hasArg().argName("count").optionalArg(true).build()); - actions.addOption(Option.builder("dhc").longOpt("ecdhc").desc("Do ECDHC, [count] times.").hasArg().argName("count").optionalArg(true).build()); + actions.addOption(Option.builder("t").longOpt("test").desc("Test ECC support. [test_suite]:\n- default:\n- invalid:\n- twist:\n- wrong:\n- composite:\n- test-vectors:").hasArg().argName("test_suite").optionalArg(true).build()); + actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build()); actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build()); opts.addOptionGroup(actions); @@ -303,45 +294,13 @@ public class ECTester { opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build()); opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build()); + opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build()); CommandLineParser parser = new DefaultParser(); return parser.parse(opts, args); } /** - * Prints help. - */ - private void help() { - HelpFormatter help = new HelpFormatter(); - help.setOptionComparator(null); - help.printHelp("ECTester.jar", CLI_HEADER, opts, CLI_FOOTER, true); - } - - /** - * List categories and named curves. - */ - private void list() { - Map<String, EC_Category> categories = dataStore.getCategories(); - if (cfg.listNamed == null) { - // print all categories, briefly - for (EC_Category cat : categories.values()) { - System.out.println(cat); - } - } else if (categories.containsKey(cfg.listNamed)) { - // print given category - System.out.println(categories.get(cfg.listNamed)); - } else { - // print given object - EC_Data object = dataStore.getObject(EC_Data.class, cfg.listNamed); - if (object != null) { - System.out.println(object); - } else { - System.err.println("Named object " + cfg.listNamed + " not found!"); - } - } - } - - /** * Exports default card/simulation EC domain parameters to output file. * * @throws CardException if APDU transmission fails @@ -386,8 +345,9 @@ public class ECTester { private void generate() throws CardException, IOException { byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; - new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send(); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); + Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send(); + respWriter.outputResponse(allocate); + Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); FileWriter keysFile = new FileWriter(cfg.output); keysFile.write("index;time;pubW;privS\n"); @@ -417,8 +377,8 @@ public class ECTester { } respWriter.outputResponse(response); - String pub = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); - String priv = Util.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); + String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false); + String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false); String line = String.format("%d;%d;%s;%s\n", generated, elapsed / 1000000, pub, priv); keysFile.write(line); keysFile.flush(); @@ -436,20 +396,38 @@ public class ECTester { * @throws CardException if APDU transmission fails * @throws IOException if an IO error occurs when writing to key file. */ - private void test() throws IOException, CardException { - TestSuite suite; + private void test() throws IOException, TestException, ParserConfigurationException { + TestWriter writer = null; + if (cfg.format == null) { + writer = new TextTestWriter(logger.getPrintStream()); + } else { + switch (cfg.format) { + case "text": + writer = new TextTestWriter(logger.getPrintStream()); + break; + case "xml": + writer = new XMLTestWriter(logger.getOutputStream()); + break; + case "yaml": + case "yml": + writer = new YAMLTestWriter(logger.getPrintStream()); + break; + } + } + + CardTestSuite suite; switch (cfg.testSuite) { case "default": - suite = new DefaultSuite(dataStore, cfg); + suite = new CardDefaultSuite(writer, cfg, cardManager); break; case "test-vectors": - suite = new TestVectorSuite(dataStore, cfg); + suite = new CardTestVectorSuite(writer, cfg, cardManager); break; default: - // These tests are dangerous, prompt before them. + // These run are dangerous, prompt before them. System.out.println("The test you selected (" + cfg.testSuite + ") is potentially dangerous."); - System.out.println("Some of these tests have caused temporary DoS of some cards."); + System.out.println("Some of these run have caused temporary DoS of some cards."); if (!cfg.yes) { System.out.print("Do you want to proceed? (y/n): "); Scanner in = new Scanner(System.in); @@ -459,17 +437,18 @@ public class ECTester { } in.close(); } - - switch (cfg.testSuite) { case "wrong": - suite = new WrongCurvesSuite(dataStore, cfg); + suite = new CardWrongCurvesSuite(writer, cfg, cardManager); break; case "composite": - suite = new CompositeCurvesSuite(dataStore, cfg); + suite = new CardCompositeCurvesSuite(writer, cfg, cardManager); break; case "invalid": - suite = new InvalidCurvesSuite(dataStore, cfg); + suite = new CardInvalidCurvesSuite(writer, cfg, cardManager); + break; + case "twist": + suite = new CardTwistTestSuite(writer, cfg, cardManager); break; default: System.err.println("Unknown test suite."); @@ -478,9 +457,7 @@ public class ECTester { break; } - TestRunner runner = new TestRunner(suite, testWriter); - suite.setup(cardManager); - runner.run(); + suite.run(); } /** @@ -492,9 +469,9 @@ public class ECTester { private void ecdh() throws IOException, CardException { byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; List<Response> prepare = new LinkedList<>(); - prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.kaType).send()); // Prepare KeyAgreement or required type + prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass).send()); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass); + Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_BOTH, (short) cfg.bits, keyClass); if (curve != null) prepare.add(curve.send()); @@ -508,21 +485,26 @@ public class ECTester { List<Command> generate = new LinkedList<>(); generate.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH)); if (cfg.anyPublicKey || cfg.anyPrivateKey || cfg.anyKey) { - generate.add(Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_REMOTE)); + generate.add(Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE)); } FileWriter out = null; if (cfg.output != null) { out = new FileWriter(cfg.output); - out.write("index;time;secret\n"); + out.write("index;time;pubW;privS;secret\n"); } int retry = 0; int done = 0; - while (done < cfg.ECDHCount) { + while (done < cfg.ECKACount) { List<Response> ecdh = Command.sendAll(generate); - Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECDHKA).send(); + Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send(); + ecdh.add(export); + byte pubkey_bytes[] = export.getParameter(pubkey, EC_Consts.PARAMETER_W); + byte privkey_bytes[] = export.getParameter(privkey, EC_Consts.PARAMETER_S); + + Response.ECDH perform = new Command.ECDH(cardManager, pubkey, privkey, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, cfg.ECKAType).send(); ecdh.add(perform); for (Response r : ecdh) { respWriter.outputResponse(r); @@ -539,7 +521,7 @@ public class ECTester { } if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSecret(), false))); + out.write(String.format("%d;%d;%s;%s;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(perform.getSecret(), false))); } ++done; @@ -571,15 +553,16 @@ public class ECTester { Command generate; if (cfg.anyKeypart) { - generate = Command.prepareKey(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL); + generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL); } else { generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL); } byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M; List<Response> prepare = new LinkedList<>(); + prepare.add(new Command.AllocateSignature(cardManager, cfg.ECDSAType).send()); prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass).send()); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); + Command curve = Command.prepareCurve(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, (short) cfg.bits, keyClass); if (curve != null) prepare.add(curve.send()); @@ -599,7 +582,7 @@ public class ECTester { List<Response> ecdsa = new LinkedList<>(); ecdsa.add(generate.send()); - Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, data).send(); + Response.ECDSA perform = new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data).send(); ecdsa.add(perform); for (Response r : ecdsa) { respWriter.outputResponse(r); @@ -616,7 +599,7 @@ public class ECTester { } if (out != null) { - out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, Util.bytesToHex(perform.getSignature(), false))); + out.write(String.format("%d;%d;%s\n", done, perform.getDuration() / 1000000, ByteUtil.bytesToHex(perform.getSignature(), false))); } ++done; @@ -629,18 +612,18 @@ public class ECTester { } public static void main(String[] args) { - ECTester app = new ECTester(); + ECTesterReader app = new ECTesterReader(); app.run(args); } public static class Config { //Options - public int bits; + public short bits; public boolean all; public boolean primeField = false; public boolean binaryField = false; - public byte kaType = KeyAgreement_ALG_EC_SVDP_DH; + public String namedCurve; public String curveFile; @@ -674,9 +657,10 @@ public class ECTester { public String listNamed; public String testSuite; public int generateAmount; - public int ECDHCount; - public byte ECDHKA; + public int ECKACount; + public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH; public int ECDSACount; + public byte ECDSAType = Signature_ALG_ECDSA_SHA; /** * Reads and validates options, also sets defaults. @@ -685,11 +669,11 @@ public class ECTester { * @return whether the options are valid. */ boolean readOptions(CommandLine cli) { - bits = Integer.parseInt(cli.getOptionValue("bit-size", "0")); + bits = Short.parseShort(cli.getOptionValue("bit-size", "0")); all = cli.hasOption("all"); primeField = cli.hasOption("fp"); binaryField = cli.hasOption("f2m"); - kaType = Byte.parseByte(cli.getOptionValue("ka-type", "1")); + namedCurve = cli.getOptionValue("named-curve"); customCurve = cli.hasOption("custom"); @@ -770,7 +754,6 @@ public class ECTester { System.err.println("You have to specify curve bit-size with -b"); return false; } - } else if (cli.hasOption("generate")) { if (primeField == binaryField) { System.err.print("Need to specify field with -fp or -f2m. (not both)"); @@ -801,13 +784,12 @@ public class ECTester { } testSuite = cli.getOptionValue("test", "default").toLowerCase(); - String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong"}; + String[] tests = new String[]{"default", "composite", "invalid", "test-vectors", "wrong", "twist"}; if (!Arrays.asList(tests).contains(testSuite)) { System.err.println("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests)); return false; } - - } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) { + } else if (cli.hasOption("ecdh")) { if (primeField == binaryField) { System.err.print("Need to specify field with -fp or -f2m. (not both)"); return false; @@ -817,18 +799,13 @@ public class ECTester { return false; } - if (cli.hasOption("ecdh")) { - ECDHCount = Integer.parseInt(cli.getOptionValue("ecdh", "1")); - ECDHKA = EC_Consts.KA_ECDH; - } else if (cli.hasOption("ecdhc")) { - ECDHCount = Integer.parseInt(cli.getOptionValue("ecdhc", "1")); - ECDHKA = EC_Consts.KA_ECDHC; - } - if (ECDHCount <= 0) { + ECKACount = Integer.parseInt(cli.getOptionValue("ecdh", "1")); + if (ECKACount <= 0) { System.err.println("ECDH count cannot be <= 0."); return false; } + ECKAType = CardUtil.parseKAType(cli.getOptionValue("ka-type", "1")); } else if (cli.hasOption("ecdsa")) { if (primeField == binaryField) { System.err.print("Need to specify field with -fp or -f2m. (but not both)"); @@ -849,6 +826,8 @@ public class ECTester { System.err.println("ECDSA count cannot be <= 0."); return false; } + + ECDSAType = CardUtil.parseSigType(cli.getOptionValue("sig-type", "17")); } return true; } diff --git a/src/cz/crcs/ectester/reader/Util.java b/src/cz/crcs/ectester/reader/Util.java deleted file mode 100644 index 4e1154b..0000000 --- a/src/cz/crcs/ectester/reader/Util.java +++ /dev/null @@ -1,379 +0,0 @@ -package cz.crcs.ectester.reader; - -import cz.crcs.ectester.applet.ECTesterApplet; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_PACE_GM; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DHC_PLAIN; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN; -import static cz.crcs.ectester.applet.ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY; -import cz.crcs.ectester.applet.EC_Consts; -import javacard.framework.ISO7816; -import javacard.security.CryptoException; - -/** - * Utility class, some byte/hex manipulation, convenient byte[] methods. - * - * @author Petr Svenda petr@svenda.com - * @author Jan Jancar johny@neuromancer.sk - */ -public class Util { - - public static short getShort(byte[] array, int offset) { - return (short) (((array[offset] & 0xFF) << 8) | (array[offset + 1] & 0xFF)); - } - - public static void setShort(byte[] array, int offset, short value) { - array[offset + 1] = (byte) (value & 0xFF); - array[offset] = (byte) ((value >> 8) & 0xFF); - } - - public static int diffBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { - for (int i = 0; i < length; ++i) { - byte a = one[i + oneOffset]; - byte b = other[i + otherOffset]; - if (a != b) { - return i; - } - } - return length; - } - - public static boolean compareBytes(byte[] one, int oneOffset, byte[] other, int otherOffset, int length) { - return diffBytes(one, oneOffset, other, otherOffset, length) == length; - } - - public static boolean allValue(byte[] array, byte value) { - for (byte a : array) { - if (a != value) - return false; - } - return true; - } - - public static byte[] hexToBytes(String hex) { - return hexToBytes(hex, true); - } - - public static byte[] hexToBytes(String hex, boolean bigEndian) { - hex = hex.replace(" ", ""); - int len = hex.length(); - StringBuilder sb = new StringBuilder(); - - if (len % 2 == 1) { - sb.append("0"); - ++len; - } - - if (bigEndian) { - sb.append(hex); - } else { - for (int i = 0; i < len / 2; ++i) { - if (sb.length() >= 2) { - sb.insert(sb.length() - 2, hex.substring(2 * i, 2 * i + 2)); - } else { - sb.append(hex.substring(2 * i, 2 * i + 2)); - } - - } - } - - String data = sb.toString(); - byte[] result = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - result[i / 2] = (byte) ((Character.digit(data.charAt(i), 16) << 4) - + (Character.digit(data.charAt(i + 1), 16))); - } - return result; - } - - public static String byteToHex(byte data) { - return String.format("%02x", data); - } - - public static String bytesToHex(byte[] data) { - return bytesToHex(data, true); - } - - public static String bytesToHex(byte[] data, boolean addSpace) { - return bytesToHex(data, 0, data.length, addSpace); - } - - public static String bytesToHex(byte[] data, int offset, int len) { - return bytesToHex(data, offset, len, true); - } - - public static String bytesToHex(byte[] data, int offset, int len, boolean addSpace) { - StringBuilder buf = new StringBuilder(); - for (int i = offset; i < (offset + len); i++) { - buf.append(byteToHex(data[i])); - if (addSpace && i != (offset + len - 1)) { - buf.append(" "); - } - } - return (buf.toString()); - } - - public static byte[] concatenate(byte[]... arrays) { - int len = 0; - for (byte[] array : arrays) { - if (array == null) - continue; - len += array.length; - } - byte[] out = new byte[len]; - int offset = 0; - for (byte[] array : arrays) { - if (array == null || array.length == 0) - continue; - System.arraycopy(array, 0, out, offset, array.length); - offset += array.length; - } - return out; - } - - public static String getSWSource(short sw) { - switch (sw) { - case ISO7816.SW_NO_ERROR: - case ISO7816.SW_APPLET_SELECT_FAILED: - case ISO7816.SW_BYTES_REMAINING_00: - case ISO7816.SW_CLA_NOT_SUPPORTED: - case ISO7816.SW_COMMAND_NOT_ALLOWED: - case ISO7816.SW_CONDITIONS_NOT_SATISFIED: - case ISO7816.SW_CORRECT_LENGTH_00: - case ISO7816.SW_DATA_INVALID: - case ISO7816.SW_FILE_FULL: - case ISO7816.SW_FILE_INVALID: - case ISO7816.SW_FILE_NOT_FOUND: - case ISO7816.SW_FUNC_NOT_SUPPORTED: - case ISO7816.SW_INCORRECT_P1P2: - case ISO7816.SW_INS_NOT_SUPPORTED: - case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: - case ISO7816.SW_RECORD_NOT_FOUND: - case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: - case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: - case ISO7816.SW_UNKNOWN: - case ISO7816.SW_WARNING_STATE_UNCHANGED: - case ISO7816.SW_WRONG_DATA: - case ISO7816.SW_WRONG_LENGTH: - case ISO7816.SW_WRONG_P1P2: - return "ISO"; - case CryptoException.ILLEGAL_VALUE: - case CryptoException.UNINITIALIZED_KEY: - case CryptoException.NO_SUCH_ALGORITHM: - case CryptoException.INVALID_INIT: - case CryptoException.ILLEGAL_USE: - return "CryptoException"; - case ECTesterApplet.SW_SIG_VERIFY_FAIL: - case ECTesterApplet.SW_DH_DHC_MISMATCH: - case ECTesterApplet.SW_KEYPAIR_NULL: - case ECTesterApplet.SW_KA_NULL: - case ECTesterApplet.SW_SIGNATURE_NULL: - case ECTesterApplet.SW_OBJECT_NULL: - return "ECTesterApplet"; - default: - return "?"; - } - } - - public static String getSW(short sw) { - String str; - switch (sw) { - case ISO7816.SW_APPLET_SELECT_FAILED: - str = "APPLET_SELECT_FAILED"; - break; - case ISO7816.SW_BYTES_REMAINING_00: - str = "BYTES_REMAINING"; - break; - case ISO7816.SW_CLA_NOT_SUPPORTED: - str = "CLA_NOT_SUPPORTED"; - break; - case ISO7816.SW_COMMAND_NOT_ALLOWED: - str = "COMMAND_NOT_ALLOWED"; - break; - case ISO7816.SW_CONDITIONS_NOT_SATISFIED: - str = "CONDITIONS_NOT_SATISFIED"; - break; - case ISO7816.SW_CORRECT_LENGTH_00: - str = "CORRECT_LENGTH"; - break; - case ISO7816.SW_DATA_INVALID: - str = "DATA_INVALID"; - break; - case ISO7816.SW_FILE_FULL: - str = "FILE_FULL"; - break; - case ISO7816.SW_FILE_INVALID: - str = "FILE_INVALID"; - break; - case ISO7816.SW_FILE_NOT_FOUND: - str = "FILE_NOT_FOUND"; - break; - case ISO7816.SW_FUNC_NOT_SUPPORTED: - str = "FUNC_NOT_SUPPORTED"; - break; - case ISO7816.SW_INCORRECT_P1P2: - str = "INCORRECT_P1P2"; - break; - case ISO7816.SW_INS_NOT_SUPPORTED: - str = "INS_NOT_SUPPORTED"; - break; - case ISO7816.SW_LOGICAL_CHANNEL_NOT_SUPPORTED: - str = "LOGICAL_CHANNEL_NOT_SUPPORTED"; - break; - case ISO7816.SW_RECORD_NOT_FOUND: - str = "RECORD_NOT_FOUND"; - break; - case ISO7816.SW_SECURE_MESSAGING_NOT_SUPPORTED: - str = "SECURE_MESSAGING_NOT_SUPPORTED"; - break; - case ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED: - str = "SECURITY_STATUS_NOT_SATISFIED"; - break; - case ISO7816.SW_UNKNOWN: - str = "UNKNOWN"; - break; - case ISO7816.SW_WARNING_STATE_UNCHANGED: - str = "WARNING_STATE_UNCHANGED"; - break; - case ISO7816.SW_WRONG_DATA: - str = "WRONG_DATA"; - break; - case ISO7816.SW_WRONG_LENGTH: - str = "WRONG_LENGTH"; - break; - case ISO7816.SW_WRONG_P1P2: - str = "WRONG_P1P2"; - break; - case CryptoException.ILLEGAL_VALUE: - str = "ILLEGAL_VALUE"; - break; - case CryptoException.UNINITIALIZED_KEY: - str = "UNINITIALIZED_KEY"; - break; - case CryptoException.NO_SUCH_ALGORITHM: - str = "NO_SUCH_ALG"; - break; - case CryptoException.INVALID_INIT: - str = "INVALID_INIT"; - break; - case CryptoException.ILLEGAL_USE: - str = "ILLEGAL_USE"; - break; - case ECTesterApplet.SW_SIG_VERIFY_FAIL: - str = "SIG_VERIFY_FAIL"; - break; - case ECTesterApplet.SW_DH_DHC_MISMATCH: - str = "DH_DHC_MISMATCH"; - break; - case ECTesterApplet.SW_KEYPAIR_NULL: - str = "KEYPAIR_NULL"; - break; - case ECTesterApplet.SW_KA_NULL: - str = "KA_NULL"; - break; - case ECTesterApplet.SW_SIGNATURE_NULL: - str = "SIGNATURE_NULL"; - break; - case ECTesterApplet.SW_OBJECT_NULL: - str = "OBJECT_NULL"; - break; - default: - str = "unknown"; - break; - } - return str; - } - - public static String getSWString(short sw) { - if (sw == ISO7816.SW_NO_ERROR) { - return "OK (0x9000)"; - } else { - String str = getSW(sw); - return String.format("fail (%s, 0x%04x)", str, sw); - } - } - - public static String getCorruption(short corruptionType) { - String corrupt; - switch (corruptionType) { - case EC_Consts.CORRUPTION_NONE: - corrupt = "NONE"; - break; - case EC_Consts.CORRUPTION_FIXED: - corrupt = "FIXED"; - break; - case EC_Consts.CORRUPTION_ONE: - corrupt = "ONE"; - break; - case EC_Consts.CORRUPTION_ZERO: - corrupt = "ZERO"; - break; - case EC_Consts.CORRUPTION_ONEBYTERANDOM: - corrupt = "ONE_BYTE_RANDOM"; - break; - case EC_Consts.CORRUPTION_FULLRANDOM: - corrupt = "FULL_RANDOM"; - break; - case EC_Consts.CORRUPTION_INCREMENT: - corrupt = "INCREMENT"; - break; - case EC_Consts.CORRUPTION_INFINITY: - corrupt = "INFINITY"; - break; - case EC_Consts.CORRUPTION_COMPRESS: - corrupt = "COMPRESSED"; - break; - case EC_Consts.CORRUPTION_MAX: - corrupt = "MAX"; - break; - default: - corrupt = "unknown"; - break; - } - return corrupt; - } - - public static String getKA(byte ka) { - String algo = ""; - if ((ka & EC_Consts.KA_ECDH) != 0 || ka == EC_Consts.KA_ANY) { - algo += "ECDH"; - } - if (ka == EC_Consts.KA_BOTH) { - algo += "+"; - } else if (ka == EC_Consts.KA_ANY) { - algo += "/"; - } - if ((ka & EC_Consts.KA_ECDHC) != 0 || ka == EC_Consts.KA_ANY) { - algo += "ECDHC"; - } - return algo; - } - - public static String getKATypeString(byte kaType) { - String kaTypeString = "unknown"; - switch (kaType) { - case KeyAgreement_ALG_EC_SVDP_DH: - kaTypeString = "ALG_EC_SVDP_DH"; - break; - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN: - kaTypeString = "ALG_EC_SVDP_DH_PLAIN"; - break; - case KeyAgreement_ALG_EC_PACE_GM: - kaTypeString = "ALG_EC_PACE_GM"; - break; - case KeyAgreement_ALG_EC_SVDP_DH_PLAIN_XY: - kaTypeString = "ALG_EC_SVDP_DH_PLAIN_XY"; - break; - case KeyAgreement_ALG_EC_SVDP_DHC: - kaTypeString = "ALG_EC_SVDP_DHC"; - break; - case KeyAgreement_ALG_EC_SVDP_DHC_PLAIN: - kaTypeString = "ALG_EC_SVDP_DHC_PLAIN"; - break; - default: - kaTypeString = "unknown"; - } - return kaTypeString; - } -} diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java index 3c11456..5a6906c 100644 --- a/src/cz/crcs/ectester/reader/command/Command.java +++ b/src/cz/crcs/ectester/reader/command/Command.java @@ -2,15 +2,15 @@ package cz.crcs.ectester.reader.command; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.util.ByteUtil; import cz.crcs.ectester.data.EC_Store; import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; +import cz.crcs.ectester.reader.ECTesterReader; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.Util; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; -import cz.crcs.ectester.reader.ec.EC_Keypair; -import cz.crcs.ectester.reader.ec.EC_Params; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.ec.EC_Keypair; +import cz.crcs.ectester.common.ec.EC_Params; import javacard.security.KeyPair; import javax.smartcardio.CardException; @@ -54,7 +54,7 @@ public abstract class Command { * @return a Command to send in order to prepare the curve on the keypairs. * @throws IOException if curve file cannot be found/opened */ - public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { + public static Command prepareCurve(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException { if (cfg.customCurve) { // Set custom curve (one of the SECG curves embedded applet-side) @@ -109,7 +109,7 @@ public abstract class Command { * @return a CommandAPDU setting params loaded on the keyPair/s * @throws IOException if any of the key files cannot be found/opened */ - public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTester.Config cfg, byte keyPair) throws IOException { + public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair) throws IOException { short params = EC_Consts.PARAMETERS_NONE; byte[] data = null; @@ -174,7 +174,7 @@ public abstract class Command { if (privkey == null) { throw new IOException("Couldn't read the private key file correctly."); } - data = Util.concatenate(data, privkey); + data = ByteUtil.concatenate(data, privkey); } return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data); } @@ -203,7 +203,7 @@ public abstract class Command { this.keyClass = keyClass; byte[] data = new byte[]{0, 0, keyClass}; - Util.setShort(data, 0, keyLength); + ByteUtil.setShort(data, 0, keyLength); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, 0x00, data); } @@ -214,13 +214,19 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Allocate(response, elapsed, keyPair, keyLength, keyClass); } + + @Override + public String toString() { + return "Allocate"; + } } - - public static class AllocateKeyAgreement extends Command { + /** + * + */ + public static class AllocateKeyAgreement extends Command { private byte kaType; - /** * Creates the INS_ALLOCATE_KA instruction. * @@ -241,7 +247,45 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.AllocateKeyAgreement(response, elapsed, kaType); } - } + + @Override + public String toString() { + return "AllocateKeyAgreement"; + } + } + + /** + * + */ + public static class AllocateSignature extends Command { + private byte sigType; + + /** + * Creates the INS_ALLOCATE_SIG instruction. + * + * @param cardManager cardManager to send APDU through + * @param sigType which type of Signature to use + */ + public AllocateSignature(CardMngr cardManager, byte sigType) { + super(cardManager); + this.sigType = sigType; + byte[] data = new byte[]{sigType}; + this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_SIG, 0x00, 0x00, data); + } + + @Override + public Response.AllocateSignature send() throws CardException { + long elapsed = -System.nanoTime(); + ResponseAPDU response = cardManager.send(cmd); + elapsed += System.nanoTime(); + return new Response.AllocateSignature(response, elapsed, sigType); + } + + @Override + public String toString() { + return "AllocateSignature"; + } + } /** * @@ -267,6 +311,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Clear(response, elapsed, keyPair); } + + @Override + public String toString() { + return "Clear"; + } } /** @@ -296,7 +345,7 @@ public abstract class Command { int len = external != null ? 2 + external.length : 2; byte[] data = new byte[len]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); if (external != null) { System.arraycopy(external, 0, data, 2, external.length); } @@ -311,6 +360,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Set(response, elapsed, keyPair, curve, params); } + + @Override + public String toString() { + return "Set"; + } } /** @@ -337,7 +391,7 @@ public abstract class Command { this.corruption = corruption; byte[] data = new byte[3]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); data[2] = corruption; this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CORRUPT, keyPair, key, data); @@ -350,6 +404,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Corrupt(response, elapsed, keyPair, key, params, corruption); } + + @Override + public String toString() { + return "Corrupt"; + } } /** @@ -378,6 +437,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Generate(response, elapsed, keyPair); } + + @Override + public String toString() { + return "Generate"; + } } /** @@ -403,7 +467,7 @@ public abstract class Command { this.params = params; byte[] data = new byte[2]; - Util.setShort(data, 0, params); + ByteUtil.setShort(data, 0, params); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_EXPORT, keyPair, key, data); } @@ -415,6 +479,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Export(response, elapsed, keyPair, key, params); } + + @Override + public String toString() { + return "Export"; + } } /** @@ -446,7 +515,7 @@ public abstract class Command { this.type = type; byte[] data = new byte[]{export, 0,0, type}; - Util.setShort(data, 1, corruption); + ByteUtil.setShort(data, 1, corruption); this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH, pubkey, privkey, data); } @@ -458,6 +527,11 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.ECDH(response, elapsed, pubkey, privkey, export, corruption, type); } + + @Override + public String toString() { + return "ECDH"; + } } /** @@ -477,7 +551,7 @@ public abstract class Command { * @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 (EC_Consts.CORRUPTION_* | ...) - * @param type ECDH algorithm type (EC_Consts.KA_* | ...) + * @param type EC KeyAgreement type * @param pubkey pubkey data to do ECDH with. */ public ECDH_direct(CardMngr cardManager, byte privkey, byte export, short corruption, byte type, byte[] pubkey) { @@ -489,7 +563,7 @@ public abstract class Command { this.pubkey = pubkey; byte[] data = new byte[3 + pubkey.length]; - Util.setShort(data, 0, corruption); + ByteUtil.setShort(data, 0, corruption); data[2] = type; System.arraycopy(pubkey, 0, data, 3, pubkey.length); @@ -503,10 +577,16 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.ECDH(response, elapsed, ECTesterApplet.KEYPAIR_REMOTE, privkey, export, corruption, type); } + + @Override + public String toString() { + return "ECDH_direct"; + } } public static class ECDSA extends Command { private byte keyPair; + private byte sigType; private byte export; private byte[] raw; @@ -515,20 +595,23 @@ public abstract class Command { * * @param cardManager cardManager to send APDU through * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE) + * @param sigType Signature type to use * @param export whether to export ECDSA signature * @param raw data to sign, can be null, in which case random data is signed. */ - public ECDSA(CardMngr cardManager, byte keyPair, byte export, byte[] raw) { + public ECDSA(CardMngr cardManager, byte keyPair, byte sigType, byte export, byte[] raw) { super(cardManager); this.keyPair = keyPair; + this.sigType = sigType; this.export = export; this.raw = raw; int len = raw != null ? raw.length : 0; - byte[] data = new byte[2 + len]; - Util.setShort(data, 0, (short) len); + byte[] data = new byte[3 + len]; + data[0] = sigType; + ByteUtil.setShort(data, 1, (short) len); if (raw != null) { - System.arraycopy(raw, 0, data, 2, len); + System.arraycopy(raw, 0, data, 3, len); } this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDSA, keyPair, export, data); @@ -539,7 +622,12 @@ public abstract class Command { long elapsed = -System.nanoTime(); ResponseAPDU response = cardManager.send(cmd); elapsed += System.nanoTime(); - return new Response.ECDSA(response, elapsed, keyPair, export, raw); + return new Response.ECDSA(response, elapsed, keyPair, sigType, export, raw); + } + + @Override + public String toString() { + return "ECDSA"; } } @@ -564,28 +652,10 @@ public abstract class Command { elapsed += System.nanoTime(); return new Response.Cleanup(response, elapsed); } - } - - /** - * - */ - public static class Support extends Command { - - /** - * @param cardManager cardManager to send APDU through - */ - public Support(CardMngr cardManager) { - super(cardManager); - - this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SUPPORT, 0, 0); - } @Override - public Response.Support send() throws CardException { - long elapsed = -System.nanoTime(); - ResponseAPDU response = cardManager.send(cmd); - elapsed += System.nanoTime(); - return new Response.Support(response, elapsed); + public String toString() { + return "Cleanup"; } } } diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java deleted file mode 100644 index cb4a2df..0000000 --- a/src/cz/crcs/ectester/reader/ec/EC_Curve.java +++ /dev/null @@ -1,52 +0,0 @@ -package cz.crcs.ectester.reader.ec; - -import cz.crcs.ectester.applet.EC_Consts; -import javacard.security.KeyPair; - -/** - * An Elliptic curve, contains parameters Fp/F2M, A, B, G, R, (K)?. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public class EC_Curve extends EC_Params { - private short bits; - private byte field; - private String desc; - - /** - * @param bits - * @param field KeyPair.ALG_EC_FP or KeyPair.ALG_EC_F2M - */ - public EC_Curve(short bits, byte field) { - super(field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M); - this.bits = bits; - this.field = field; - } - - public EC_Curve(String id, short bits, byte field) { - this(bits, field); - this.id = id; - } - - public EC_Curve(String id, short bits, byte field, String desc) { - this(id, bits, field); - this.desc = desc; - } - - public short getBits() { - return bits; - } - - public byte getField() { - return field; - } - - public String getDesc() { - return desc; - } - - @Override - public String toString() { - return "<" + getId() + "> " + (field == KeyPair.ALG_EC_FP ? "Prime" : "Binary") + " field Elliptic curve (" + String.valueOf(bits) + "b)" + (desc == null ? "" : ": " + desc); - } -} diff --git a/src/cz/crcs/ectester/reader/output/ResponseWriter.java b/src/cz/crcs/ectester/reader/output/ResponseWriter.java index c357233..85bf79a 100644 --- a/src/cz/crcs/ectester/reader/output/ResponseWriter.java +++ b/src/cz/crcs/ectester/reader/output/ResponseWriter.java @@ -1,6 +1,6 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.util.CardUtil; import cz.crcs.ectester.reader.response.Response; import java.io.PrintStream; @@ -20,20 +20,24 @@ public class ResponseWriter { for (int j = 0; j < r.getNumSW(); ++j) { short sw = r.getSW(j); if (sw != 0) { - suffix.append(" ").append(Util.getSWString(sw)); + suffix.append(" ").append(CardUtil.getSWString(sw)); } } if (suffix.length() == 0) { - suffix.append(" [").append(Util.getSW(r.getNaturalSW())).append("]"); + suffix.append(" [").append(CardUtil.getSW(r.getNaturalSW())).append(String.format(" 0x%04x", r.getNaturalSW())).append("]"); } return String.format("%4d ms ┃ %s", r.getDuration() / 1000000, suffix); } - public void outputResponse(Response r) { + public String responseString(Response r) { String out = ""; out += String.format("%-70s", r.getDescription()) + " ┃ "; out += responseSuffix(r); - output.println(out); + return out; + } + + public void outputResponse(Response r) { + output.println(responseString(r)); output.flush(); } } diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java index bcebcd5..eb52937 100644 --- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/TextTestWriter.java @@ -1,85 +1,57 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.test.Test; -import cz.crcs.ectester.reader.test.TestSuite; +import cz.crcs.ectester.common.output.BaseTextTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.test.CardTestSuite; +import cz.crcs.ectester.reader.test.CommandTestable; +import javax.smartcardio.CardException; import java.io.PrintStream; +import java.util.Map; /** * @author Jan Jancar johny@neuromancer.sk */ -public class TextTestWriter implements TestWriter { - private PrintStream output; - private ResponseWriter respWriter; - - public static int BASE_WIDTH = 76; +public class TextTestWriter extends BaseTextTestWriter { + private ResponseWriter writer; public TextTestWriter(PrintStream output) { - this.output = output; - this.respWriter = new ResponseWriter(output); + super(output); + this.writer = new ResponseWriter(output); } @Override - public void begin(TestSuite suite) { - output.println("=== Running test suite: " + suite.getName() + " ==="); - output.println("=== " + suite.getDescription()); - } - - private String testString(Test t, int offset) { - if (!t.hasRun()) { - return null; + protected String testableString(Testable t) { + if (t instanceof CommandTestable) { + CommandTestable cmd = (CommandTestable) t; + return writer.responseSuffix(cmd.getResponse()); } + return ""; + } - StringBuilder out = new StringBuilder(); - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; - out.append(test.ok() ? "OK " : "NOK "); - out.append("━ "); - int width = BASE_WIDTH - (offset + out.length()); - String widthSpec = "%-" + String.valueOf(width) + "s"; - out.append(String.format(widthSpec, t.getDescription())); - out.append(" ┃ "); - out.append(String.format("%-9s", test.getResultValue().name())); - out.append(" ┃ "); - out.append(respWriter.responseSuffix(test.getResponse())); - } else { - Test.Compound test = (Test.Compound) t; - out.append(test.ok() ? "OK " : "NOK "); - out.append("┳ "); - int width = BASE_WIDTH - (offset + out.length()); - String widthSpec = "%-" + String.valueOf(width) + "s"; - out.append(String.format(widthSpec, t.getDescription())); - out.append(" ┃ "); - out.append(String.format("%-9s", test.getResultValue().name())); - out.append(" ┃ "); - out.append(test.getResultCause()); - out.append(System.lineSeparator()); - Test[] tests = test.getTests(); - for (int i = 0; i < tests.length; ++i) { - if (i == tests.length - 1) { - out.append(" ┗ "); - } else { - out.append(" ┣ "); - } - out.append(testString(tests[i], offset + 6)); - if (i != tests.length - 1) { - out.append(System.lineSeparator()); + @Override + protected String deviceString(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + StringBuilder sb = new StringBuilder(); + sb.append("═══ Card ATR: ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator()); + try { + CardMngr.CPLC cplc = cardSuite.getCard().getCPLC(); + if (!cplc.values().isEmpty()) { + sb.append("═══ Card CPLC data:").append(System.lineSeparator()); + for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + sb.append("═══ ").append(field.name()).append(": ").append(CardMngr.mapCPLCField(field, value)); + } } + } catch (CardException ignored) { } + return sb.toString(); } - - return out.toString(); - } - - @Override - public void outputTest(Test t) { - if (!t.hasRun()) - return; - output.println(testString(t, 0)); - output.flush(); - } - - @Override - public void end() { + return ""; } } diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java index beb758c..d3674e8 100644 --- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java @@ -1,55 +1,34 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.output.BaseXMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.test.Test; -import cz.crcs.ectester.reader.test.TestSuite; -import org.w3c.dom.Document; +import cz.crcs.ectester.reader.test.CardTestSuite; +import cz.crcs.ectester.reader.test.CommandTestable; import org.w3c.dom.Element; -import org.w3c.dom.Node; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import javax.smartcardio.CardException; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; import java.io.OutputStream; +import java.util.Map; /** * @author Jan Jancar johny@neuromancer.sk */ -public class XMLTestWriter implements TestWriter { - private OutputStream output; - private DocumentBuilder db; - private Document doc; - private Node root; - +public class XMLTestWriter extends BaseXMLTestWriter { public XMLTestWriter(OutputStream output) throws ParserConfigurationException { - this.output = output; - this.db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - } - - @Override - public void begin(TestSuite suite) { - doc = db.newDocument(); - Element rootElem = doc.createElement("testSuite"); - rootElem.setAttribute("name", suite.getName()); - rootElem.setAttribute("desc", suite.getDescription()); - - root = rootElem; - doc.appendChild(root); + super(output); } private Element commandElement(Command c) { Element commandElem = doc.createElement("command"); Element apdu = doc.createElement("apdu"); - apdu.setTextContent(Util.bytesToHex(c.getAPDU().getBytes())); + apdu.setTextContent(ByteUtil.bytesToHex(c.getAPDU().getBytes())); commandElem.appendChild(apdu); return commandElem; @@ -60,7 +39,7 @@ public class XMLTestWriter implements TestWriter { responseElem.setAttribute("successful", r.successful() ? "true" : "false"); Element apdu = doc.createElement("apdu"); - apdu.setTextContent(Util.bytesToHex(r.getAPDU().getBytes())); + apdu.setTextContent(ByteUtil.bytesToHex(r.getAPDU().getBytes())); responseElem.appendChild(apdu); Element naturalSW = doc.createElement("natural-sw"); @@ -86,60 +65,50 @@ public class XMLTestWriter implements TestWriter { return responseElem; } - private Element testElement(Test t) { - Element testElem = doc.createElement("test"); + @Override + protected Element testableElement(Testable t) { + if (t instanceof CommandTestable) { + CommandTestable cmd = (CommandTestable) t; + Element result = doc.createElement("test"); + result.setAttribute("type", "command"); + result.appendChild(commandElement(cmd.getCommand())); + result.appendChild(responseElement(cmd.getResponse())); + return result; + } + return null; + } - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; - testElem.setAttribute("type", "simple"); - testElem.appendChild(commandElement(test.getCommand())); - testElem.appendChild(responseElement(test.getResponse())); - } else if (t instanceof Test.Compound) { - Test.Compound test = (Test.Compound) t; - testElem.setAttribute("type", "compound"); - for (Test innerTest : test.getTests()) { - testElem.appendChild(testElement(innerTest)); + private Element cplcElement(CardMngr card) { + Element result = doc.createElement("cplc"); + try { + CardMngr.CPLC cplc = card.getCPLC(); + if (!cplc.values().isEmpty()) { + for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + Element keyVal = doc.createElement(field.name()); + keyVal.setTextContent(ByteUtil.bytesToHex(value, false)); + result.appendChild(keyVal); + } } + } catch (CardException ignored) { } - - Element description = doc.createElement("desc"); - description.setTextContent(t.getDescription()); - testElem.appendChild(description); - - Element result = doc.createElement("result"); - Element ok = doc.createElement("ok"); - ok.setTextContent(String.valueOf(t.ok())); - Element value = doc.createElement("value"); - value.setTextContent(t.getResultValue().name()); - Element cause = doc.createElement("cause"); - cause.setTextContent(t.getResultCause()); - result.appendChild(ok); - result.appendChild(value); - result.appendChild(cause); - testElem.appendChild(result); - - return testElem; + return result; } @Override - public void outputTest(Test t) { - if (!t.hasRun()) - return; - root.appendChild(testElement(t)); - } + protected Element deviceElement(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + Element result = doc.createElement("device"); + result.setAttribute("type", "card"); + result.appendChild(cplcElement(cardSuite.getCard())); - @Override - public void end() { - try { - DOMSource domSource = new DOMSource(doc); - StreamResult result = new StreamResult(output); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); - transformer.transform(domSource, result); - } catch (TransformerException e) { - e.printStackTrace(); + Element atr = doc.createElement("ATR"); + atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)); + result.appendChild(atr); + return result; } + return null; } }
\ No newline at end of file diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java index 3b2b72d..199f2c0 100644 --- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java +++ b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java @@ -1,13 +1,16 @@ package cz.crcs.ectester.reader.output; -import cz.crcs.ectester.reader.Util; +import cz.crcs.ectester.common.output.BaseYAMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.reader.CardMngr; import cz.crcs.ectester.reader.command.Command; import cz.crcs.ectester.reader.response.Response; -import cz.crcs.ectester.reader.test.Test; -import cz.crcs.ectester.reader.test.TestSuite; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; +import cz.crcs.ectester.reader.test.CardTestSuite; +import cz.crcs.ectester.reader.test.CommandTestable; +import javax.smartcardio.CardException; import java.io.PrintStream; import java.util.HashMap; import java.util.LinkedList; @@ -17,39 +20,21 @@ import java.util.Map; /** * @author Jan Jancar johny@neuromancer.sk */ -public class YAMLTestWriter implements TestWriter { - private PrintStream output; - private Map<String, Object> testRun; - private Map<String, String> testSuite; - private List<Object> tests; - +public class YAMLTestWriter extends BaseYAMLTestWriter { public YAMLTestWriter(PrintStream output) { - this.output = output; - } - - @Override - public void begin(TestSuite suite) { - output.println("---"); - testRun = new HashMap<>(); - testSuite = new HashMap<>(); - tests = new LinkedList<>(); - testSuite.put("name", suite.getName()); - testSuite.put("desc", suite.getDescription()); - - testRun.put("suite", testSuite); - testRun.put("tests", tests); + super(output); } private Map<String, Object> commandObject(Command c) { Map<String, Object> commandObj = new HashMap<>(); - commandObj.put("apdu", Util.bytesToHex(c.getAPDU().getBytes())); + commandObj.put("apdu", ByteUtil.bytesToHex(c.getAPDU().getBytes())); return commandObj; } private Map<String, Object> responseObject(Response r) { Map<String, Object> responseObj = new HashMap<>(); responseObj.put("successful", r.successful()); - responseObj.put("apdu", Util.bytesToHex(r.getAPDU().getBytes())); + responseObj.put("apdu", ByteUtil.bytesToHex(r.getAPDU().getBytes())); responseObj.put("natural_sw", Short.toUnsignedInt(r.getNaturalSW())); List<Integer> sws = new LinkedList<>(); for (int i = 0; i < r.getNumSW(); ++i) { @@ -61,53 +46,45 @@ public class YAMLTestWriter implements TestWriter { return responseObj; } - private Map<String, Object> testObject(Test t) { - Map<String, Object> testObj = new HashMap<>(); - - if (t instanceof Test.Simple) { - Test.Simple test = (Test.Simple) t; - testObj.put("type", "simple"); - testObj.put("command", commandObject(test.getCommand())); - testObj.put("response", responseObject(test.getResponse())); - } else if (t instanceof Test.Compound) { - Test.Compound test = (Test.Compound) t; - testObj.put("type", "compound"); - List<Map<String, Object>> tests = new LinkedList<>(); - for (Test innerTest : test.getTests()) { - tests.add(testObject(innerTest)); - } - testObj.put("tests", tests); + @Override + protected Map<String, Object> testableObject(Testable t) { + if (t instanceof CommandTestable) { + CommandTestable cmd = (CommandTestable) t; + Map<String, Object> result = new HashMap<>(); + result.put("type", "command"); + result.put("command", commandObject(cmd.getCommand())); + result.put("response", responseObject(cmd.getResponse())); + return result; } - - testObj.put("desc", t.getDescription()); - Map<String, Object> result = new HashMap<>(); - result.put("ok", t.ok()); - result.put("value", t.getResultValue().name()); - result.put("cause", t.getResultCause()); - testObj.put("result", result); - - return testObj; + return null; } - @Override - public void outputTest(Test t) { - if (!t.hasRun()) - return; - tests.add(testObject(t)); + private Map<String, Object> cplcObject(CardMngr card) { + Map<String, Object> result = new HashMap<>(); + try { + CardMngr.CPLC cplc = card.getCPLC(); + if (!cplc.values().isEmpty()) { + for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) { + CardMngr.CPLC.Field field = entry.getKey(); + byte[] value = entry.getValue(); + result.put(field.name(), ByteUtil.bytesToHex(value, false)); + } + } + } catch (CardException ignored) { + } + return result; } @Override - public void end() { - DumperOptions options = new DumperOptions(); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - options.setPrettyFlow(true); - Yaml yaml = new Yaml(options); - - Map<String, Object> result = new HashMap<>(); - result.put("testRun", testRun); - String out = yaml.dump(result); - - output.println(out); - output.println("---"); + protected Map<String, Object> deviceObject(TestSuite suite) { + if (suite instanceof CardTestSuite) { + CardTestSuite cardSuite = (CardTestSuite) suite; + Map<String, Object> result = new HashMap<>(); + result.put("type", "card"); + result.put("cplc", cplcObject(cardSuite.getCard())); + result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)); + return result; + } + return null; } } diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java index 4abfd14..cbed3b2 100644 --- a/src/cz/crcs/ectester/reader/response/Response.java +++ b/src/cz/crcs/ectester/reader/response/Response.java @@ -2,8 +2,8 @@ package cz.crcs.ectester.reader.response; import cz.crcs.ectester.applet.ECTesterApplet; import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.reader.Util; -import cz.crcs.ectester.reader.ec.EC_Data; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.CardUtil; import javacard.framework.ISO7816; import javacard.security.KeyPair; @@ -13,7 +13,6 @@ import javax.smartcardio.ResponseAPDU; * @author Jan Jancar johny@neuromancer.sk */ public abstract class Response { - private ResponseAPDU resp; private long time; private short[] sws; @@ -37,7 +36,7 @@ public abstract class Response { //parse SWs in response for (int i = 0; i < numSW; ++i) { if (getLength() >= (offset + 2)) { - short sw = Util.getShort(data, offset); + short sw = ByteUtil.getShort(data, offset); offset += 2; sws[i] = sw; if (sw != ISO7816.SW_NO_ERROR) { @@ -63,7 +62,7 @@ public abstract class Response { error = true; break; } - short paramLength = Util.getShort(data, offset); + short paramLength = ByteUtil.getShort(data, offset); offset += 2; if (data.length < offset + paramLength) { error = true; @@ -88,6 +87,10 @@ public abstract class Response { return (short) resp.getSW(); } + public short[] getSWs() { + return sws; + } + public short getSW(int index) { return sws[index]; } @@ -130,24 +133,44 @@ public abstract class Response { * */ public static class AllocateKeyAgreement extends Response { - byte kaType; + private byte kaType; public AllocateKeyAgreement(ResponseAPDU response, long time, byte kaType) { super(response, time); this.kaType = kaType; - parse(2, 0); + parse(1, 0); } @Override public String getDescription() { - return String.format("Allocated KeyAgreement(%s) object", Util.getKATypeString(this.kaType)); + return String.format("Allocated KeyAgreement(%s) object", CardUtil.getKATypeString(this.kaType)); } + } + + /** + * + */ + public static class AllocateSignature extends Response { + private byte sigType; + + public AllocateSignature(ResponseAPDU response, long time, byte sigType) { + super(response, time); + this.sigType = sigType; + parse(1, 0); + } + + @Override + public String getDescription() { + return String.format("Allocated Signature(%s) object", CardUtil.getSigTypeString(this.sigType)); + } } + /** + * + */ public static class Allocate extends Response { - private byte keyPair; private short keyLength; private byte keyClass; @@ -181,7 +204,6 @@ public abstract class Response { * */ public static class Clear extends Response { - private byte keyPair; public Clear(ResponseAPDU response, long time, byte keyPair) { @@ -210,7 +232,6 @@ public abstract class Response { * */ public static class Set extends Response { - private byte keyPair; private byte curve; private short parameters; @@ -268,7 +289,6 @@ public abstract class Response { * */ public static class Corrupt extends Response { - private byte keyPair; private byte key; private short params; @@ -290,7 +310,7 @@ public abstract class Response { @Override public String getDescription() { - String corrupt = Util.getCorruption(corruption); + String corrupt = CardUtil.getCorruption(corruption); String pair; if (keyPair == ECTesterApplet.KEYPAIR_BOTH) { @@ -306,7 +326,6 @@ public abstract class Response { * */ public static class Generate extends Response { - private byte keyPair; public Generate(ResponseAPDU response, long time, byte keyPair) { @@ -336,7 +355,6 @@ public abstract class Response { * */ public static class Export extends Response { - private byte keyPair; private byte key; private short parameters; @@ -445,7 +463,6 @@ public abstract class Response { * */ public static class ECDH extends Response { - private byte pubkey; private byte privkey; private byte export; @@ -477,7 +494,7 @@ public abstract class Response { @Override public String getDescription() { - String algo = Util.getKA(type); + String algo = CardUtil.getKATypeString(type); String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; @@ -486,7 +503,7 @@ public abstract class Response { if (corruption == EC_Consts.CORRUPTION_NONE) { validity = "unchanged"; } else { - validity = Util.getCorruption(corruption); + validity = CardUtil.getCorruption(corruption); } return String.format("%s of %s pubkey and %s privkey(%s point)", algo, pub, priv, validity); } @@ -496,14 +513,15 @@ public abstract class Response { * */ public static class ECDSA extends Response { - private byte keyPair; + private byte sigType; private byte export; private byte[] raw; - public ECDSA(ResponseAPDU response, long time, byte keyPair, byte export, byte[] raw) { + public ECDSA(ResponseAPDU response, long time, byte keyPair, byte sigType, byte export, byte[] raw) { super(response, time); this.keyPair = keyPair; + this.sigType = sigType; this.export = export; this.raw = raw; @@ -520,9 +538,10 @@ public abstract class Response { @Override public String getDescription() { + String algo = CardUtil.getSigTypeString(sigType); String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote"; String data = raw == null ? "random" : "provided"; - return String.format("ECDSA with %s keypair(%s data)", key, data); + return String.format("%s with %s keypair(%s data)", algo, key, data); } } @@ -543,21 +562,4 @@ public abstract class Response { } } - - /** - * - */ - public static class Support extends Response { - - public Support(ResponseAPDU response, long time) { - super(response, time); - - parse(3, 0); - } - - @Override - public String getDescription() { - return "Support of ECDH, ECDHC, ECDSA allocation"; - } - } } diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java new file mode 100644 index 0000000..a53806c --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardCompositeCurvesSuite.java @@ -0,0 +1,51 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import javacard.security.KeyPair; + +import java.util.Map; + +import static cz.crcs.ectester.common.test.Result.ExpectedValue; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardCompositeCurvesSuite extends CardTestSuite { + + public CardCompositeCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "composite", "The composite suite run ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe."); + } + + @Override + protected void runTests() throws Exception { + /* Do the default run with the public keys set to provided smallorder keys + * over composite order curves. Essentially small subgroup attacks. + * These should fail, the curves aren't safe so that if the computation with + * a small order public key succeeds the private key modulo the public key order + * is revealed. + */ + Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite"); + for (EC_Key key : keys.values()) { + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve()); + if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { + continue; + } + if ((curve.getBits() == cfg.bits || cfg.all)) { + doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); + doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); + Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, key.flatten()); + doTest(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); + new Command.Cleanup(this.card).send(); + } + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java new file mode 100644 index 0000000..c3bd9c8 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java @@ -0,0 +1,94 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.common.util.CardUtil; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import javacard.security.KeyPair; + +import java.util.LinkedList; +import java.util.List; + +import static cz.crcs.ectester.common.test.Result.ExpectedValue; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardDefaultSuite extends CardTestSuite { + + public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "default", "The default test suite run basic support of ECDH and ECDSA."); + } + + @Override + protected void runTests() throws Exception { + if (cfg.primeField) { + runDefault(KeyPair.ALG_EC_FP); + } + if (cfg.binaryField) { + runDefault(KeyPair.ALG_EC_F2M); + } + } + + private void runDefault(byte field) throws Exception { + short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES; + for (short keyLength : keySizes) { + String description = "Tests of " + keyLength + "b " + (field == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M") + " support."; + + List<Test> supportTests = new LinkedList<>(); + Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS)); + if (!key.ok()) { + doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " None.", key)); + continue; + } + supportTests.add(key); + + Test genDefault = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); + Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS)); + Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); + supportTests.add(genDefault); + supportTests.add(setCustom); + supportTests.add(genCustom); + + for (byte kaType : EC_Consts.KA_TYPES) { + Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS)); + if (allocate.ok()) { + Command ecdh = new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType); + Test ka = runTest(CommandTest.expect(ecdh, ExpectedValue.SUCCESS)); + Test kaCompressed = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, kaType), ExpectedValue.SUCCESS)); + Test perfTest = null; + if (ka.ok()) { + perfTest = runTest(PerformanceTest.repeat(ecdh, 10)); + } + Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.", allocate, ka, kaCompressed, perfTest)); + supportTests.add(compound); + } else { + runTest(allocate); + supportTests.add(allocate); + } + } + for (byte sigType : EC_Consts.SIG_TYPES) { + Test allocate = runTest(CommandTest.expect(new Command.AllocateSignature(this.card, sigType), ExpectedValue.SUCCESS)); + if (allocate.ok()) { + Command ecdsa = new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_FALSE, null); + Test expect = runTest(CommandTest.expect(ecdsa, ExpectedValue.SUCCESS)); + Test perfTest = null; + if (expect.ok()) { + perfTest = runTest(PerformanceTest.repeat(ecdsa, 10)); + } + Test compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.", allocate, expect, perfTest)); + supportTests.add(compound); + } else { + supportTests.add(allocate); + } + } + doTest(CompoundTest.all(ExpectedValue.SUCCESS, description + " Some.", supportTests.toArray(new Test[0]))); + new Command.Cleanup(this.card).send(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java new file mode 100644 index 0000000..8424d45 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardInvalidCurvesSuite.java @@ -0,0 +1,67 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import javacard.security.KeyPair; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static cz.crcs.ectester.common.test.Result.ExpectedValue; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardInvalidCurvesSuite extends CardTestSuite { + + public CardInvalidCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH."); + } + + @Override + protected void runTests() throws Exception { + /* Set original curves (secg/nist/brainpool). Generate local. + * Try ECDH with invalid public keys of increasing (or decreasing) order. + */ + Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid"); + Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>(); + for (EC_Key.Public key : pubkeys.values()) { + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve()); + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { + continue; + } + List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>()); + keys.add(key); + curves.putIfAbsent(curve, keys); + } + for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) { + EC_Curve curve = e.getKey(); + List<EC_Key.Public> keys = e.getValue(); + + doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); + List<Test> ecdhTests = new LinkedList<>(); + for (EC_Key.Public pub : keys) { + Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); + ecdhTests.add(CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve.")); + } + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); + new Command.Cleanup(this.card).send(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java new file mode 100644 index 0000000..0eccd16 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardTestSuite.java @@ -0,0 +1,24 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class CardTestSuite extends TestSuite { + ECTesterReader.Config cfg; + CardMngr card; + + CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String description) { + super(writer, name, description); + this.card = cardManager; + this.cfg = cfg; + } + + public CardMngr getCard() { + return card; + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java new file mode 100644 index 0000000..73c6621 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java @@ -0,0 +1,83 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.*; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.*; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; +import javacard.security.KeyPair; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static cz.crcs.ectester.common.test.Result.ExpectedValue; +import static cz.crcs.ectester.common.test.Result.Value; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardTestVectorSuite extends CardTestSuite { + + public CardTestVectorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness."); + } + + @Override + protected void runTests() throws Exception { + /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors. + * Do ECDH both ways, export and verify that the result is correct. + */ + Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test"); + for (EC_KAResult result : results.values()) { + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, result.getCurve()); + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { + continue; + } + EC_Params onekey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOneKey()); + if (onekey == null) { + onekey = EC_Store.getInstance().getObject(EC_Key.Private.class, result.getOneKey()); + } + EC_Params otherkey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOtherKey()); + if (otherkey == null) { + otherkey = EC_Store.getInstance().getObject(EC_Key.Public.class, result.getOtherKey()); + } + if (onekey == null || otherkey == null) { + throw new IOException("Test vector keys couldn't be located."); + } + List<Test> testVector = new LinkedList<>(); + + testVector.add(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); + testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); + testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); + testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); + testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getJavaCardKA()), new TestCallback<CommandTestable>() { + @Override + public Result apply(CommandTestable testable) { + Response.ECDH dh = (Response.ECDH) testable.getResponse(); + if (!dh.successful()) + return new Result(Value.FAILURE, "ECDH was unsuccessful."); + if (!dh.hasSecret()) + return new Result(Value.FAILURE, "ECDH response did not contain the derived secret."); + if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) { + int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength()); + return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + String.valueOf(firstDiff) + "."); + } + return new Result(Value.SUCCESS); + } + })); + doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); + new Command.Cleanup(this.card).send(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java new file mode 100644 index 0000000..c43b234 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardTwistTestSuite.java @@ -0,0 +1,62 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.ec.EC_Key; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import javacard.security.KeyPair; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardTwistTestSuite extends CardTestSuite { + public CardTwistTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "twist", "The twist test suite tests whether the card correctly rejects points on the quadratic twist of the curve during ECDH."); + } + + @Override + protected void runTests() throws Exception { + Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist"); + Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>(); + for (EC_Key.Public key : pubkeys.values()) { + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve()); + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { + continue; + } + List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>()); + keys.add(key); + curves.putIfAbsent(curve, keys); + } + for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) { + EC_Curve curve = e.getKey(); + List<EC_Key.Public> keys = e.getValue(); + + doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); + doTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS)); + doTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS)); + List<Test> ecdhTests = new LinkedList<>(); + for (EC_Key.Public pub : keys) { + Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, ECTesterApplet.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten()); + ecdhTests.add(CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist.")); + } + doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); + new Command.Cleanup(this.card).send(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java new file mode 100644 index 0000000..cac8fab --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CardWrongCurvesSuite.java @@ -0,0 +1,58 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.applet.ECTesterApplet; +import cz.crcs.ectester.applet.EC_Consts; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.CompoundTest; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.Test; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.reader.CardMngr; +import cz.crcs.ectester.reader.ECTesterReader; +import cz.crcs.ectester.reader.command.Command; +import javacard.security.KeyPair; + +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CardWrongCurvesSuite extends CardTestSuite { + + public CardWrongCurvesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) { + super(writer, cfg, cardManager, "wrong", "The wrong curve suite run whether the card rejects domain parameters which are not curves."); + } + + @Override + protected void runTests() throws Exception { + /* Just do the default run on the wrong curves. + * These should generally fail, the curves aren't curves. + */ + Map<String, EC_Curve> curves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong"); + for (Map.Entry<String, EC_Curve> e : curves.entrySet()) { + EC_Curve curve = e.getValue(); + if (curve.getBits() != cfg.bits && !cfg.all) { + continue; + } + if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { + continue; + } + Test key = doTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS)); + if (!key.ok()) { + continue; + } + Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS)); + Test generate = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS)); + doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Set wrong curve and generate keypairs, should fail." ,set, generate)); + + for (byte kaType : EC_Consts.KA_TYPES) { + Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS)); + if (allocate.ok()) { + Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, kaType), Result.ExpectedValue.FAILURE)); + doTest(CompoundTest.any(Result.ExpectedValue.FAILURE, "Allocate and perform KA, should fail.", allocate, ka)); + } + } + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java new file mode 100644 index 0000000..a08d820 --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CommandTest.java @@ -0,0 +1,76 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; + +/** + * A simple test that runs one Command to get and evaluate one Response + * to get a Result and compare it with the expected one. + */ +public class CommandTest extends SimpleTest<CommandTestable> { + private CommandTest(CommandTestable command, TestCallback<CommandTestable> callback) { + super(command, callback); + } + + public static CommandTest function(CommandTestable command, TestCallback<CommandTestable> callback) { + return new CommandTest(command, callback); + } + + public static CommandTest function(Command command, TestCallback<CommandTestable> callback) { + return function(new CommandTestable(command), callback); + } + + public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected, String ok, String nok) { + return new CommandTest(command, new TestCallback<CommandTestable>() { + @Override + public Result apply(CommandTestable commandTestable) { + Response resp = commandTestable.getResponse(); + Result.Value resultValue = Result.Value.fromExpected(expected, resp.successful(), resp.error()); + return new Result(resultValue, resultValue.ok() ? ok : nok); + } + }); + } + + public static CommandTest expect(Command command, Result.ExpectedValue expectedValue, String ok, String nok) { + return expect(new CommandTestable(command), expectedValue, ok, nok); + } + + public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected) { + return expect(command, expected, null, null); + } + + public static CommandTest expect(Command command, Result.ExpectedValue expectedValue) { + return expect(command, expectedValue, null, null); + } + + public Command getCommand() { + return testable.getCommand(); + } + + public Response getResponse() { + return testable.getResponse(); + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + testable.run(); + result = callback.apply(testable); + hasRun = true; + } + + @Override + public String getDescription() { + if (hasRun) { + return testable.getResponse().getDescription(); + } else { + return testable.getCommand().toString(); + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CommandTestable.java b/src/cz/crcs/ectester/reader/test/CommandTestable.java new file mode 100644 index 0000000..3bb55bf --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/CommandTestable.java @@ -0,0 +1,44 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.test.BaseTestable; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.command.Command; +import cz.crcs.ectester.reader.response.Response; + +import javax.smartcardio.CardException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class CommandTestable extends BaseTestable { + private Command command; + private Response response; + + public CommandTestable(Command command) { + this.command = command; + } + + public Command getCommand() { + return command; + } + + public Response getResponse() { + return response; + } + + @Override + public void run() throws TestException { + try { + response = command.send(); + } catch (CardException e) { + throw new TestException(e); + } + + hasRun = true; + if (response.error()) { + error = true; + } else if (response.successful()) { + ok = true; + } + } +} diff --git a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java b/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java deleted file mode 100644 index 8e7ca31..0000000 --- a/src/cz/crcs/ectester/reader/test/CompositeCurvesSuite.java +++ /dev/null @@ -1,53 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; -import javacard.security.KeyPair; - -import java.util.Map; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class CompositeCurvesSuite extends TestSuite { - - public CompositeCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { - super(dataStore, cfg, "composite", "The composite suite tests ECDH over curves with composite order. This should generally fail, as using such a curve is unsafe."); - } - - @Override - public void setup(CardMngr cardManager) { - /* Do the default tests with the public keys set to provided smallorder keys - * over composite order curves. Essentially small subgroup attacks. - * These should fail, the curves aren't safe so that if the computation with - * a small order public key succeeds the private key modulo the public key order - * is revealed. - */ - Map<String, EC_Key> keys = dataStore.getObjects(EC_Key.class, "composite"); - for (EC_Key key : keys.values()) { - EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); - if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) { - continue; - } - if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { - continue; - } - if ((curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY)); - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.ANY)); - Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH, key.flatten()); - tests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.")); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); - } - } - } -} diff --git a/src/cz/crcs/ectester/reader/test/DefaultSuite.java b/src/cz/crcs/ectester/reader/test/DefaultSuite.java deleted file mode 100644 index 736b7c5..0000000 --- a/src/cz/crcs/ectester/reader/test/DefaultSuite.java +++ /dev/null @@ -1,69 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import cz.crcs.ectester.reader.command.Command; -import javacard.security.KeyPair; - -import java.io.IOException; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class DefaultSuite extends TestSuite { - - public DefaultSuite(EC_Store dataStore, ECTester.Config cfg) { - super(dataStore, cfg, "default", "The default test suite tests basic support of ECDH and ECDSA."); - } - - @Override - public void setup(CardMngr cardManager) throws IOException { - tests.add(new Test.Simple(new Command.Support(cardManager), ExpectedValue.ANY)); - if (cfg.namedCurve != null) { - String desc = "Default tests over the " + cfg.namedCurve + " curve category."; - if (cfg.primeField) { - tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_FP, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc)); - } - if (cfg.binaryField) { - tests.addAll(defaultCategoryTests(cardManager, cfg.namedCurve, KeyPair.ALG_EC_F2M, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, desc)); - } - } else { - if (cfg.all) { - if (cfg.primeField) { - //iterate over prime curve sizes used: EC_Consts.FP_SIZES - for (short keyLength : EC_Consts.FP_SIZES) { - defaultTests(cardManager, keyLength, KeyPair.ALG_EC_FP); - } - } - if (cfg.binaryField) { - //iterate over binary curve sizes used: EC_Consts.F2M_SIZES - for (short keyLength : EC_Consts.F2M_SIZES) { - defaultTests(cardManager, keyLength, KeyPair.ALG_EC_F2M); - } - } - } else { - if (cfg.primeField) { - defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_FP); - } - - if (cfg.binaryField) { - defaultTests(cardManager, (short) cfg.bits, KeyPair.ALG_EC_F2M); - } - } - } - } - - private void defaultTests(CardMngr cardManager, short keyLength, byte keyType) throws IOException { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType), ExpectedValue.SUCCESS)); - Command curve = Command.prepareCurve(cardManager, dataStore, cfg, ECTesterApplet.KEYPAIR_BOTH, keyLength, keyType); - if (curve != null) - tests.add(new Test.Simple(curve, ExpectedValue.SUCCESS)); - tests.add(defaultCurveTests(cardManager, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, "Default tests.")); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); - } -} diff --git a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java b/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java deleted file mode 100644 index f61b695..0000000 --- a/src/cz/crcs/ectester/reader/test/InvalidCurvesSuite.java +++ /dev/null @@ -1,68 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; -import cz.crcs.ectester.reader.ec.EC_Key; -import javacard.security.KeyPair; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class InvalidCurvesSuite extends TestSuite { - - public InvalidCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { - super(dataStore, cfg, "invalid", "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH."); - } - - @Override - public void setup(CardMngr cardManager) throws IOException { - /* Set original curves (secg/nist/brainpool). Generate local. - * Try ECDH with invalid public keys of increasing (or decreasing) order. - */ - Map<String, EC_Key.Public> pubkeys = dataStore.getObjects(EC_Key.Public.class, "invalid"); - Map<EC_Curve, List<EC_Key.Public>> curves = new HashMap<>(); - for (EC_Key.Public key : pubkeys.values()) { - EC_Curve curve = dataStore.getObject(EC_Curve.class, key.getCurve()); - if (cfg.namedCurve != null && !(key.getCurve().startsWith(cfg.namedCurve) || key.getCurve().equals(cfg.namedCurve))) { - continue; - } - if (curve.getBits() != cfg.bits && !cfg.all) { - continue; - } - if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { - continue; - } - List<EC_Key.Public> keys = curves.getOrDefault(curve, new LinkedList<>()); - keys.add(key); - curves.putIfAbsent(curve, keys); - } - for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curves.entrySet()) { - EC_Curve curve = e.getKey(); - List<EC_Key.Public> keys = e.getValue(); - - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS)); - List<Test> ecdhTests = new LinkedList<>(); - for (EC_Key.Public pub : keys) { - Command ecdhCommand = new Command.ECDH_direct(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ANY, pub.flatten()); - ecdhTests.add(new Test.Simple(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve." , "Card incorrectly accepted point on invalid curve.")); - } - tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId(), ecdhTests.toArray(new Test[0]))); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); - } - } -} diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java new file mode 100644 index 0000000..4a27bad --- /dev/null +++ b/src/cz/crcs/ectester/reader/test/PerformanceTest.java @@ -0,0 +1,103 @@ +package cz.crcs.ectester.reader.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.reader.command.Command; + +import java.util.Arrays; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class PerformanceTest extends SimpleTest<CommandTestable> { + private long[] times; + private long mean; + private long median; + private long mode; + private int count; + + private PerformanceTest(CommandTestable testable, int count) { + super(testable, new TestCallback<CommandTestable>() { + @Override + public Result apply(CommandTestable testable) { + return new Result(Result.Value.SUCCESS); + } + }); + this.count = count; + } + + public static PerformanceTest repeat(Command cmd, int count) { + return new PerformanceTest(new CommandTestable(cmd), count); + } + + @Override + public String getDescription() { + return String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode); + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + + times = new long[count]; + for (int i = 0; i < count; ++i) { + testable.run(); + times[i] = testable.getResponse().getDuration(); + testable.reset(); + } + + mean = Arrays.stream(times).sum() / count; + + long[] sorted = times.clone(); + Arrays.sort(sorted); + if (count % 2 == 0) { + median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2; + } else { + median = sorted[count / 2]; + } + + long max_occurences = 0; + int i = 0; + while (i < count) { + long current_value = sorted[i]; + long current_occurences = 0; + while (i < count && sorted[i] == current_value) { + i++; + current_occurences++; + } + if (current_occurences > max_occurences) { + max_occurences = current_occurences; + mode = current_value; + } + } + hasRun = true; + result = callback.apply(testable); + } + + public long getCount() { + return count; + } + + public Command getCommand() { + return testable.getCommand(); + } + + public long[] getTimes() { + return times; + } + + public long getMean() { + return mean; + } + + public long getMedian() { + return median; + } + + public long getMode() { + return mode; + } +} diff --git a/src/cz/crcs/ectester/reader/test/Test.java b/src/cz/crcs/ectester/reader/test/Test.java deleted file mode 100644 index 022ad56..0000000 --- a/src/cz/crcs/ectester/reader/test/Test.java +++ /dev/null @@ -1,217 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.response.Response; - -import javax.smartcardio.CardException; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; - -/** - * An abstract test that can be run and has a Result. - * - * @author Jan Jancar johny@neuromancer.sk - */ -public abstract class Test { - boolean hasRun = false; - Result result; - - public Result getResult() { - if (!hasRun) { - return null; - } - return result; - } - - public Value getResultValue() { - if (!hasRun) { - return null; - } - return result.getValue(); - } - - public String getResultCause() { - if (!hasRun) { - return null; - } - return result.getCause(); - } - - public boolean ok() { - if (!hasRun) { - return true; - } - return result.ok(); - } - - public abstract String getDescription(); - - public boolean hasRun() { - return hasRun; - } - - public abstract void run() throws CardException; - - /** - * A simple test that runs one Command to get and evaluate one Response - * to get a Result and compare it with the expected one. - */ - public static class Simple extends Test { - private BiFunction<Command, Response, Result> callback; - private Command command; - private Response response; - - public Simple(Command command, BiFunction<Command, Response, Result> callback) { - this.command = command; - this.callback = callback; - } - - public Simple(Command command, ExpectedValue expected, String ok, String nok) { - this(command, (cmd, resp) -> { - Value resultValue = Value.fromExpected(expected, resp.successful(), resp.error()); - return new Result(resultValue, resultValue.ok() ? ok : nok); - }); - } - - public Simple(Command command, ExpectedValue expected) { - this(command, expected, null, null); - } - - public Command getCommand() { - return command; - } - - public Response getResponse() { - return response; - } - - @Override - public void run() throws CardException { - if (hasRun) - return; - - response = command.send(); - if (callback != null) { - result = callback.apply(command, response); - } else { - if (response.successful()) { - result = new Result(Value.SUCCESS); - } else { - result = new Result(Value.FAILURE); - } - } - hasRun = true; - } - - @Override - public String getDescription() { - return response.getDescription(); - } - } - - /** - * A compound test that runs many Tests and has a Result dependent on all/some of their Results. - */ - public static class Compound extends Test { - private Function<Test[], Result> callback; - private Test[] tests; - private String description; - - private Compound(Function<Test[], Result> callback, Test... tests) { - this.callback = callback; - this.tests = tests; - } - - private Compound(Function<Test[], Result> callback, String descripiton, Test... tests) { - this(callback, tests); - this.description = descripiton; - } - - public static Compound function(Function<Test[], Result> callback, Test... tests) { - return new Compound(callback, tests); - } - - public static Compound function(Function<Test[], Result> callback, String description, Test... tests) { - return new Compound(callback, description, tests); - } - - public static Compound all(ExpectedValue what, Test... all) { - return new Compound((tests) -> { - for (Test test : tests) { - if (!Value.fromExpected(what, test.ok()).ok()) { - return new Result(Value.FAILURE, "At least one of the sub-tests did not have the expected result."); - } - } - return new Result(Value.SUCCESS, "All sub-tests had the expected result."); - }, all); - } - - public static Compound all(ExpectedValue what, String description, Test... all) { - Compound result = Compound.all(what, all); - result.setDescription(description); - return result; - } - - public static Compound any(ExpectedValue what, Test... any) { - return new Compound((tests) -> { - for (Test test : tests) { - if (Value.fromExpected(what, test.ok()).ok()) { - return new Result(Value.SUCCESS, "At least one of the sub-tests did have the expected result."); - } - } - return new Result(Value.FAILURE, "None of the sub-tests had the expected result."); - }, any); - } - - public static Compound any(ExpectedValue what, String description, Test... any) { - Compound result = Compound.any(what, any); - result.setDescription(description); - return result; - } - - public static Compound mask(ExpectedValue[] results, Test... masked) { - return new Compound((tests) -> { - for (int i = 0; i < results.length; ++i) { - if (!Value.fromExpected(results[i], tests[i].ok()).ok()) { - return new Result(Value.FAILURE, "At least one of the sub-tests did not match the result mask."); - } - } - return new Result(Value.SUCCESS, "All sub-tests matched the expected mask."); - }, masked); - } - - public static Compound mask(ExpectedValue[] results, String description, Test... masked) { - Compound result = Compound.mask(results, masked); - result.setDescription(description); - return result; - } - - public Test[] getTests() { - return tests; - } - - @Override - public void run() throws CardException { - if (hasRun) - return; - - for (Test test : tests) { - test.run(); - } - result = callback.apply(tests); - this.hasRun = true; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String getDescription() { - return description; - } - } -} diff --git a/src/cz/crcs/ectester/reader/test/TestRunner.java b/src/cz/crcs/ectester/reader/test/TestRunner.java deleted file mode 100644 index baab6a8..0000000 --- a/src/cz/crcs/ectester/reader/test/TestRunner.java +++ /dev/null @@ -1,29 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.reader.output.TestWriter; - -import javax.smartcardio.CardException; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class TestRunner { - private TestSuite suite; - private TestWriter writer; - - public TestRunner(TestSuite suite, TestWriter writer) { - this.suite = suite; - this.writer = writer; - } - - public void run() throws CardException { - writer.begin(suite); - for (Test t : suite.getTests()) { - if (!t.hasRun()) { - t.run(); - writer.outputTest(t); - } - } - writer.end(); - } -} diff --git a/src/cz/crcs/ectester/reader/test/TestSuite.java b/src/cz/crcs/ectester/reader/test/TestSuite.java deleted file mode 100644 index f13317c..0000000 --- a/src/cz/crcs/ectester/reader/test/TestSuite.java +++ /dev/null @@ -1,135 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.EC_Curve; - -import java.io.IOException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public abstract class TestSuite { - EC_Store dataStore; - ECTester.Config cfg; - String name; - String description; - List<Test> tests = new LinkedList<>(); - - TestSuite(EC_Store dataStore, ECTester.Config cfg, String name, String description) { - this.dataStore = dataStore; - this.cfg = cfg; - this.name = name; - this.description = description; - } - - public abstract void setup(CardMngr cardManager) throws IOException; - - public List<Test> getTests() { - return Collections.unmodifiableList(tests); - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - - /** - * @param cardManager cardManager to send APDU through - * @param generateExpected expected result of the Generate command - * @param ecdhExpected expected result of the ordinary ECDH command - * @param ecdhCompressExpected expected result of ECDH with a compressed point - * @param ecdsaExpected expected result of the ordinary ECDSA command - * @param description compound test description - * @return test to run - */ - Test defaultCurveTests(CardMngr cardManager, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressExpected, ExpectedValue ecdsaExpected, String description) { - List<Test> tests = new LinkedList<>(); - - tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), generateExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_NONE, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_COMPRESS, EC_Consts.KA_ECDH), ecdhExpected)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ONE, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_ZERO, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_MAX, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.CORRUPTION_FULLRANDOM, EC_Consts.KA_ECDH), ExpectedValue.FAILURE)); - tests.add(new Test.Simple(new Command.ECDSA(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, null), ecdsaExpected)); - - return Test.Compound.function((testArray) -> { - Function<ExpectedValue, String> shouldHave = (expected) -> { - switch (expected) { - case SUCCESS: - return "succeeded"; - case FAILURE: - return "failed"; - case ANY: - default: - return ""; - } - }; - - for (int i = 0; i < testArray.length; ++i) { - Test t = testArray[i]; - if (!t.ok()) { - if (i == 0) { // generate - return new Result(Value.FAILURE, "The generation of a key should have " + shouldHave.apply(generateExpected) + ", but it did not."); - } else if (i == 2) { // ecdh compress - return new Result(Value.FAILURE, "The ECDH should have " + shouldHave.apply(ecdhExpected) + ", but it did not."); - } else if (i == 1) { // ecdh normal - return new Result(Value.FAILURE, "The ECDH of a compressed point should have " + shouldHave.apply(ecdhCompressExpected) + ", but it did not."); - } else if (i <= 6) { // ecdh wrong, should fail - return new Result(Value.FAILURE, "The ECDH of a corrupted point should have failed, but it did not."); - } else { // ecdsa - return new Result(Value.FAILURE, "The ECDSA should have " + shouldHave.apply(ecdsaExpected) + ", but it did not."); - } - } - } - return new Result(Value.SUCCESS); - }, description, tests.toArray(new Test[0])); - } - - /** - * @param cardManager cardManager to send APDU through - * @param category category to test - * @param field field to test (KeyPair.ALG_EC_FP || KeyPair.ALG_EC_F2M) - * @param setExpected expected result of the Set (curve) command - * @param generateExpected expected result of the Generate command - * @param ecdhExpected expected result of the ordinary ECDH command - * @param ecdhCompressedExpected expected result of the ECDH command with a compressed point. - * @param ecdsaExpected expected result of the ordinary ECDSA command - * @param description compound test description - * @return tests to run - */ - List<Test> defaultCategoryTests(CardMngr cardManager, String category, byte field, ExpectedValue setExpected, ExpectedValue generateExpected, ExpectedValue ecdhExpected, ExpectedValue ecdhCompressedExpected, ExpectedValue ecdsaExpected, String description) { - List<Test> tests = new LinkedList<>(); - Map<String, EC_Curve> curves = dataStore.getObjects(EC_Curve.class, category); - if (curves == null) - return tests; - for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) { - EC_Curve curve = entry.getValue(); - if (curve.getField() == field && (curve.getBits() == cfg.bits || cfg.all)) { - tests.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), field), ExpectedValue.SUCCESS)); - tests.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), setExpected)); - tests.add(defaultCurveTests(cardManager, generateExpected, ecdhExpected, ecdhCompressedExpected, ecdsaExpected, description)); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); - } - } - - return tests; - } -} diff --git a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java b/src/cz/crcs/ectester/reader/test/TestVectorSuite.java deleted file mode 100644 index ff46feb..0000000 --- a/src/cz/crcs/ectester/reader/test/TestVectorSuite.java +++ /dev/null @@ -1,83 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.applet.ECTesterApplet; -import cz.crcs.ectester.applet.EC_Consts; -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import cz.crcs.ectester.reader.Util; -import cz.crcs.ectester.reader.command.Command; -import cz.crcs.ectester.reader.ec.*; -import cz.crcs.ectester.reader.response.Response; -import javacard.security.KeyPair; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; -import static cz.crcs.ectester.reader.test.Result.Value; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class TestVectorSuite extends TestSuite { - - public TestVectorSuite(EC_Store dataStore, ECTester.Config cfg) { - super(dataStore, cfg, "test", "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness."); - } - - @Override - public void setup(CardMngr cardManager) throws IOException { - /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors. - * Do ECDH both ways, export and verify that the result is correct. - */ - Map<String, EC_KAResult> results = dataStore.getObjects(EC_KAResult.class, "test"); - for (EC_KAResult result : results.values()) { - EC_Curve curve = dataStore.getObject(EC_Curve.class, result.getCurve()); - if (cfg.namedCurve != null && !(result.getCurve().startsWith(cfg.namedCurve) || result.getCurve().equals(cfg.namedCurve))) { - continue; - } - if (curve.getBits() != cfg.bits && !cfg.all) { - continue; - } - if (curve.getField() == KeyPair.ALG_EC_FP && !cfg.primeField || curve.getField() == KeyPair.ALG_EC_F2M && !cfg.binaryField) { - continue; - } - EC_Params onekey = dataStore.getObject(EC_Keypair.class, result.getOneKey()); - if (onekey == null) { - onekey = dataStore.getObject(EC_Key.Private.class, result.getOneKey()); - } - EC_Params otherkey = dataStore.getObject(EC_Keypair.class, result.getOtherKey()); - if (otherkey == null) { - otherkey = dataStore.getObject(EC_Key.Public.class, result.getOtherKey()); - } - if (onekey == null || otherkey == null) { - throw new IOException("Test vector keys couldn't be located."); - } - List<Test> testVector = new LinkedList<>(); - - testVector.add(new Test.Simple(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS)); - //tests.add(new Test.Simple(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS)); - testVector.add(new Test.Simple(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.CORRUPTION_NONE, result.getKA()), (command, response) -> { - Response.ECDH dh = (Response.ECDH) response; - if (!dh.successful()) - return new Result(Value.FAILURE, "ECDH was unsuccessful."); - if (!dh.hasSecret()) - return new Result(Value.FAILURE, "ECDH response did not contain the derived secret."); - if (!Util.compareBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength())) { - int firstDiff = Util.diffBytes(dh.getSecret(), 0, result.getParam(0), 0, dh.secretLength()); - return new Result(Value.FAILURE, "ECDH derived secret does not match the test, first difference was at byte " + String.valueOf(firstDiff) + "."); - } - return new Result(Value.SUCCESS); - })); - tests.add(Test.Compound.all(ExpectedValue.SUCCESS, "Test vector " + result.getId(), testVector.toArray(new Test[0]))); - tests.add(new Test.Simple(new Command.Cleanup(cardManager), ExpectedValue.ANY)); - - } - } -} diff --git a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java b/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java deleted file mode 100644 index e9389b4..0000000 --- a/src/cz/crcs/ectester/reader/test/WrongCurvesSuite.java +++ /dev/null @@ -1,34 +0,0 @@ -package cz.crcs.ectester.reader.test; - -import cz.crcs.ectester.data.EC_Store; -import cz.crcs.ectester.reader.CardMngr; -import cz.crcs.ectester.reader.ECTester; -import javacard.security.KeyPair; - -import java.io.IOException; - -import static cz.crcs.ectester.reader.test.Result.ExpectedValue; - -/** - * @author Jan Jancar johny@neuromancer.sk - */ -public class WrongCurvesSuite extends TestSuite { - - public WrongCurvesSuite(EC_Store dataStore, ECTester.Config cfg) { - super(dataStore, cfg, "wrong", "The wrong curve suite tests whether the card rejects domain parameters which are not curves."); - } - - @Override - public void setup(CardMngr cardManager) throws IOException { - /* Just do the default tests on the wrong curves. - * These should generally fail, the curves aren't curves. - */ - String desc = "Default tests over wrong curve params."; - if (cfg.primeField) { - tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_FP, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc)); - } - if (cfg.binaryField) { - tests.addAll(defaultCategoryTests(cardManager, cfg.testSuite, KeyPair.ALG_EC_F2M, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, ExpectedValue.FAILURE, desc)); - } - } -} diff --git a/src/cz/crcs/ectester/scripts/ectester.bat b/src/cz/crcs/ectester/scripts/ectester.bat deleted file mode 100644 index e20b855..0000000 --- a/src/cz/crcs/ectester/scripts/ectester.bat +++ /dev/null @@ -1,34 +0,0 @@ -@ECHO OFF -SETLOCAL enabledelayedexpansion - -SET n=0 -:loop -IF NOT "%1"=="" ( - IF "%1"=="--dangerous" ( - SET dangerous=1 - ) ELSE ( - SET positional[!n!]=%1 - SET /A n+=1 - ) - SHIFT - GOTO :loop -) - -IF NOT "%n%"=="1" ( - ECHO "One argument expected:" - ECHO " ./ectester.bar [--dangerous] CARD_NAME" -) - -SET card=!positional[%%0]! - -SET tests="default test-vectors" -java -jar ECTester.jar -t default -a --format yaml -l %card%.default -java -jar ECTester.jar -t test-vectors -a --format yaml -l %card%.test-vectors -IF "%dangerous%"=="1" ( - SET tests=%tests% "invalid wrong composite" - java -jar ECTester.jar -t invalid -a --format yaml -l %card%.invalid - java -jar ECTester.jar -t wrong -a --format yaml -l %card%.wrong - java -jar ECTester.jar -t composite -a --format yaml -l %card%.composite -) - -zip %card%.zip %tests% diff --git a/src/cz/crcs/ectester/scripts/ectester.sh b/src/cz/crcs/ectester/scripts/ectester.sh deleted file mode 100755 index 8040096..0000000 --- a/src/cz/crcs/ectester/scripts/ectester.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -dangerous="0" - -positional=() -while [[ $# -gt 0 ]] -do - -key="$1" -case $key in - --dangerous) - dangerous=1 - shift - ;; - *) - positional+=("$1") - shift - ;; -esac -done -set -- "${positional[@]}" - -if [[ $# -lt 1 ]]; then - echo "At least one argument expected:" >&2 - echo " ./ectester.sh [--dangerous] CARD_NAME [ECTester args]" >&2 - exit 1 -fi - -card="$1" -shift - -declare -a tests=("default" "test-vectors") -if [[ "$dangerous" == "1" ]]; then - tests+=("invalid" "wrong" "composite") -fi - -declare -a files=() -for i in $(seq 0 $((${#tests[@]} - 1))); do - test="${tests[$i]}" - java -jar ECTester.jar -t ${test} -a --format yaml -l ${card}.${test} $@ - files+=(${card}.$test) -done - -if command -v tar 2>&1 >/dev/null; then - tar -czvf ${card}.tar.gz ${files[*]} -elif command -v zip 2>&1 >/dev/null; then - zip ${card}.zip ${files[*]} -fi diff --git a/src/cz/crcs/ectester/standalone/ECTesterStandalone.java b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java new file mode 100644 index 0000000..f5361c3 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/ECTesterStandalone.java @@ -0,0 +1,525 @@ +package cz.crcs.ectester.standalone; + +import cz.crcs.ectester.common.cli.*; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.TestException; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.common.util.ECUtil; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; +import cz.crcs.ectester.standalone.libs.*; +import cz.crcs.ectester.standalone.output.TextTestWriter; +import cz.crcs.ectester.standalone.output.XMLTestWriter; +import cz.crcs.ectester.standalone.output.YAMLTestWriter; +import cz.crcs.ectester.standalone.test.StandaloneDefaultSuite; +import cz.crcs.ectester.standalone.test.StandaloneTestSuite; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import javax.crypto.KeyAgreement; +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Standalone part of ECTester, a tool for testing Elliptic curve implementations in software libraries. + * + * @author Jan Jancar johny@neuromancer.sk + * @version v0.1.0 + */ +public class ECTesterStandalone { + private ProviderECLibrary[] libs = new ProviderECLibrary[]{new SunECLib(), new BouncyCastleLib(), new TomcryptLib(), new BotanLib()}; + private Config cfg; + + private Options opts = new Options(); + private TreeParser optParser; + private TreeCommandLine cli; + private static final String VERSION = "v0.1.0"; + private static final String DESCRIPTION = "ECTesterStandalone " + VERSION + ", an Elliptic Curve Cryptography support tester/utility."; + private static final String LICENSE = "MIT Licensed\nCopyright (c) 2016-2017 Petr Svenda <petr@svenda.com>"; + private static final String CLI_HEADER = "\n" + DESCRIPTION + "\n\n"; + private static final String CLI_FOOTER = "\n" + LICENSE; + + private void run(String[] args) { + try { + cli = parseArgs(args); + + if (cli.hasOption("version")) { + CLITools.version(DESCRIPTION, LICENSE); + return; + } else if (cli.hasOption("help") || cli.getNext() == null) { + CLITools.help("ECTesterStandalone.jar", CLI_HEADER, opts, optParser, CLI_FOOTER, true); + return; + } + + for (ECLibrary lib : libs) { + lib.initialize(); + } + + cfg = new Config(libs); + if (!cfg.readOptions(cli)) { + return; + } + + if (cli.isNext("list-libs")) { + listLibraries(); + } else if (cli.isNext("list-data")) { + CLITools.listNamed(EC_Store.getInstance(), cli.getNext().getArg(0)); + } else if (cli.isNext("ecdh")) { + ecdh(); + } else if (cli.isNext("ecdsa")) { + ecdsa(); + } else if (cli.isNext("generate")) { + generate(); + } else if (cli.isNext("test")) { + test(); + } else if (cli.isNext("export")) { + export(); + } + + } catch (ParseException | ParserConfigurationException | IOException ex) { + System.err.println(ex.getMessage()); + } catch (InvalidAlgorithmParameterException | InvalidParameterException e) { + System.err.println("Invalid algorithm parameter: " + e.getMessage()); + } catch (NoSuchAlgorithmException nsaex) { + System.err.println("Algorithm not supported by the selected library: " + nsaex.getMessage()); + nsaex.printStackTrace(); + } catch (InvalidKeyException | SignatureException | TestException e) { + e.printStackTrace(); + } + } + + private TreeCommandLine parseArgs(String[] args) throws ParseException { + Map<String, ParserOptions> actions = new TreeMap<>(); + + Option namedCurve = Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").hasArg().argName("cat/id").build(); + Option bits = Option.builder("b").longOpt("bits").hasArg().argName("n").optionalArg(false).desc("What size of curve to use.").build(); + + Options testOpts = new Options(); + testOpts.addOption(bits); + testOpts.addOption(namedCurve); + testOpts.addOption(Option.builder("gt").longOpt("kpg-type").desc("Set the KeyPairGenerator object [type].").hasArg().argName("type").optionalArg(false).build()); + testOpts.addOption(Option.builder("kt").longOpt("ka-type").desc("Set the KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); + testOpts.addOption(Option.builder("st").longOpt("sig-type").desc("Set the Signature object [type].").hasArg().argName("type").optionalArg(false).build()); + testOpts.addOption(Option.builder("f").longOpt("format").desc("Set the output format, one of text,yaml,xml.").hasArg().argName("format").optionalArg(false).build()); + List<Argument> testArgs = new LinkedList<>(); + testArgs.add(new Argument("test_suite", "The test suite to run.", true)); + ParserOptions test = new ParserOptions(new DefaultParser(), testOpts, testArgs); + actions.put("test", test); + + Options ecdhOpts = new Options(); + ecdhOpts.addOption(bits); + ecdhOpts.addOption(namedCurve); + ecdhOpts.addOption(Option.builder("t").longOpt("type").desc("Set KeyAgreement object [type].").hasArg().argName("type").optionalArg(false).build()); + ecdhOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDH [amount] times.").build()); + ParserOptions ecdh = new ParserOptions(new DefaultParser(), ecdhOpts); + actions.put("ecdh", ecdh); + + Options ecdsaOpts = new Options(); + ecdsaOpts.addOption(bits); + ecdsaOpts.addOption(namedCurve); + ecdsaOpts.addOption(Option.builder("t").longOpt("type").desc("Set Signature object [type].").hasArg().argName("type").optionalArg(false).build()); + ecdsaOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Do ECDSA [amount] times.").build()); + ecdsaOpts.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").optionalArg(false).desc("Input [file] to sign.").build()); + ParserOptions ecdsa = new ParserOptions(new DefaultParser(), ecdsaOpts); + actions.put("ecdsa", ecdsa); + + Options generateOpts = new Options(); + generateOpts.addOption(bits); + generateOpts.addOption(namedCurve); + generateOpts.addOption(Option.builder("n").longOpt("amount").hasArg().argName("amount").optionalArg(false).desc("Generate [amount] of EC keys.").build()); + generateOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPairGenerator object [type].").build()); + ParserOptions generate = new ParserOptions(new DefaultParser(), generateOpts); + actions.put("generate", generate); + + Options exportOpts = new Options(); + exportOpts.addOption(Option.builder("t").longOpt("type").hasArg().argName("type").optionalArg(false).desc("Set KeyPair object [type].").build()); + exportOpts.addOption(bits); + ParserOptions export = new ParserOptions(new DefaultParser(), exportOpts); + actions.put("export", export); + + Options listDataOpts = new Options(); + List<Argument> listDataArgs = new LinkedList<>(); + listDataArgs.add(new Argument("what", "what to list.", false)); + ParserOptions listData = new ParserOptions(new TreeParser(Collections.emptyMap(), false, listDataArgs), listDataOpts); + actions.put("list-data", listData); + + Options listLibsOpts = new Options(); + ParserOptions listLibs = new ParserOptions(new DefaultParser(), listLibsOpts); + actions.put("list-libs", listLibs); + + List<Argument> baseArgs = new LinkedList<>(); + baseArgs.add(new Argument("lib", "What library to use.", false)); + optParser = new TreeParser(actions, false, baseArgs); + + opts.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build()); + opts.addOption(Option.builder("h").longOpt("help").desc("Print help.").build()); + + return optParser.parse(opts, args); + } + + /** + * + */ + private void listLibraries() { + for (ECLibrary lib : libs) { + if (lib.isInitialized() && (cfg.selected == null || lib == cfg.selected)) { + System.out.println("\t- " + lib.name()); + Set<KeyPairGeneratorIdent> kpgs = lib.getKPGs(); + if (!kpgs.isEmpty()) { + System.out.println("\t\t- KeyPairGenerators: " + String.join(",", kpgs.stream().map(KeyPairGeneratorIdent::getName).collect(Collectors.toList()))); + } + Set<KeyAgreementIdent> eckas = lib.getKAs(); + if (!eckas.isEmpty()) { + System.out.println("\t\t- KeyAgreements: " + String.join(",", eckas.stream().map(KeyAgreementIdent::getName).collect(Collectors.toList()))); + } + Set<SignatureIdent> sigs = lib.getSigs(); + if (!sigs.isEmpty()) { + System.out.println("\t\t- Signatures: " + String.join(",", sigs.stream().map(SignatureIdent::getName).collect(Collectors.toList()))); + } + Set<String> curves = lib.getCurves(); + if (!curves.isEmpty()) { + System.out.println("\t\t- Curves: " + String.join(",", curves)); + } + System.out.println(); + } + } + } + + /** + * + */ + private void ecdh() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException { + ProviderECLibrary lib = cfg.selected; + + String algo = cli.getOptionValue("ecdh.type", "ECDH"); + KeyAgreementIdent kaIdent = lib.getKAs().stream() + .filter((ident) -> ident.contains(algo)) + .findFirst() + .orElse(null); + + KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream() + .filter((ident) -> ident.contains(algo)) + .findFirst() + .orElse(lib.getKPGs().stream() + .filter((ident) -> ident.contains("ECDH")) + .findFirst() + .orElse(lib.getKPGs().stream() + .filter((ident) -> ident.contains("EC")) + .findFirst() + .orElse(null))); + + + if (kaIdent == null || kpIdent == null) { + throw new NoSuchAlgorithmException(algo); + } else { + KeyAgreement ka = kaIdent.getInstance(lib.getProvider()); + KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider()); + AlgorithmParameterSpec spec = null; + if (cli.hasOption("ecdh.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("ecdh.bits")); + kpg.initialize(bits); + } else if (cli.hasOption("ecdh.named-curve")) { + String curveName = cli.getOptionValue("ecdh.named-curve"); + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + if (curve == null) { + System.err.println("Curve not found: " + curveName); + return; + } + spec = curve.toSpec(); + kpg.initialize(spec); + }//TODO: allow ECGenNamedSpec + + System.out.println("index;nanotime;pubW;privS;secret"); + + int amount = Integer.parseInt(cli.getOptionValue("ecdh.amount", "1")); + for (int i = 0; i < amount; ++i) { + KeyPair one = kpg.genKeyPair(); + KeyPair other = kpg.genKeyPair(); + + ECPrivateKey privkey = (ECPrivateKey) one.getPrivate(); + ECPublicKey pubkey = (ECPublicKey) other.getPublic(); + + long elapsed = -System.nanoTime(); + if (spec != null) { + ka.init(privkey, spec); + } else { + ka.init(privkey); + } + ka.doPhase(pubkey, true); + elapsed += System.nanoTime(); + byte[] result = ka.generateSecret(); + ka = kaIdent.getInstance(lib.getProvider()); + + String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); + String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false); + String dh = ByteUtil.bytesToHex(result, false); + System.out.println(String.format("%d;%d;%s;%s;%s", i, elapsed, pub, priv, dh)); + } + } + } + + /** + * + */ + private void ecdsa() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, SignatureException { + byte[] data; + String dataString; + if (cli.hasOption("ecdsa.file")) { + String fileName = cli.getOptionValue("ecdsa.file"); + File in = new File(fileName); + long len = in.length(); + if (len == 0) { + throw new FileNotFoundException(fileName); + } + data = Files.readAllBytes(in.toPath()); + dataString = ""; + } else { + SecureRandom random = new SecureRandom(); + data = new byte[32]; + random.nextBytes(data); + dataString = ByteUtil.bytesToHex(data, false); + } + + ProviderECLibrary lib = cfg.selected; + + String algo = cli.getOptionValue("ecdsa.type", "ECDSA"); + SignatureIdent sigIdent = lib.getSigs().stream() + .filter((ident) -> ident.contains(algo)) + .findFirst() + .orElse(null); + + KeyPairGeneratorIdent kpIdent = lib.getKPGs().stream() + .filter((ident) -> ident.contains(algo)) + .findFirst() + .orElse(lib.getKPGs().stream() + .filter((ident) -> ident.contains("EC")) + .findFirst() + .orElse(null)); + + if (sigIdent == null || kpIdent == null) { + throw new NoSuchAlgorithmException(algo); + } else { + Signature sig = sigIdent.getInstance(lib.getProvider()); + KeyPairGenerator kpg = kpIdent.getInstance(lib.getProvider()); + if (cli.hasOption("ecdsa.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("ecdsa.bits")); + kpg.initialize(bits); + } else if (cli.hasOption("ecdsa.named-curve")) { + String curveName = cli.getOptionValue("ecdsa.named-curve"); + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + if (curve == null) { + System.err.println("Curve not found: " + curveName); + return; + } + kpg.initialize(curve.toSpec()); + } + + System.out.println("index;data;signtime;verifytime;pubW;privS;signature;verified"); + + int amount = Integer.parseInt(cli.getOptionValue("ecdsa.amount", "1")); + for (int i = 0; i < amount; ++i) { + KeyPair one = kpg.genKeyPair(); + + ECPrivateKey privkey = (ECPrivateKey) one.getPrivate(); + ECPublicKey pubkey = (ECPublicKey) one.getPublic(); + + sig.initSign(privkey); + sig.update(data); + + long signTime = -System.nanoTime(); + byte[] signature = sig.sign(); + signTime += System.nanoTime(); + + sig.initVerify(pubkey); + sig.update(data); + + long verifyTime = -System.nanoTime(); + boolean verified = sig.verify(signature); + verifyTime += System.nanoTime(); + + + String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(pubkey.getW(), pubkey.getParams()), false); + String priv = ByteUtil.bytesToHex(privkey.getS().toByteArray(), false); + String sign = ByteUtil.bytesToHex(signature, false); + System.out.println(String.format("%d;%s;%d;%d;%s;%s;%s;%d", i, dataString, signTime, verifyTime, pub, priv, sign, verified ? 1 : 0)); + } + } + } + + /** + * + */ + private void generate() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + ProviderECLibrary lib = cfg.selected; + KeyPairGeneratorIdent ident = null; + String algo = cli.getOptionValue("generate.type", "EC"); + for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) { + if (kpIdent.contains(algo)) { + ident = kpIdent; + break; + } + } + if (ident == null) { + throw new NoSuchAlgorithmException(algo); + } else { + KeyPairGenerator kpg = ident.getInstance(lib.getProvider()); + if (cli.hasOption("generate.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("generate.bits")); + kpg.initialize(bits); + } else if (cli.hasOption("generate.named-curve")) { + String curveName = cli.getOptionValue("generate.named-curve"); + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + if (curve == null) { + System.err.println("Curve not found: " + curveName); + return; + } + kpg.initialize(curve.toSpec()); + } + System.out.println("index;nanotime;pubW;privS"); + + int amount = Integer.parseInt(cli.getOptionValue("generate.amount", "1")); + for (int i = 0; i < amount; ++i) { + long elapsed = -System.nanoTime(); + KeyPair kp = kpg.genKeyPair(); + elapsed += System.nanoTime(); + ECPublicKey publicKey = (ECPublicKey) kp.getPublic(); + ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); + + String pub = ByteUtil.bytesToHex(ECUtil.toX962Uncompressed(publicKey.getW(), publicKey.getParams()), false); + String priv = ByteUtil.bytesToHex(privateKey.getS().toByteArray(), false); + System.out.println(String.format("%d;%d;%s;%s", i, elapsed, pub, priv)); + } + } + } + + /** + * + */ + private void test() throws NoSuchAlgorithmException, TestException, ParserConfigurationException { + TestWriter writer; + switch (cli.getOptionValue("test.format", "text").toLowerCase()) { + case "yaml": + case "yml": + writer = new YAMLTestWriter(System.out); + break; + case "xml": + writer = new XMLTestWriter(System.out); + break; + case "text": + default: + writer = new TextTestWriter(System.out); + break; + } + + StandaloneTestSuite suite = new StandaloneDefaultSuite(writer, cfg, cli); + suite.run(); + } + + /** + * + */ + private void export() throws NoSuchAlgorithmException, IOException { + ProviderECLibrary lib = (ProviderECLibrary) cfg.selected; + KeyPairGeneratorIdent ident = null; + String algo = cli.getOptionValue("export.type", "EC"); + for (KeyPairGeneratorIdent kpIdent : lib.getKPGs()) { + if (kpIdent.contains(algo)) { + ident = kpIdent; + break; + } + } + if (ident == null) { + throw new NoSuchAlgorithmException(algo); + } else { + KeyPairGenerator kpg = ident.getInstance(lib.getProvider()); + if (cli.hasOption("export.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("export.bits")); + kpg.initialize(bits); + } + KeyPair kp = kpg.genKeyPair(); + ECPrivateKey privateKey = (ECPrivateKey) kp.getPrivate(); + ECParameterSpec params = privateKey.getParams(); + System.out.println(params); + EC_Curve curve = EC_Curve.fromSpec(params); + curve.writeCSV(System.out); + } + } + + public static void main(String[] args) { + ECTesterStandalone app = new ECTesterStandalone(); + app.run(args); + } + + + /** + * + */ + public static class Config { + private ProviderECLibrary[] libs; + public ProviderECLibrary selected = null; + + public Config(ProviderECLibrary[] libs) { + this.libs = libs; + } + + boolean readOptions(TreeCommandLine cli) { + if (cli.isNext("generate") || cli.isNext("export") || cli.isNext("ecdh") || cli.isNext("ecdsa") || cli.isNext("test")) { + if (!cli.hasArg(-1)) { + System.err.println("Missing library name argument."); + return false; + } + + String next = cli.getNextName(); + if (cli.hasOption(next + ".bits") && cli.hasOption(next + ".named-curve")) { + System.err.println("You can only specify bitsize or a named curve, nor both."); + return false; + } + } + + String libraryName = cli.getArg(-1); + if (libraryName != null) { + List<ProviderECLibrary> matchedLibs = new LinkedList<>(); + for (ProviderECLibrary lib : libs) { + if (lib.name().toLowerCase().contains(libraryName.toLowerCase())) { + matchedLibs.add(lib); + } + } + if (matchedLibs.size() == 0) { + System.err.println("No library " + libraryName + " found."); + return false; + } else if (matchedLibs.size() > 1) { + System.err.println("Multiple matching libraries found: " + String.join(",", matchedLibs.stream().map(ECLibrary::name).collect(Collectors.toList()))); + return false; + } else { + selected = matchedLibs.get(0); + } + } + + if (cli.hasOption("test.format")) { + String fmt = cli.getOptionValue("test.format"); + String formats[] = new String[]{"text", "xml", "yaml", "yml"}; + if (!Arrays.asList(formats).contains(fmt.toLowerCase())) { + System.err.println("Invalid format specified."); + return false; + } + } + + return true; + } + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/Ident.java b/src/cz/crcs/ectester/standalone/consts/Ident.java new file mode 100644 index 0000000..40a44ac --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/Ident.java @@ -0,0 +1,80 @@ +package cz.crcs.ectester.standalone.consts; + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.BiFunction; + +public abstract class Ident { + Set<String> idents; + String name; + + public Ident(String name, String... aliases) { + this.name = name; + this.idents = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + this.idents.add(name); + this.idents.addAll(Arrays.asList(aliases)); + } + + public String getName() { + return name; + } + + public Set<String> getIdents() { + return Collections.unmodifiableSet(idents); + } + + public boolean contains(String other) { + return name.equals(other) || idents.contains(other); + } + + <T> T getInstance(BiFunction<String, Provider, T> getter, Provider provider) throws NoSuchAlgorithmException { + T instance = null; + try { + instance = getter.apply(name, provider); + } catch (Exception ignored) { + } + + if (instance == null) { + for (String alias : idents) { + try { + instance = getter.apply(alias, provider); + if (instance != null) { + break; + } + } catch (Exception ignored) { + } + } + } + + if (instance == null) { + throw new NoSuchAlgorithmException(name); + } + return instance; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Ident)) { + return false; + } + Ident other = (Ident) obj; + return idents.equals(other.getIdents()); + } + + @Override + public int hashCode() { + return idents.hashCode() + 37; + } + + @Override + public String toString() { + return "(" + String.join("|", idents) + ")"; + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java new file mode 100644 index 0000000..0e4d311 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/KeyAgreementIdent.java @@ -0,0 +1,68 @@ +package cz.crcs.ectester.standalone.consts; + +import javax.crypto.KeyAgreement; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementIdent extends Ident { + private static final List<KeyAgreementIdent> ALL = new LinkedList<>(); + + static { + //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + // Basic ECDH and ECDHC (plain/raw) + ALL.add(new KeyAgreementIdent("ECDH")); + ALL.add(new KeyAgreementIdent("ECDHC", "ECCDH")); + // ECDH and ECDHC with SHA as KDF, OIDs from RFC 3278 + ALL.add(new KeyAgreementIdent("ECDHwithSHA1KDF", "1.3.133.16.840.63.0.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA1KDF", "1.3.133.16.840.63.0.3")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA224KDF", "1.3.132.1.11.0")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA224KDF", "1.3.132.1.14.0")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA256KDF", "1.3.132.1.11.1")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA256KDF", "1.3.132.1.14.1")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA384KDF", "1.3.132.1.11.2")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA384KDF", "1.3.132.1.14.2")); + ALL.add(new KeyAgreementIdent("ECDHwithSHA512KDF", "1.3.132.1.11.3")); + ALL.add(new KeyAgreementIdent("ECCDHwithSHA512KDF", "1.3.132.1.14.3")); + // ECMQV - Disable for now as it needs diferent params(too different from DH) + //ALL.add(new KeyAgreementIdent("ECMQV")); + //ALL.add(new KeyAgreementIdent("ECMQVwithSHA1CKDF", "1.3.133.16.840.63.0.16")); + //ALL.add(new KeyAgreementIdent("ECMQVwithSHA224CKDF", "1.3.132.1.15.0")); + //ALL.add(new KeyAgreementIdent("ECMQVwithSHA256CKDF", "1.3.132.1.15.1")); + //ALL.add(new KeyAgreementIdent("ECMQVwithSHA384CKDF", "1.3.132.1.15.2")); + //ALL.add(new KeyAgreementIdent("ECMQVwithSHA512CKDF", "1.3.132.1.15.3")); + // ECVKO - Disable for now as it needs diferent params(too different from DH) + //ALL.add(new KeyAgreementIdent("ECVKO", "ECGOST3410", "1.2.643.2.2.19", "GOST-3410-2001", "1.2.643.2.2.96")); + //ALL.add(new KeyAgreementIdent("ECVKO256", "ECGOST3410-2012-256", "1.2.643.7.1.1.6.1", "1.2.643.7.1.1.1.1")); + //ALL.add(new KeyAgreementIdent("ECVKO512", "ECGOST3410-2012-512", "1.2.643.7.1.1.6.2", "1.2.643.7.1.1.1.2")); + } + + public static KeyAgreementIdent get(String ident) { + for (KeyAgreementIdent ka : ALL) { + if (ka.getIdents().contains(ident)) { + return ka; + } + } + return null; + } + + private KeyAgreementIdent(String name, String... aliases) { + super(name, aliases); + } + + public KeyAgreement getInstance(Provider provider) throws NoSuchAlgorithmException { + KeyAgreement instance = getInstance((algorithm, provider1) -> { + try { + return KeyAgreement.getInstance(algorithm, provider1); + } catch (NoSuchAlgorithmException e) { + return null; + } + }, provider); + instance.getProvider(); + return instance; + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java new file mode 100644 index 0000000..8e67967 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/KeyPairGeneratorIdent.java @@ -0,0 +1,50 @@ +package cz.crcs.ectester.standalone.consts; + +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.LinkedList; +import java.util.List; + +public class KeyPairGeneratorIdent extends Ident { + private static final List<KeyPairGeneratorIdent> ALL = new LinkedList<>(); + + static { + ALL.add(new KeyPairGeneratorIdent("EC")); + ALL.add(new KeyPairGeneratorIdent("ECDH")); + ALL.add(new KeyPairGeneratorIdent("ECDSA")); + ALL.add(new KeyPairGeneratorIdent("ECDHC")); + ALL.add(new KeyPairGeneratorIdent("ECMQV")); + ALL.add(new KeyPairGeneratorIdent("ECGOST3410")); + ALL.add(new KeyPairGeneratorIdent("ECGOST3410-2012")); + // ECKCDSA? Botan provides. + ALL.add(new KeyPairGeneratorIdent("ECKCDSA")); + // ECGDSA? Botan provides. + ALL.add(new KeyPairGeneratorIdent("ECGDSA")); + } + + public static KeyPairGeneratorIdent get(String ident) { + for (KeyPairGeneratorIdent kg : ALL) { + if (kg.getIdents().contains(ident)) { + return kg; + } + } + return null; + } + + public KeyPairGeneratorIdent(String name, String... aliases) { + super(name, aliases); + } + + public KeyPairGenerator getInstance(Provider provider) throws NoSuchAlgorithmException { + KeyPairGenerator instance = getInstance((algorithm, provider1) -> { + try { + return KeyPairGenerator.getInstance(algorithm, provider1); + } catch (NoSuchAlgorithmException e) { + return null; + } + }, provider); + instance.getProvider(); + return instance; + } +} diff --git a/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java new file mode 100644 index 0000000..42ff050 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/consts/SignatureIdent.java @@ -0,0 +1,109 @@ +package cz.crcs.ectester.standalone.consts; + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureIdent extends Ident { + private static final List<SignatureIdent> ALL = new LinkedList<>(); + + static { + //https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html + // ECDSA + ALL.add(new SignatureIdent("ECDSA", "SHA1withECDSA", "ECDSAwithSHA1", "1.2.840.10045.4.1", "1.3.36.3.3.2.1")); + ALL.add(new SignatureIdent("NONEwithECDSA")); + ALL.add(new SignatureIdent("SHA224withECDSA", "SHA224/ECDSA", "1.2.840.10045.4.3.1")); + ALL.add(new SignatureIdent("SHA256withECDSA", "SHA256/ECDSA", "1.2.840.10045.4.3.2")); + ALL.add(new SignatureIdent("SHA384withECDSA", "SHA384/ECDSA", "1.2.840.10045.4.3.3")); + ALL.add(new SignatureIdent("SHA512withECDSA", "SHA512/ECDSA", "1.2.840.10045.4.3.4")); + ALL.add(new SignatureIdent("SHA3-224withECDSA", "SHA3-224/ECDSA", "2.16.840.1.101.3.4.3.9")); + ALL.add(new SignatureIdent("SHA3-256withECDSA", "SHA3-256/ECDSA", "2.16.840.1.101.3.4.3.10")); + ALL.add(new SignatureIdent("SHA3-384withECDSA", "SHA3-384/ECDSA", "2.16.840.1.101.3.4.3.11")); + ALL.add(new SignatureIdent("SHA3-512withECDSA", "SHA3-512/ECDSA", "2.16.840.1.101.3.4.3.12")); + ALL.add(new SignatureIdent("RIPEMD160withECDSA", "RIPEMD160/ECDSA", "1.3.36.3.3.2.2")); + // ECNR + ALL.add(new SignatureIdent("SHA1withECNR")); + ALL.add(new SignatureIdent("SHA224withECNR")); + ALL.add(new SignatureIdent("SHA256withECNR")); + ALL.add(new SignatureIdent("SHA512withECNR")); + // CVC-ECDSA + ALL.add(new SignatureIdent("SHA1withCVC-ECDSA", "SHA1/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.1")); + ALL.add(new SignatureIdent("SHA224withCVC-ECDSA", "SHA224/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.2")); + ALL.add(new SignatureIdent("SHA256withCVC-ECDSA", "SHA256/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.3")); + ALL.add(new SignatureIdent("SHA384withCVC-ECDSA", "SHA384/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.4")); + ALL.add(new SignatureIdent("SHA512withCVC-ECDSA", "SHA512/CVC-ECDSA", "0.4.0.127.0.7.2.2.2.2.5")); + // PLAIN-ECDSA + ALL.add(new SignatureIdent("SHA1withPLAIN-ECDSA", "SHA1/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.1")); + ALL.add(new SignatureIdent("SHA224withPLAIN-ECDSA", "SHA224/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.2")); + ALL.add(new SignatureIdent("SHA256withPLAIN-ECDSA", "SHA256/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.3")); + ALL.add(new SignatureIdent("SHA384withPLAIN-ECDSA", "SHA384/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.4")); + ALL.add(new SignatureIdent("SHA512withPLAIN-ECDSA", "SHA512/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.5")); + ALL.add(new SignatureIdent("RIPEMD160withPLAIN-ECDSA", "RIPEMD160/PLAIN-ECDSA", "0.4.0.127.0.7.1.1.4.1.6")); + // ECGOST + ALL.add(new SignatureIdent("ECGOST3410", "ECGOST-3410", "GOST-3410-2001")); + ALL.add(new SignatureIdent("GOST3411withECGOST3410", "GOST3411/ECGOST3410", "1.2.643.2.2.3")); + ALL.add(new SignatureIdent("ECGOST3410-2012-256", "GOST-3410-2012-256")); + ALL.add(new SignatureIdent("GOST3411-2012-256withECGOST3410-2012-256", "GOST3411-2012-256/ECGOST3410-2012-2560", "1.2.643.7.1.1.3.2")); + ALL.add(new SignatureIdent("ECGOST3410-2012-512", "GOST-3410-2012-512")); + ALL.add(new SignatureIdent("GOST3411-2012-512withECGOST3410-2012-512", "GOST3411-2012-512/ECGOST3410-2012-5120", "1.2.643.7.1.1.3.3")); + ALL.add(new SignatureIdent("SM3withSM2")); + // ECDDSA + ALL.add(new SignatureIdent("ECDDSA", "DETECDSA", "ECDETDSA")); + ALL.add(new SignatureIdent("SHA1withECDDSA", "SHA1withDETECDSA")); + ALL.add(new SignatureIdent("SHA224withECDDSA", "SHA224withDETECDSA")); + ALL.add(new SignatureIdent("SHA256withECDDSA", "SHA256withDETECDSA")); + ALL.add(new SignatureIdent("SHA384withECDDSA", "SHA384withDETECDSA")); + ALL.add(new SignatureIdent("SHA512withECDDSA", "SHA512withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-224withECDDSA", "SHA3-224withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-256withECDDSA", "SHA3-256withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-384withECDDSA", "SHA3-384withDETECDSA")); + ALL.add(new SignatureIdent("SHA3-512withECDDSA", "SHA3-512withDETECDSA")); + // ECKCDSA? Botan provides. + ALL.add(new SignatureIdent("ECKCDSA","SHA1withECKCDSA", "1.2.410.200004.1.100.4.3")); + ALL.add(new SignatureIdent("NONEwithECKCDSA")); + ALL.add(new SignatureIdent("RIPEMD160withECKCDSA")); + ALL.add(new SignatureIdent("SHA224withECKCDSA", "1.2.410.200004.1.100.4.4")); + ALL.add(new SignatureIdent("SHA256withECKCDSA", "1.2.410.200004.1.100.4.5")); + ALL.add(new SignatureIdent("SHA384withECKCDSA")); + ALL.add(new SignatureIdent("SHA512withECKCDSA")); + // ECGDSA? Botan provides. + ALL.add(new SignatureIdent("ECGDSA", "SHA1withECGDSA", "1.3.36.3.3.2.5.4.2")); + ALL.add(new SignatureIdent("NONEwithECGDSA")); + ALL.add(new SignatureIdent("RIPEMD160withECGDSA", "1.3.36.3.3.2.5.4.1")); + ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.3")); + ALL.add(new SignatureIdent("SHA224withECGDSA", "1.3.36.3.3.2.5.4.4")); + ALL.add(new SignatureIdent("SHA384withECGDSA", "1.3.36.3.3.2.5.4.5")); + ALL.add(new SignatureIdent("SHA512withECGDSA", "1.3.36.3.3.2.5.4.6")); + + } + + public static SignatureIdent get(String ident) { + for (SignatureIdent sig : ALL) { + if (sig.getIdents().contains(ident)) { + return sig; + } + } + return null; + } + + private SignatureIdent(String name, String... aliases) { + super(name, aliases); + } + + public Signature getInstance(Provider provider) throws NoSuchAlgorithmException { + Signature instance = getInstance((algorithm, provider1) -> { + try { + return Signature.getInstance(algorithm, provider1); + } catch (NoSuchAlgorithmException e) { + return null; + } + }, provider); + instance.getProvider(); + return instance; + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/BotanLib.java b/src/cz/crcs/ectester/standalone/libs/BotanLib.java new file mode 100644 index 0000000..cd28791 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BotanLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BotanLib extends NativeECLibrary { + + public BotanLib() { + super("botan_provider", "botan-2"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set<String> getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java new file mode 100644 index 0000000..c6600f9 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/BouncyCastleLib.java @@ -0,0 +1,28 @@ +package cz.crcs.ectester.standalone.libs; + +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.util.Enumeration; +import java.util.Set; +import java.util.TreeSet; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class BouncyCastleLib extends ProviderECLibrary { + + public BouncyCastleLib() { + super(new BouncyCastleProvider()); + } + + @Override + public Set<String> getCurves() { + Set<String> result = new TreeSet<>(); + Enumeration names = ECNamedCurveTable.getNames(); + while (names.hasMoreElements()) { + result.add((String) names.nextElement()); + } + return result; + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/ECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java new file mode 100644 index 0000000..0f81978 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/ECLibrary.java @@ -0,0 +1,26 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public interface ECLibrary { + boolean initialize(); + + boolean isInitialized(); + + Set<String> getCurves(); + + Set<KeyAgreementIdent> getKAs(); + + Set<SignatureIdent> getSigs(); + + Set<KeyPairGeneratorIdent> getKPGs(); + + String name(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java new file mode 100644 index 0000000..0a420a1 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/NativeECLibrary.java @@ -0,0 +1,119 @@ +package cz.crcs.ectester.standalone.libs; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.Provider; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECLibrary extends ProviderECLibrary { + private String resource; + private String[] requriements; + + public static String LIB_RESOURCE_DIR = "/cz/crcs/ectester/standalone/libs/jni/"; + + public NativeECLibrary(String resource, String... requirements) { + this.resource = resource; + this.requriements = requirements; + } + + @Override + public boolean initialize() { + try { + /* Determine what OS are we running on and use appropriate suffix and path. */ + String suffix; + Path appData; + if (System.getProperty("os.name").startsWith("Windows")) { + suffix = "dll"; + appData = Paths.get(System.getenv("AppData")); + } else { + suffix = "so"; + if (System.getProperty("os.name").startsWith("Linux")) { + String dataHome = System.getenv("XDG_DATA_HOME"); + if (dataHome != null) { + appData = Paths.get(dataHome); + } else { + appData = Paths.get(System.getProperty("user.home"), ".local", "share"); + } + } else { + appData = Paths.get(System.getProperty("user.home"), ".local", "share"); + } + } + Path libDir = appData.resolve("ECTesterStandalone"); + File libDirFile = libDir.toFile(); + Path libPath = libDir.resolve(resource + "." + suffix); + File libFile = libPath.toFile(); + + URL jarURL = NativeECLibrary.class.getResource(LIB_RESOURCE_DIR + resource + "." + suffix); + if (jarURL == null) { + return false; + } + URLConnection jarConnection = jarURL.openConnection(); + + /* Only write the file if it does not exist, + * or if the existing one is older than the + * one in the JAR. + */ + boolean write = false; + if (libDirFile.isDirectory() && libFile.isFile()) { + long jarModified = jarConnection.getLastModified(); + + long libModified = Files.getLastModifiedTime(libPath).toMillis(); + if (jarModified > libModified) { + write = true; + } + } else { + libDir.toFile().mkdirs(); + libFile.createNewFile(); + write = true; + } + + if (write) { + Files.copy(jarConnection.getInputStream(), libPath, StandardCopyOption.REPLACE_EXISTING); + } + jarConnection.getInputStream().close(); + + /* + * Need to hack in /usr/local/lib to path. + * See: https://stackoverflow.com/questions/5419039/is-djava-library-path-equivalent-to-system-setpropertyjava-library-path/24988095#24988095 + */ + String path = System.getProperty("java.library.path"); + if (suffix.equals("so")) { + String newPath = path + ":/usr/local/lib"; + System.setProperty("java.library.path", newPath); + Field fieldSysPath; + try { + fieldSysPath = ClassLoader.class.getDeclaredField( "sys_paths" ); + fieldSysPath.setAccessible( true ); + fieldSysPath.set( null, null ); + } catch (NoSuchFieldException | IllegalAccessException ignored) { + } + } + + for (String requirement : requriements) { + System.loadLibrary(requirement); + } + + if (suffix.equals("so")) { + System.setProperty("java.library.path", path); + } + + System.load(libPath.toString()); + + provider = createProvider(); + return super.initialize(); + } catch (IOException | UnsatisfiedLinkError ignored) { + } + return false; + } + + abstract Provider createProvider(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java new file mode 100644 index 0000000..9108eaf --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/ProviderECLibrary.java @@ -0,0 +1,93 @@ +package cz.crcs.ectester.standalone.libs; + +import cz.crcs.ectester.standalone.consts.Ident; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import java.security.Provider; +import java.security.Security; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class ProviderECLibrary implements ECLibrary { + Provider provider; + private boolean initialized = false; + + public ProviderECLibrary() { + + } + + public ProviderECLibrary(Provider provider) { + this.provider = provider; + } + + @Override + public boolean initialize() { + try { + int result = Security.addProvider(provider); + if (result == -1) { + provider = Security.getProvider(provider.getName()); + } + initialized = true; + } catch (NullPointerException | SecurityException ignored) { + initialized = false; + } + return initialized; + } + + @Override + public boolean isInitialized() { + return initialized; + } + + private <T extends Ident> Set<T> getIdents(String type, Function<String, T> getter) { + Set<T> results = new HashSet<>(); + if (!initialized) { + return results; + } + + for (Provider.Service service : provider.getServices()) { + if (service.getType().equals(type)) { + T id = getter.apply(service.getAlgorithm()); + if (id != null) { + results.add(id); + } + } + } + return results; + } + + @Override + public Set<KeyAgreementIdent> getKAs() { + return getIdents("KeyAgreement", KeyAgreementIdent::get); + } + + @Override + public Set<SignatureIdent> getSigs() { + return getIdents("Signature", SignatureIdent::get); + } + + @Override + public Set<KeyPairGeneratorIdent> getKPGs() { + return getIdents("KeyPairGenerator", KeyPairGeneratorIdent::get); + } + + @Override + public String name() { + return provider.getInfo(); + } + + public Provider getProvider() { + return provider; + } + + @Override + public String toString() { + return name(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/SunECLib.java b/src/cz/crcs/ectester/standalone/libs/SunECLib.java new file mode 100644 index 0000000..3aec842 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/SunECLib.java @@ -0,0 +1,28 @@ +package cz.crcs.ectester.standalone.libs; + +import sun.security.ec.SunEC; + +import java.util.Set; +import java.util.TreeSet; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SunECLib extends ProviderECLibrary { + + public SunECLib() { + super(new SunEC()); + } + + @Override + public Set<String> getCurves() { + String curves = provider.get("AlgorithmParameters.EC SupportedCurves").toString(); + String[] split = curves.split("\\|"); + Set<String> result = new TreeSet<>(); + for (String curve : split) { + String body = curve.split(",")[0].substring(1); + result.add(body); + } + return result; + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java new file mode 100644 index 0000000..57b273a --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/TomcryptLib.java @@ -0,0 +1,20 @@ +package cz.crcs.ectester.standalone.libs; + +import java.security.Provider; +import java.util.Set; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TomcryptLib extends NativeECLibrary { + + public TomcryptLib() { + super("tomcrypt_provider", "tommath", "tomcrypt"); + } + + @Override + native Provider createProvider(); + + @Override + public native Set<String> getCurves(); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/Makefile b/src/cz/crcs/ectester/standalone/libs/jni/Makefile new file mode 100644 index 0000000..3530499 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/Makefile @@ -0,0 +1,70 @@ +ifeq ($(JAVA_HOME),) +ifeq ($(OS),Windows_NT) +which = $(shell where $1) +else +which = $(shell which $1) +endif +JAVAC ?= $(realpath $(call which,javac)) +JAVA_HOME = $(abspath $(dir $(JAVAC))..) +endif + +ifneq ($(JAVA_HOME),) +JNI_INCLUDEDIR ?= $(JAVA_HOME)/include +endif + +ifeq ($(JNI_INCLUDEDIR),) +$(error could not determine JNI include dir, try specifying either \ + JAVA_HOME or JNI_INCLUDEDIR) +endif + +TARGETTRIPLET := $(shell $(CC) -dumpmachine) +ifeq ($(JNI_PLATFORM),) +ifeq ($(findstring mingw,$(TARGETTRIPLET)),mingw) +JNI_PLATFORM:= win32 +else +ifeq ($(findstring linux,$(TARGETTRIPLET)),linux) +JNI_PLATFORM:= linux +# add more checks here +endif +endif +endif + +JNI_PLATFORMINCLUDEDIR ?= $(JNI_INCLUDEDIR)/$(JNI_PLATFORM) + +LOCAL_INCLUDES = /usr/local/include +LOCAL_LIBS = /usr/local/lib + +CC?=gcc +CXX?=g++ + +CFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. +CXXFLAGS+=-fPIC -g -I"$(JNI_INCLUDEDIR)" -I"$(JNI_PLATFORMINCLUDEDIR)" -I. + + +all: tomcrypt_provider.so botan_provider.so + +c_utils.o: c_utils.c + $(CC) $(CFLAGS) -c $< + +cpp_utils.o: cpp_utils.cpp + $(CXX) $(CXXFLAGS) -c $< + + +tomcrypt_provider.so: tomcrypt.o c_utils.o + $(CC) -fPIC -g -shared -o $@ $^ -L. -ltommath -ltomcrypt + +tomcrypt.o: tomcrypt.c + $(CC) -DLTM_DESC $(CFLAGS) -c $< + + +botan_provider.so: botan.o cpp_utils.o + $(CXX) -fPIC -g -shared -o $@ $^ -L. -L"$(LOCAL_LIBS)" -lbotan-2 -fstack-protector -m64 -pthread + +botan.o: botan.cpp + $(CXX) -I"$(LOCAL_INCLUDES)/botan-2" $(CFLAGS) -c $< + +clean: + rm -rf *.o + rm -rf *.so + +.PHONY: all clean
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java new file mode 100644 index 0000000..22e5329 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey.java @@ -0,0 +1,68 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import org.bouncycastle.util.Arrays; + +import java.math.BigInteger; +import java.security.interfaces.ECPrivateKey; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECPrivateKey implements ECPrivateKey { + private String algorithm; + private String format; + + public NativeECPrivateKey(String algorithm, String format) { + this.algorithm = algorithm; + this.format = format; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return format; + } + + private static class Raw extends NativeECPrivateKey { + private byte[] keyData; + private ECParameterSpec params; + + public Raw(byte[] keyData, ECParameterSpec params) { + super("EC", "raw"); + this.keyData = keyData; + this.params = params; + } + + @Override + public BigInteger getS() { + return new BigInteger(1, keyData); + } + + @Override + public byte[] getEncoded() { + return Arrays.clone(keyData); + } + + @Override + public ECParameterSpec getParams() { + return params; + } + } + + public static class TomCrypt extends Raw { + public TomCrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + + public static class Botan extends Raw { + public Botan(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java new file mode 100644 index 0000000..8fc4747 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey.java @@ -0,0 +1,69 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; +import org.bouncycastle.util.Arrays; + +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeECPublicKey implements ECPublicKey { + private String algorithm; + private String format; + + public NativeECPublicKey(String algorithm, String format) { + this.algorithm = algorithm; + this.format = format; + } + + @Override + public String getAlgorithm() { + return algorithm; + } + + @Override + public String getFormat() { + return format; + } + + private static class ANSIX962 extends NativeECPublicKey { + private byte[] keyData; + private ECParameterSpec params; + + public ANSIX962(byte[] keyData, ECParameterSpec params) { + super("EC", "ANSI X9.62"); + this.keyData = keyData; + this.params = params; + } + + @Override + public ECPoint getW() { + return ECUtil.fromX962(keyData, params.getCurve()); + } + + @Override + public byte[] getEncoded() { + return Arrays.clone(keyData); + } + + @Override + public ECParameterSpec getParams() { + return params; + } + } + + public static class TomCrypt extends ANSIX962 { + public TomCrypt(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } + + public static class Botan extends ANSIX962 { + public Botan(byte[] keyData, ECParameterSpec params) { + super(keyData, params); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java new file mode 100644 index 0000000..37c9add --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi.java @@ -0,0 +1,137 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeKeyAgreementSpi extends KeyAgreementSpi { + private ECPrivateKey privateKey; + private ECPublicKey publicKey; + private ECParameterSpec params; + + @Override + protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException { + if (!(key instanceof ECPrivateKey)) { + throw new InvalidKeyException + ("Key must be instance of ECPrivateKey"); + } + privateKey = (ECPrivateKey) key; + this.params = privateKey.getParams(); + } + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { + if (!(params instanceof ECParameterSpec)) { + throw new InvalidAlgorithmParameterException(); + } + engineInit(key, random); + this.params = (ECParameterSpec) params; + } + + @Override + protected Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { + if (privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (publicKey != null) { + throw new IllegalStateException("Phase already executed"); + } + if (!lastPhase) { + throw new IllegalStateException + ("Only two party agreement supported, lastPhase must be true"); + } + if (!(key instanceof ECPublicKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPublicKey"); + } + publicKey = (ECPublicKey) key; + return null; + } + + @Override + protected byte[] engineGenerateSecret() throws IllegalStateException { + byte[] pubkey = ECUtil.toX962Uncompressed(publicKey.getW(), params.getCurve()); + byte[] privkey = ECUtil.toByteArray(privateKey.getS(), params.getCurve().getField().getFieldSize()); + return generateSecret(pubkey, privkey, params); + } + + @Override + protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { + byte[] secret = engineGenerateSecret(); + if (sharedSecret.length < offset + secret.length) { + throw new ShortBufferException(); + } + System.arraycopy(secret, 0, sharedSecret, offset, secret.length); + return secret.length; + } + + @Override + protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { + throw new NoSuchAlgorithmException(algorithm); + } + + abstract byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + + + public static class TomCrypt extends NativeKeyAgreementSpi { + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public abstract static class Botan extends NativeKeyAgreementSpi { + private String type; + public Botan(String type) { + this.type = type; + } + + @Override + native byte[] generateSecret(byte[] pubkey, byte[] privkey, ECParameterSpec params); + } + + public static class BotanECDH extends Botan { + public BotanECDH() { + super("ECDH"); + } + } + + public static class BotanECDHwithSHA1KDF extends Botan { + public BotanECDHwithSHA1KDF() { + super("ECDHwithSHA1KDF"); + } + } + + public static class BotanECDHwithSHA224KDF extends Botan { + public BotanECDHwithSHA224KDF() { + super("ECDHwithSHA224KDF"); + } + } + + public static class BotanECDHwithSHA256KDF extends Botan { + public BotanECDHwithSHA256KDF() { + super("ECDHwithSHA256KDF"); + } + } + + public static class BotanECDHwithSHA384KDF extends Botan { + public BotanECDHwithSHA384KDF() { + super("ECDHwithSHA384KDF"); + } + } + + public static class BotanECDHwithSHA512KDF extends Botan { + public BotanECDHwithSHA512KDF() { + super("ECDHwithSHA512KDF"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java new file mode 100644 index 0000000..9461251 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi.java @@ -0,0 +1,123 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeKeyPairGeneratorSpi extends KeyPairGeneratorSpi { + private int keysize; + private SecureRandom random; + private AlgorithmParameterSpec params; + private boolean useKeysize; + private boolean useParams; + + @Override + public void initialize(int keysize, SecureRandom random) { + if (!keysizeSupported(keysize)) { + throw new InvalidParameterException("Keysize " + keysize + " not supported."); + } + this.keysize = keysize; + this.random = random; + this.useKeysize = true; + this.useParams = false; + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { + if (!paramsSupported(params)) { + throw new InvalidAlgorithmParameterException("not supported."); + } + this.params = params; + this.random = random; + this.useParams = true; + this.useKeysize = false; + } + + @Override + public KeyPair generateKeyPair() { + if (useKeysize) { + return generate(keysize, random); + } else if (useParams) { + return generate(params, random); + } + return null; + } + + abstract boolean keysizeSupported(int keysize); + + abstract boolean paramsSupported(AlgorithmParameterSpec params); + + abstract KeyPair generate(int keysize, SecureRandom random); + + abstract KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + + public static class TomCrypt extends NativeKeyPairGeneratorSpi { + + public TomCrypt() { + initialize(256, new SecureRandom()); + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + + public static abstract class Botan extends NativeKeyPairGeneratorSpi { + private String type; + + public Botan(String type) { + this.type = type; + initialize(256, new SecureRandom()); + } + + @Override + native boolean keysizeSupported(int keysize); + + @Override + native boolean paramsSupported(AlgorithmParameterSpec params); + + @Override + native KeyPair generate(int keysize, SecureRandom random); + + @Override + native KeyPair generate(AlgorithmParameterSpec params, SecureRandom random); + } + + public static class BotanECDH extends Botan { + + public BotanECDH() { + super("ECDH"); + } + } + + public static class BotanECDSA extends Botan { + + public BotanECDSA() { + super("ECDSA"); + } + } + + public static class BotanECKCDSA extends Botan { + + public BotanECKCDSA() { + super("ECKCDSA"); + } + } + + public static class BotanECGDSA extends Botan { + + public BotanECGDSA() { + super("ECGDSA"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java new file mode 100644 index 0000000..a0689d6 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeProvider.java @@ -0,0 +1,42 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeProvider extends Provider { + + public NativeProvider(String name, double version, String info) { + super(name, version, info); + + AccessController.doPrivileged((PrivilegedAction<Object>) () -> { + setup(); + return null; + }); + } + + abstract void setup(); + + public static class TomCrypt extends NativeProvider { + + public TomCrypt(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } + + public static class Botan extends NativeProvider { + + public Botan(String name, double version, String info) { + super(name, version, info); + } + + @Override + native void setup(); + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java new file mode 100644 index 0000000..b212697 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi.java @@ -0,0 +1,227 @@ +package cz.crcs.ectester.standalone.libs.jni; + +import cz.crcs.ectester.common.util.ECUtil; + +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class NativeSignatureSpi extends SignatureSpi { + private ECPublicKey verifyKey; + private ECPrivateKey signKey; + private ECParameterSpec params; + + private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + @Override + protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { + if (!(publicKey instanceof ECPublicKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPublicKey"); + } + verifyKey = (ECPublicKey) publicKey; + params = verifyKey.getParams(); + buffer.reset(); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { + if (!(privateKey instanceof ECPrivateKey)) { + throw new InvalidKeyException + ("Key must be an instance of ECPrivateKey"); + } + signKey = (ECPrivateKey) privateKey; + params = signKey.getParams(); + buffer.reset(); + } + + @Override + protected void engineUpdate(byte b) throws SignatureException { + buffer.write(b); + } + + @Override + protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { + buffer.write(b, off, len); + } + + @Override + protected byte[] engineSign() throws SignatureException { + return sign(buffer.toByteArray(), ECUtil.toByteArray(signKey.getS(), params.getCurve().getField().getFieldSize()), params); + } + + @Override + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + return verify(sigBytes, buffer.toByteArray(), ECUtil.toX962Uncompressed(verifyKey.getW(), params), params); + } + + @Override + @Deprecated + protected void engineSetParameter(String param, Object value) throws InvalidParameterException { + throw new UnsupportedOperationException("setParameter() not supported"); + } + + @Override + @Deprecated + protected Object engineGetParameter(String param) throws InvalidParameterException { + throw new UnsupportedOperationException("getParameter() not supported"); + } + + abstract byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + abstract boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + + public static class TomCryptRaw extends NativeSignatureSpi { + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public abstract static class Botan extends NativeSignatureSpi { + private String type; + + public Botan(String type) { + this.type = type; + } + + @Override + native byte[] sign(byte[] data, byte[] privkey, ECParameterSpec params); + + @Override + native boolean verify(byte[] signature, byte[] data, byte[] pubkey, ECParameterSpec params); + } + + public static class BotanECDSAwithNONE extends Botan { + + public BotanECDSAwithNONE() { + super("NONEwithECDSA"); + } + } + + public static class BotanECDSAwithSHA1 extends Botan { + + public BotanECDSAwithSHA1() { + super("SHA1withECDSA"); + } + } + + public static class BotanECDSAwithSHA224 extends Botan { + + public BotanECDSAwithSHA224() { + super("SHA224withECDSA"); + } + } + + public static class BotanECDSAwithSHA256 extends Botan { + + public BotanECDSAwithSHA256() { + super("SHA256withECDSA"); + } + } + + public static class BotanECDSAwithSHA384 extends Botan { + + public BotanECDSAwithSHA384() { + super("SHA384withECDSA"); + } + } + + public static class BotanECDSAwithSHA512 extends Botan { + + public BotanECDSAwithSHA512() { + super("SHA512withECDSA"); + } + } + + public static class BotanECKCDSAwithNONE extends Botan { + + public BotanECKCDSAwithNONE() { + super("NONEwithECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA1 extends Botan { + + public BotanECKCDSAwithSHA1() { + super("SHA1withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA224 extends Botan { + + public BotanECKCDSAwithSHA224() { + super("SHA224withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA256 extends Botan { + + public BotanECKCDSAwithSHA256() { + super("SHA256withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA384 extends Botan { + + public BotanECKCDSAwithSHA384() { + super("SHA384withECKCDSA"); + } + } + + public static class BotanECKCDSAwithSHA512 extends Botan { + + public BotanECKCDSAwithSHA512() { + super("SHA512withECKCDSA"); + } + } + + public static class BotanECGDSAwithNONE extends Botan { + + public BotanECGDSAwithNONE() { + super("NONEwithECGDSA"); + } + } + + public static class BotanECGDSAwithSHA1 extends Botan { + + public BotanECGDSAwithSHA1() { + super("SHA1withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA224 extends Botan { + + public BotanECGDSAwithSHA224() { + super("SHA224withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA256 extends Botan { + + public BotanECGDSAwithSHA256() { + super("SHA256withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA384 extends Botan { + + public BotanECGDSAwithSHA384() { + super("SHA384withECGDSA"); + } + } + + public static class BotanECGDSAwithSHA512 extends Botan { + + public BotanECGDSAwithSHA512() { + super("SHA512withECGDSA"); + } + } +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp new file mode 100644 index 0000000..8e666d6 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/botan.cpp @@ -0,0 +1,631 @@ +#include "native.h" +#include <string> +#include <botan/botan.h> +#include <botan/ec_group.h> +#include <botan/ecc_key.h> +#include <botan/ecdsa.h> +#include <botan/eckcdsa.h> +#include <botan/ecgdsa.h> +#include <botan/ecdh.h> +#include <botan/pubkey.h> +#include "cpp_utils.hpp" + +static jclass provider_class; + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider(JNIEnv *env, jobject self) { + /* Create the custom provider. */ + jclass local_provider_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeProvider$Botan"); + provider_class = (jclass) env->NewGlobalRef(local_provider_class); + + jmethodID init = env->GetMethodID(local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V"); + + const char* info_str = Botan::version_cstr(); + const char* v_str = Botan::short_version_cstr(); + std::string name_str = Botan::short_version_string(); + name_str.insert(0, "Botan "); + + jstring name = env->NewStringUTF(name_str.c_str()); + double version = strtod(v_str, NULL); + jstring info = env->NewStringUTF(info_str); + + return env->NewObject(provider_class, init, name, version, info); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup(JNIEnv *env, jobject self){ + jmethodID provider_put = env->GetMethodID(provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring ecdh = env->NewStringUTF("KeyPairGenerator.ECDH"); + jstring ecdh_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDH"); + env->CallObjectMethod(self, provider_put, ecdh, ecdh_value); + + jstring ecdsa = env->NewStringUTF("KeyPairGenerator.ECDSA"); + jstring ecdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECDSA"); + env->CallObjectMethod(self, provider_put, ecdsa, ecdsa_value); + + jstring eckcdsa = env->NewStringUTF("KeyPairGenerator.ECKCDSA"); + jstring eckcdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECKCDSA"); + env->CallObjectMethod(self, provider_put, eckcdsa, eckcdsa_value); + + jstring ecgdsa = env->NewStringUTF("KeyPairGenerator.ECGDSA"); + jstring ecgdsa_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$BotanECGDSA"); + env->CallObjectMethod(self, provider_put, ecgdsa, ecgdsa_value); + + jstring ecdh_ka = env->NewStringUTF("KeyAgreement.ECDH"); + jstring ecdh_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDH"); + env->CallObjectMethod(self, provider_put, ecdh_ka, ecdh_ka_value); + + jstring ecdh_sha1_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA1KDF"); + jstring ecdh_sha1_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA1KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha1_ka, ecdh_sha1_ka_value); + + jstring ecdh_sha224_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA224KDF"); + jstring ecdh_sha224_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA224KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha224_ka, ecdh_sha224_ka_value); + + jstring ecdh_sha256_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA256KDF"); + jstring ecdh_sha256_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA256KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha256_ka, ecdh_sha256_ka_value); + + jstring ecdh_sha384_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA384KDF"); + jstring ecdh_sha384_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA384KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha384_ka, ecdh_sha384_ka_value); + + jstring ecdh_sha512_ka = env->NewStringUTF("KeyAgreement.ECDHwithSHA512KDF"); + jstring ecdh_sha512_ka_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$BotanECDHwithSHA512KDF"); + env->CallObjectMethod(self, provider_put, ecdh_sha512_ka, ecdh_sha512_ka_value); + + jstring ecdsa_sig = env->NewStringUTF("Signature.NONEwithECDSA"); + jstring ecdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithNONE"); + env->CallObjectMethod(self, provider_put, ecdsa_sig, ecdsa_sig_value); + + jstring ecdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECDSA"); + jstring ecdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, ecdsa_sha1_sig, ecdsa_sha1_sig_value); + + jstring ecdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECDSA"); + jstring ecdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, ecdsa_sha224_sig, ecdsa_sha224_sig_value); + + jstring ecdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECDSA"); + jstring ecdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, ecdsa_sha256_sig, ecdsa_sha256_sig_value); + + jstring ecdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECDSA"); + jstring ecdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, ecdsa_sha384_sig, ecdsa_sha384_sig_value); + + jstring ecdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECDSA"); + jstring ecdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, ecdsa_sha512_sig, ecdsa_sha512_sig_value); + + jstring eckcdsa_sig = env->NewStringUTF("Signature.NONEwithECKCDSA"); + jstring eckcdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithNONE"); + env->CallObjectMethod(self, provider_put, eckcdsa_sig, eckcdsa_sig_value); + + jstring eckcdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECKCDSA"); + jstring eckcdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha1_sig, eckcdsa_sha1_sig_value); + + jstring eckcdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECKCDSA"); + jstring eckcdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha224_sig, eckcdsa_sha224_sig_value); + + jstring eckcdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECKCDSA"); + jstring eckcdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha256_sig, eckcdsa_sha256_sig_value); + + jstring eckcdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECKCDSA"); + jstring eckcdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha384_sig, eckcdsa_sha384_sig_value); + + jstring eckcdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECKCDSA"); + jstring eckcdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECKCDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, eckcdsa_sha512_sig, eckcdsa_sha512_sig_value); + + jstring ecgdsa_sig = env->NewStringUTF("Signature.NONEwithECGDSA"); + jstring ecgdsa_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithNONE"); + env->CallObjectMethod(self, provider_put, ecgdsa_sig, ecgdsa_sig_value); + + jstring ecgdsa_sha1_sig = env->NewStringUTF("Signature.SHA1withECGDSA"); + jstring ecgdsa_sha1_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA1"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha1_sig, ecgdsa_sha1_sig_value); + + jstring ecgdsa_sha224_sig = env->NewStringUTF("Signature.SHA224withECGDSA"); + jstring ecgdsa_sha224_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA224"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha224_sig, ecgdsa_sha224_sig_value); + + jstring ecgdsa_sha256_sig = env->NewStringUTF("Signature.SHA256withECGDSA"); + jstring ecgdsa_sha256_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA256"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha256_sig, ecgdsa_sha256_sig_value); + + jstring ecgdsa_sha384_sig = env->NewStringUTF("Signature.SHA384withECGDSA"); + jstring ecgdsa_sha384_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA384"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha384_sig, ecgdsa_sha384_sig_value); + + jstring ecgdsa_sha512_sig = env->NewStringUTF("Signature.SHA512withECGDSA"); + jstring ecgdsa_sha512_sig_value = env->NewStringUTF("cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$BotanECGDSAwithSHA512"); + env->CallObjectMethod(self, provider_put, ecgdsa_sha512_sig, ecgdsa_sha512_sig_value); + + init_classes(env, "Botan"); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves(JNIEnv *env, jobject self){ + jclass hash_set_class = env->FindClass("java/util/TreeSet"); + + jmethodID hash_set_ctr = env->GetMethodID(hash_set_class, "<init>", "()V"); + jmethodID hash_set_add = env->GetMethodID(hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = env->NewObject(hash_set_class, hash_set_ctr); + + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + for (auto it = curves.begin(); it != curves.end(); ++it) { + std::string curve_name = *it; + jstring name_str = env->NewStringUTF(curve_name.c_str()); + env->CallBooleanMethod(result, hash_set_add, name_str); + } + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported(JNIEnv *env, jobject self, jint keysize){ + return JNI_TRUE; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported(JNIEnv *env, jobject self, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(curve, get_field); + + if (env->IsInstanceOf(field, fp_field_class)) { + return JNI_TRUE; + } + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string str_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + if (curves.find(str_name) != curves.end()) { + return JNI_TRUE; + } + } + return JNI_FALSE; +} + +static jobject biginteger_from_bigint(JNIEnv *env, const Botan::BigInt& bigint) { + std::vector<uint8_t> bigint_data = Botan::BigInt::encode(bigint); + jbyteArray bigint_array = env->NewByteArray(bigint_data.size()); + jbyte * bigint_bytes = env->GetByteArrayElements(bigint_array, NULL); + std::copy(bigint_data.begin(), bigint_data.end(), bigint_bytes); + env->ReleaseByteArrayElements(bigint_array, bigint_bytes, JNI_COMMIT); + + jmethodID biginteger_init = env->GetMethodID(biginteger_class, "<init>", "(I[B)V"); + return env->NewObject(biginteger_class, biginteger_init, (jint) 1, bigint_array); +} + +static Botan::BigInt bigint_from_biginteger(JNIEnv *env, jobject biginteger) { + jmethodID to_byte_array = env->GetMethodID(biginteger_class, "toByteArray", "()[B"); + jbyteArray byte_array = (jbyteArray) env->CallObjectMethod(biginteger, to_byte_array); + jsize byte_length = env->GetArrayLength(byte_array); + jbyte *byte_data = env->GetByteArrayElements(byte_array, NULL); + Botan::BigInt result((unsigned uint8_t*) byte_data, byte_length); + env->ReleaseByteArrayElements(byte_array, byte_data, JNI_ABORT); + return result; +} + +static Botan::EC_Group group_from_params(JNIEnv *env, jobject params) { + if (env->IsInstanceOf(params, ec_parameter_spec_class)) { + jmethodID get_curve = env->GetMethodID(ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = env->CallObjectMethod(params, get_curve); + + jmethodID get_field = env->GetMethodID(elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = env->CallObjectMethod(elliptic_curve, get_field); + + jmethodID get_bits = env->GetMethodID(fp_field_class, "getFieldSize", "()I"); + jint bits = env->CallIntMethod(field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_a = env->GetMethodID(elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = env->CallObjectMethod(elliptic_curve, get_a); + + jmethodID get_b = env->GetMethodID(elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = env->CallObjectMethod(elliptic_curve, get_b); + + jmethodID get_p = env->GetMethodID(fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = env->CallObjectMethod(field, get_p); + + jmethodID get_g = env->GetMethodID(ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = env->CallObjectMethod(params, get_g); + + jmethodID get_x = env->GetMethodID(point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = env->CallObjectMethod(g, get_x); + + jmethodID get_y = env->GetMethodID(point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = env->CallObjectMethod(g, get_y); + + jmethodID get_n = env->GetMethodID(ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = env->CallObjectMethod(params, get_n); + + jmethodID get_h = env->GetMethodID(ec_parameter_spec_class, "getCofactor", "()I"); + jint h = env->CallIntMethod(params, get_h); + + Botan::BigInt pi = bigint_from_biginteger(env, p); + Botan::BigInt ai = bigint_from_biginteger(env, a); + Botan::BigInt bi = bigint_from_biginteger(env, b); + Botan::CurveGFp curve(pi, ai, bi); + + Botan::BigInt gxi = bigint_from_biginteger(env, gx); + Botan::BigInt gyi = bigint_from_biginteger(env, gy); + Botan::PointGFp generator(curve, gxi, gyi); + + Botan::BigInt ni = bigint_from_biginteger(env, n); + Botan::BigInt hi(h); + + return Botan::EC_Group(curve, generator, ni, hi); + } else if (env->IsInstanceOf(params, ecgen_parameter_spec_class)) { + jmethodID get_name = env->GetMethodID(ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (jstring) env->CallObjectMethod(params, get_name); + const char *utf_name = env->GetStringUTFChars(name, NULL); + std::string curve_name(utf_name); + env->ReleaseStringUTFChars(name, utf_name); + return Botan::EC_Group(curve_name); + } + return Botan::EC_Group(); +} + +static jobject params_from_group(JNIEnv *env, Botan::EC_Group group) { + const Botan::CurveGFp& curve = group.get_curve(); + jobject p = biginteger_from_bigint(env, curve.get_p()); + + jmethodID fp_field_init = env->GetMethodID(fp_field_class, "<init>", "(Ljava/math/BigInteger;)V"); + jobject fp_field = env->NewObject(fp_field_class, fp_field_init, p); + + jobject a = biginteger_from_bigint(env, curve.get_a()); + jobject b = biginteger_from_bigint(env, curve.get_b()); + + jmethodID elliptic_curve_init = env->GetMethodID(elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = env->NewObject(elliptic_curve_class, elliptic_curve_init, fp_field, a, b); + + const Botan::PointGFp& generator = group.get_base_point(); + jobject gx = biginteger_from_bigint(env, generator.get_affine_x()); + jobject gy = biginteger_from_bigint(env, generator.get_affine_y()); + + jmethodID point_init = env->GetMethodID(point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = env->NewObject(point_class, point_init, gx, gy); + + const Botan::BigInt& order = group.get_order(); + jobject n = biginteger_from_bigint(env, order); + + const Botan::BigInt& cofactor = group.get_cofactor(); + jint h = (jint) cofactor.to_u32bit(); + + jmethodID ec_parameter_spec_init = env->GetMethodID(ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return env->NewObject(ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, h); +} + +static jobject generate_from_group(JNIEnv* env, jobject self, Botan::EC_Group group) { + Botan::AutoSeeded_RNG rng; + + jclass botan_kpg_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyPairGeneratorSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_kpg_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char* type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + std::unique_ptr<Botan::EC_PrivateKey> skey; + try { + if (type_str == "ECDH") { + skey = std::make_unique<Botan::ECDH_PrivateKey>(rng, group); + } else if (type_str == "ECDSA") { + skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group); + } else if (type_str == "ECKCDSA") { + skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, group); + } else if (type_str == "ECGDSA") { + skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, group); + } + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return NULL; + } + + jobject ec_param_spec = params_from_group(env, group); + + const Botan::PointGFp& pub_point = skey->public_point(); + std::vector<uint8_t> pub_data = Botan::unlock(Botan::EC2OSP(pub_point, Botan::PointGFp::UNCOMPRESSED)); + + jbyteArray pub_bytearray = env->NewByteArray(pub_data.size()); + jbyte *pub_bytes = env->GetByteArrayElements(pub_bytearray, NULL); + std::copy(pub_data.begin(), pub_data.end(), pub_bytes); + env->ReleaseByteArrayElements(pub_bytearray, pub_bytes, JNI_COMMIT); + + jobject ec_pub_param_spec = env->NewLocalRef(ec_param_spec); + jmethodID ec_pub_init = env->GetMethodID(pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = env->NewObject(pubkey_class, ec_pub_init, pub_bytearray, ec_pub_param_spec); + + const Botan::BigInt& priv_scalar = skey->private_value(); + std::vector<uint8_t> priv_data = Botan::BigInt::encode(priv_scalar); + + jbyteArray priv_bytearray = env->NewByteArray(priv_data.size()); + jbyte *priv_bytes = env->GetByteArrayElements(priv_bytearray, NULL); + std::copy(priv_data.begin(), priv_data.end(), priv_bytes); + env->ReleaseByteArrayElements(priv_bytearray, priv_bytes, JNI_COMMIT); + + jobject ec_priv_param_spec = env->NewLocalRef(ec_param_spec); + jmethodID ec_priv_init = env->GetMethodID(privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = env->NewObject(privkey_class, ec_priv_init, priv_bytearray, ec_priv_param_spec); + + jmethodID keypair_init = env->GetMethodID(keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + return env->NewObject(keypair_class, keypair_init, pubkey, privkey); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject self, jint keysize, jobject random){ + const std::set<std::string>& curves = Botan::EC_Group::known_named_groups(); + for (auto it = curves.begin(); it != curves.end(); ++it) { + Botan::EC_Group curve_group = Botan::EC_Group(*it); + size_t curve_size = curve_group.get_curve().get_p().bits(); + if (curve_size == keysize) { + //generate on this group. Even thou no default groups are present... + return generate_from_group(env, self, curve_group); + } + } + + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject self, jobject params, jobject random){ + Botan::EC_Group curve_group = group_from_params(env, params); + return generate_from_group(env, self, curve_group); +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret(JNIEnv *env, jobject self, jbyteArray pubkey, jbyteArray privkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jsize privkey_length = env->GetArrayLength(privkey); + jbyte *privkey_data = env->GetByteArrayElements(privkey, NULL); + Botan::BigInt privkey_scalar((unsigned uint8_t*) privkey_data, privkey_length); + env->ReleaseByteArrayElements(privkey, privkey_data, JNI_ABORT); + + Botan::AutoSeeded_RNG rng; + + Botan::ECDH_PrivateKey skey(rng, curve_group, privkey_scalar); + + jsize pubkey_length = env->GetArrayLength(pubkey); + jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL); + Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve()); + env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT); + + Botan::ECDH_PublicKey pkey(curve_group, public_point); + //TODO: do check_key here? + + jclass botan_ka_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeKeyAgreementSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_ka_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + std::string kdf; + size_t key_len = 0; + if (type_str == "ECDH") { + kdf = "Raw"; + //key len unused + } else if (type_str == "ECDHwithSHA1KDF") { + kdf = "KDF1(SHA-1)"; + key_len = 20; + } else if (type_str == "ECDHwithSHA224KDF") { + kdf = "KDF1(SHA-224)"; + key_len = 28; + } else if (type_str == "ECDHwithSHA256KDF") { + kdf = "KDF1(SHA-256)"; + key_len = 32; + } else if (type_str == "ECDHwithSHA384KDF") { + kdf = "KDF1(SHA-384)"; + key_len = 48; + } else if (type_str == "ECDHwithSHA512KDF") { + kdf = "KDF1(SHA-512)"; + key_len = 64; + } + + Botan::PK_Key_Agreement ka(skey, rng, kdf); + + std::vector<uint8_t> derived; + try { + derived = Botan::unlock(ka.derive_key(key_len, pkey.public_value()).bits_of()); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + return NULL; + } + jbyteArray result = env->NewByteArray(derived.size()); + jbyte *result_data = env->GetByteArrayElements(result, NULL); + std::copy(derived.begin(), derived.end(), result_data); + env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT); + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign(JNIEnv *env, jobject self, jbyteArray data, jbyteArray privkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + jsize privkey_length = env->GetArrayLength(privkey); + jbyte *privkey_bytes = env->GetByteArrayElements(privkey, NULL); + Botan::BigInt privkey_scalar((uint8_t*) privkey_bytes, privkey_length); + env->ReleaseByteArrayElements(privkey, privkey_bytes, JNI_ABORT); + + Botan::AutoSeeded_RNG rng; + + std::unique_ptr<Botan::EC_PrivateKey> skey; + if (type_str.find("ECDSA") != std::string::npos) { + skey = std::make_unique<Botan::ECDSA_PrivateKey>(rng, curve_group, privkey_scalar); + } else if (type_str.find("ECKCDSA") != std::string::npos) { + skey = std::make_unique<Botan::ECKCDSA_PrivateKey>(rng, curve_group, privkey_scalar); + } else if (type_str.find("ECGDSA") != std::string::npos) { + skey = std::make_unique<Botan::ECGDSA_PrivateKey>(rng, curve_group, privkey_scalar); + } + + std::string kdf; + if (type_str.find("NONE") != std::string::npos) { + kdf = "Raw"; + } else if (type_str.find("SHA1") != std::string::npos) { + kdf = "EMSA1(SHA-1)"; + } else if (type_str.find("SHA224") != std::string::npos) { + kdf = "EMSA1(SHA-224)"; + } else if (type_str.find("SHA256") != std::string::npos) { + kdf = "EMSA1(SHA-256)"; + } else if (type_str.find("SHA384") != std::string::npos) { + kdf = "EMSA1(SHA-384)"; + } else if (type_str.find("SHA512") != std::string::npos) { + kdf = "EMSA1(SHA-512)"; + } + + Botan::PK_Signer signer(*skey, rng, kdf, Botan::DER_SEQUENCE); + + jsize data_length = env->GetArrayLength(data); + jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + std::vector<uint8_t> sig; + try { + sig = signer.sign_message((uint8_t*) data_bytes, data_length, rng); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + return NULL; + } + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + + jbyteArray result = env->NewByteArray(sig.size()); + jbyte *result_data = env->GetByteArrayElements(result, NULL); + std::copy(sig.begin(), sig.end(), result_data); + env->ReleaseByteArrayElements(result, result_data, JNI_COMMIT); + + return result; +} + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify(JNIEnv *env, jobject self, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params){ + Botan::EC_Group curve_group = group_from_params(env, params); + + jclass botan_sig_class = env->FindClass("cz/crcs/ectester/standalone/libs/jni/NativeSignatureSpi$Botan"); + jfieldID type_id = env->GetFieldID(botan_sig_class, "type", "Ljava/lang/String;"); + jstring type = (jstring) env->GetObjectField(self, type_id); + const char *type_data = env->GetStringUTFChars(type, NULL); + std::string type_str(type_data); + env->ReleaseStringUTFChars(type, type_data); + + jsize pubkey_length = env->GetArrayLength(pubkey); + jbyte *pubkey_data = env->GetByteArrayElements(pubkey, NULL); + Botan::PointGFp public_point = Botan::OS2ECP((uint8_t*) pubkey_data, pubkey_length, curve_group.get_curve()); + env->ReleaseByteArrayElements(pubkey, pubkey_data, JNI_ABORT); + + std::unique_ptr<Botan::EC_PublicKey> pkey; + if (type_str.find("ECDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECDSA_PublicKey>(curve_group, public_point); + } else if (type_str.find("ECKCDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECKCDSA_PublicKey>(curve_group, public_point); + } else if (type_str.find("ECGDSA") != std::string::npos) { + pkey = std::make_unique<Botan::ECGDSA_PublicKey>(curve_group, public_point); + } + + std::string kdf; + if (type_str.find("NONE") != std::string::npos) { + kdf = "Raw"; + } else if (type_str.find("SHA1") != std::string::npos) { + kdf = "EMSA1(SHA-1)"; + } else if (type_str.find("SHA224") != std::string::npos) { + kdf = "EMSA1(SHA-224)"; + } else if (type_str.find("SHA256") != std::string::npos) { + kdf = "EMSA1(SHA-256)"; + } else if (type_str.find("SHA384") != std::string::npos) { + kdf = "EMSA1(SHA-384)"; + } else if (type_str.find("SHA512") != std::string::npos) { + kdf = "EMSA1(SHA-512)"; + } + + Botan::PK_Verifier verifier(*pkey, kdf, Botan::DER_SEQUENCE); + + jsize data_length = env->GetArrayLength(data); + jsize sig_length = env->GetArrayLength(signature); + jbyte *data_bytes = env->GetByteArrayElements(data, NULL); + jbyte *sig_bytes = env->GetByteArrayElements(signature, NULL); + + bool result; + try { + result = verifier.verify_message((uint8_t*)data_bytes, data_length, (uint8_t*)sig_bytes, sig_length); + } catch (Botan::Exception & ex) { + throw_new(env, "java/security/GeneralSecurityException", ex.what()); + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT); + return JNI_FALSE; + } + env->ReleaseByteArrayElements(data, data_bytes, JNI_ABORT); + env->ReleaseByteArrayElements(signature, sig_bytes, JNI_ABORT); + if (result) { + return JNI_TRUE; + } + return JNI_FALSE; +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c new file mode 100644 index 0000000..336f4a1 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.c @@ -0,0 +1,66 @@ +#include "c_utils.h" +#include <string.h> + +jclass ec_parameter_spec_class; +jclass ecgen_parameter_spec_class; +jclass pubkey_class; +jclass privkey_class; +jclass keypair_class; +jclass elliptic_curve_class; +jclass fp_field_class; +jclass f2m_field_class; +jclass point_class; +jclass biginteger_class; +jclass illegal_state_exception_class; + +void init_classes(JNIEnv *env, const char* lib_name) { + jclass local_ec_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECParameterSpec"); + ec_parameter_spec_class = (*env)->NewGlobalRef(env, local_ec_parameter_spec_class); + + jclass local_ecgen_parameter_spec_class = (*env)->FindClass(env, "java/security/spec/ECGenParameterSpec"); + ecgen_parameter_spec_class = (*env)->NewGlobalRef(env, local_ecgen_parameter_spec_class); + + const char *pubkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$"; + char pubkey_class_name[strlen(pubkey_base) + strlen(lib_name) + 1]; + pubkey_class_name[0] = 0; + strcat(pubkey_class_name, pubkey_base); + strcat(pubkey_class_name, lib_name); + + jclass local_pubkey_class = (*env)->FindClass(env, pubkey_class_name); + pubkey_class = (*env)->NewGlobalRef(env, local_pubkey_class); + + const char *privkey_base = "cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$"; + char privkey_class_name[strlen(privkey_base) + strlen(lib_name) + 1]; + privkey_class_name[0] = 0; + strcat(privkey_class_name, privkey_base); + strcat(privkey_class_name, lib_name); + + jclass local_privkey_class = (*env)->FindClass(env, privkey_class_name); + privkey_class = (*env)->NewGlobalRef(env, local_privkey_class); + + jclass local_keypair_class = (*env)->FindClass(env, "java/security/KeyPair"); + keypair_class = (*env)->NewGlobalRef(env, local_keypair_class); + + jclass local_elliptic_curve_class = (*env)->FindClass(env, "java/security/spec/EllipticCurve"); + elliptic_curve_class = (*env)->NewGlobalRef(env, local_elliptic_curve_class); + + jclass local_fp_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldFp"); + fp_field_class = (*env)->NewGlobalRef(env, local_fp_field_class); + + jclass local_f2m_field_class = (*env)->FindClass(env, "java/security/spec/ECFieldF2m"); + f2m_field_class = (*env)->NewGlobalRef(env, local_f2m_field_class); + + jclass local_biginteger_class = (*env)->FindClass(env, "java/math/BigInteger"); + biginteger_class = (*env)->NewGlobalRef(env, local_biginteger_class); + + jclass local_point_class = (*env)->FindClass(env, "java/security/spec/ECPoint"); + point_class = (*env)->NewGlobalRef(env, local_point_class); + + jclass local_illegal_state_exception_class = (*env)->FindClass(env, "java/lang/IllegalStateException"); + illegal_state_exception_class = (*env)->NewGlobalRef(env, local_illegal_state_exception_class); +} + +void throw_new(JNIEnv *env, const char *class, const char *message) { + jclass clazz = (*env)->FindClass(env, class); + (*env)->ThrowNew(env, clazz, message); +} diff --git a/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h new file mode 100644 index 0000000..d925dfe --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/c_utils.h @@ -0,0 +1,28 @@ +#pragma once + +#include "native.h" + +/** + * Classes that are accessed alot are cached here, manually. + */ +extern jclass ec_parameter_spec_class; +extern jclass ecgen_parameter_spec_class; +extern jclass pubkey_class; +extern jclass privkey_class; +extern jclass keypair_class; +extern jclass elliptic_curve_class; +extern jclass fp_field_class; +extern jclass f2m_field_class; +extern jclass point_class; +extern jclass biginteger_class; +extern jclass illegal_state_exception_class; + +/** + * Initialize the classes. + */ +void init_classes(JNIEnv *env, const char* lib_name); + +/** + * Throw a new exception of class with message. + */ +void throw_new(JNIEnv *env, const char *class, const char *message);
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp new file mode 100644 index 0000000..cef4bfe --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.cpp @@ -0,0 +1,59 @@ +#include "cpp_utils.hpp" + +jclass ec_parameter_spec_class; +jclass ecgen_parameter_spec_class; +jclass pubkey_class; +jclass privkey_class; +jclass keypair_class; +jclass elliptic_curve_class; +jclass fp_field_class; +jclass f2m_field_class; +jclass point_class; +jclass biginteger_class; +jclass illegal_state_exception_class; + +void init_classes(JNIEnv *env, std::string lib_name) { + jclass local_ec_parameter_spec_class = env->FindClass("java/security/spec/ECParameterSpec"); + ec_parameter_spec_class = (jclass) env->NewGlobalRef(local_ec_parameter_spec_class); + + jclass local_ecgen_parameter_spec_class = env->FindClass("java/security/spec/ECGenParameterSpec"); + ecgen_parameter_spec_class = (jclass) env->NewGlobalRef(local_ecgen_parameter_spec_class); + + std::string pubkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPublicKey$"); + pubkey_class_name += lib_name; + + jclass local_pubkey_class = env->FindClass(pubkey_class_name.c_str()); + pubkey_class = (jclass) env->NewGlobalRef(local_pubkey_class); + + std::string privkey_class_name("cz/crcs/ectester/standalone/libs/jni/NativeECPrivateKey$"); + privkey_class_name += lib_name; + + jclass local_privkey_class = env->FindClass(privkey_class_name.c_str()); + privkey_class = (jclass) env->NewGlobalRef(local_privkey_class); + + jclass local_keypair_class = env->FindClass("java/security/KeyPair"); + keypair_class = (jclass) env->NewGlobalRef(local_keypair_class); + + jclass local_elliptic_curve_class = env->FindClass("java/security/spec/EllipticCurve"); + elliptic_curve_class = (jclass) env->NewGlobalRef(local_elliptic_curve_class); + + jclass local_fp_field_class = env->FindClass("java/security/spec/ECFieldFp"); + fp_field_class = (jclass) env->NewGlobalRef(local_fp_field_class); + + jclass local_f2m_field_class = env->FindClass("java/security/spec/ECFieldF2m"); + f2m_field_class = (jclass) env->NewGlobalRef(local_f2m_field_class); + + jclass local_biginteger_class = env->FindClass("java/math/BigInteger"); + biginteger_class = (jclass) env->NewGlobalRef(local_biginteger_class); + + jclass local_point_class = env->FindClass("java/security/spec/ECPoint"); + point_class = (jclass) env->NewGlobalRef(local_point_class); + + jclass local_illegal_state_exception_class = env->FindClass("java/lang/IllegalStateException"); + illegal_state_exception_class = (jclass) env->NewGlobalRef(local_illegal_state_exception_class); +} + +void throw_new(JNIEnv *env, const std::string& klass, const std::string& message) { + jclass clazz = env->FindClass(klass.c_str()); + env->ThrowNew(clazz, message.c_str()); +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp new file mode 100644 index 0000000..bbca521 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/cpp_utils.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "native.h" +#include <string> + +/** + * Classes that are accessed alot are cached here, manually. + */ +extern jclass ec_parameter_spec_class; +extern jclass ecgen_parameter_spec_class; +extern jclass pubkey_class; +extern jclass privkey_class; +extern jclass keypair_class; +extern jclass elliptic_curve_class; +extern jclass fp_field_class; +extern jclass f2m_field_class; +extern jclass point_class; +extern jclass biginteger_class; +extern jclass illegal_state_exception_class; + +/** + * Initialize the classes. + */ +void init_classes(JNIEnv *env, std::string lib_name); + +/** + * Throw a new exception of class with message. + */ +void throw_new(JNIEnv *env, const std::string& klass, const std::string& message);
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/libs/jni/native.h b/src/cz/crcs/ectester/standalone/libs/jni/native.h new file mode 100644 index 0000000..d714b39 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/native.h @@ -0,0 +1,344 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class cz_crcs_ectester_standalone_libs_TomcryptLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_TomcryptLib +#define _Included_cz_crcs_ectester_standalone_libs_TomcryptLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_TomcryptLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_TomCrypt + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_TomCrypt + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_TomCrypt + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_TomCryptRaw + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_BotanLib */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_BotanLib +#define _Included_cz_crcs_ectester_standalone_libs_BotanLib +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: createProvider + * Signature: ()Ljava/security/Provider; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_createProvider + (JNIEnv *, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_BotanLib + * Method: getCurves + * Signature: ()Ljava/util/Set; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_BotanLib_getCurves + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan +#ifdef __cplusplus +extern "C" { +#endif +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 1421746759512286392LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_MAX_ARRAY_SIZE 2147483639L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_KEYS 0L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_VALUES 1L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_ENTRIES 2L +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID 4112578634029874840LL +#undef cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID +#define cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan_serialVersionUID -4298000515446427739LL +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeProvider_Botan + * Method: setup + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024Botan_setup + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: keysizeSupported + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_keysizeSupported + (JNIEnv *, jobject, jint); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: paramsSupported + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_paramsSupported + (JNIEnv *, jobject, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (ILjava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__ILjava_security_SecureRandom_2 + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_Botan + * Method: generate + * Signature: (Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/SecureRandom;)Ljava/security/KeyPair; + */ +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024Botan_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2 + (JNIEnv *, jobject, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPublicKey_Botan +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeECPrivateKey_Botan +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_Botan + * Method: generateSecret + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024Botan_generateSecret + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif +/* Header for class cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan */ + +#ifndef _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan +#define _Included_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: sign + * Signature: ([B[BLjava/security/spec/ECParameterSpec;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_sign + (JNIEnv *, jobject, jbyteArray, jbyteArray, jobject); + +/* + * Class: cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_Botan + * Method: verify + * Signature: ([B[B[BLjava/security/spec/ECParameterSpec;)Z + */ +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024Botan_verify + (JNIEnv *, jobject, jbyteArray, jbyteArray, jbyteArray, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c new file mode 100644 index 0000000..29ee707 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/libs/jni/tomcrypt.c @@ -0,0 +1,450 @@ +#include "native.h" +#include <stdio.h> +#include <string.h> +#include <tomcrypt.h> +#include "c_utils.h" + +static prng_state ltc_prng; +static jclass provider_class; + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_createProvider(JNIEnv *env, jobject this) { + /* Create the custom provider. */ + jclass local_provider_class = (*env)->FindClass(env, "cz/crcs/ectester/standalone/libs/jni/NativeProvider$TomCrypt"); + provider_class = (*env)->NewGlobalRef(env, local_provider_class); + + jmethodID init = (*env)->GetMethodID(env, local_provider_class, "<init>", "(Ljava/lang/String;DLjava/lang/String;)V"); + + jstring name = (*env)->NewStringUTF(env, "libtomcrypt " SCRYPT); + double version = strtod(SCRYPT, NULL); + + return (*env)->NewObject(env, provider_class, init, name, version, name); +} + + +JNIEXPORT void JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeProvider_00024TomCrypt_setup(JNIEnv *env, jobject this) { + /* Initialize libtommath as the math lib. */ + ltc_mp = ltm_desc; + + jmethodID provider_put = (*env)->GetMethodID(env, provider_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + jstring ec = (*env)->NewStringUTF(env, "KeyPairGenerator.EC"); + jstring ec_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyPairGeneratorSpi$TomCrypt"); + (*env)->CallObjectMethod(env, this, provider_put, ec, ec_value); + + jstring ecdh = (*env)->NewStringUTF(env, "KeyAgreement.ECDH"); + jstring ecdh_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeKeyAgreementSpi$TomCrypt"); + (*env)->CallObjectMethod(env, this, provider_put, ecdh, ecdh_value); + + jstring ecdsa = (*env)->NewStringUTF(env, "Signature.NONEwithECDSA"); + jstring ecdsa_value = (*env)->NewStringUTF(env, "cz.crcs.ectester.standalone.libs.jni.NativeSignatureSpi$TomCryptRaw"); + (*env)->CallObjectMethod(env, this, provider_put, ecdsa, ecdsa_value); + + int err; + /* register yarrow */ + if (register_prng(&yarrow_desc) == -1) { + fprintf(stderr, "Error registering Yarrow\n"); + return; + } + /* setup the PRNG */ + if ((err = rng_make_prng(128, find_prng("yarrow"), <c_prng, NULL)) != CRYPT_OK) { + fprintf(stderr, "Error setting up PRNG, %s\n", error_to_string(err)); + } + + init_classes(env, "TomCrypt"); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_TomcryptLib_getCurves(JNIEnv *env, jobject this) { + jclass hash_set_class = (*env)->FindClass(env, "java/util/TreeSet"); + + jmethodID hash_set_ctr = (*env)->GetMethodID(env, hash_set_class, "<init>", "()V"); + jmethodID hash_set_add = (*env)->GetMethodID(env, hash_set_class, "add", "(Ljava/lang/Object;)Z"); + + jobject result = (*env)->NewObject(env, hash_set_class, hash_set_ctr); + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + jstring curve_name = (*env)->NewStringUTF(env, curve->name); + (*env)->CallBooleanMethod(env, result, hash_set_add, curve_name); + curve++; + } + + return result; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_keysizeSupported(JNIEnv *env, jobject this, jint keysize){ + int key_bytes = (keysize + 7) / 8; + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + if (curve->size == key_bytes) { + return JNI_TRUE; + } + curve++; + } + + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_paramsSupported(JNIEnv *env, jobject this, jobject params){ + if (params == NULL) { + return JNI_FALSE; + } + + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, curve, get_field); + + if ((*env)->IsInstanceOf(env, field, fp_field_class)) { + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + jmethodID get_a = (*env)->GetMethodID(env, elliptic_curve_class, "getA", "()Ljava/math/BigInteger;"); + jobject a = (*env)->CallObjectMethod(env, curve, get_a); + + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong)3); + + jmethodID biginteger_add = (*env)->GetMethodID(env, biginteger_class, "add", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;"); + jobject a_3 = (*env)->CallObjectMethod(env, a, biginteger_add, three); + + jmethodID biginteger_equals = (*env)->GetMethodID(env, biginteger_class, "equals", "(Ljava/lang/Object;)Z"); + jboolean eq = (*env)->CallBooleanMethod(env, p, biginteger_equals, a_3); + return eq; + } else if ((*env)->IsInstanceOf(env, field, f2m_field_class)) { + return JNI_FALSE; + } else { + return JNI_FALSE; + } + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char *utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const ltc_ecc_set_type * curve = ltc_ecc_sets; + while (curve->size != 0) { + if (strcasecmp(utf_name, curve->name) == 0) { + (*env)->ReleaseStringUTFChars(env, name, utf_name); + return JNI_TRUE; + } + curve++; + } + return JNI_FALSE; + } else { + return JNI_FALSE; + } +} + +static jobject create_ec_param_spec(JNIEnv *env, const ltc_ecc_set_type *curve) { + jstring p_string = (*env)->NewStringUTF(env, curve->prime); + jmethodID biginteger_init = (*env)->GetMethodID(env, biginteger_class, "<init>", "(Ljava/lang/String;I)V"); + jobject p = (*env)->NewObject(env, biginteger_class, biginteger_init, p_string, (jint) 16); + + jmethodID fp_field_init = (*env)->GetMethodID(env, fp_field_class, "<init>", "(Ljava/math/BigInteger;)V"); + jobject field = (*env)->NewObject(env, fp_field_class, fp_field_init, p); + + jmethodID biginteger_subtract = (*env)->GetMethodID(env, biginteger_class, "subtract", "(Ljava/math/BigInteger;)Ljava/math/BigInteger;"); + jmethodID biginteger_valueof = (*env)->GetStaticMethodID(env, biginteger_class, "valueOf", "(J)Ljava/math/BigInteger;"); + jobject three = (*env)->CallStaticObjectMethod(env, biginteger_class, biginteger_valueof, (jlong) 3); + jobject a = (*env)->CallObjectMethod(env, p, biginteger_subtract, three); + + jstring b_string = (*env)->NewStringUTF(env, curve->B); + jobject b = (*env)->NewObject(env, biginteger_class, biginteger_init, b_string, (jint) 16); + + jmethodID elliptic_curve_init = (*env)->GetMethodID(env, elliptic_curve_class, "<init>", "(Ljava/security/spec/ECField;Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject elliptic_curve = (*env)->NewObject(env, elliptic_curve_class, elliptic_curve_init, field, a, b); + + jstring gx_string = (*env)->NewStringUTF(env, curve->Gx); + jstring gy_string = (*env)->NewStringUTF(env, curve->Gy); + jobject gx = (*env)->NewObject(env, biginteger_class, biginteger_init, gx_string, (jint) 16); + jobject gy = (*env)->NewObject(env, biginteger_class, biginteger_init, gy_string, (jint) 16); + + jmethodID point_init = (*env)->GetMethodID(env, point_class, "<init>", "(Ljava/math/BigInteger;Ljava/math/BigInteger;)V"); + jobject g = (*env)->NewObject(env, point_class, point_init, gx, gy); + + jstring n_string = (*env)->NewStringUTF(env, curve->order); + jobject n = (*env)->NewObject(env, biginteger_class, biginteger_init, n_string, (jint) 16); + + jmethodID ec_parameter_spec_init = (*env)->GetMethodID(env, ec_parameter_spec_class, "<init>", "(Ljava/security/spec/EllipticCurve;Ljava/security/spec/ECPoint;Ljava/math/BigInteger;I)V"); + return (*env)->NewObject(env, ec_parameter_spec_class, ec_parameter_spec_init, elliptic_curve, g, n, (jint) 1); +} + +static char *biginteger_to_hex(JNIEnv *env, jobject big, jint bytes) { + jmethodID to_string = (*env)->GetMethodID(env, biginteger_class, "toString", "(I)Ljava/lang/String;"); + jstring big_string = (*env)->CallObjectMethod(env, big, to_string, (jint) 16); + + jsize len = (*env)->GetStringUTFLength(env, big_string); + char raw_string[len]; + (*env)->GetStringUTFRegion(env, big_string, 0, len, raw_string); + + char *result = calloc(bytes, 2); + if (len >= bytes) { + return strncpy(result, raw_string, 2*bytes); + } else { + jsize diff = bytes - len; + for (jint i = 0; i < diff*2; ++i) { + result[i] = '0'; + } + return strncpy(result + diff*2, raw_string, 2*bytes); + } +} + +static ltc_ecc_set_type* create_curve(JNIEnv *env, jobject params) { + jmethodID get_curve = (*env)->GetMethodID(env, ec_parameter_spec_class, "getCurve", "()Ljava/security/spec/EllipticCurve;"); + jobject elliptic_curve = (*env)->CallObjectMethod(env, params, get_curve); + + jmethodID get_field = (*env)->GetMethodID(env, elliptic_curve_class, "getField", "()Ljava/security/spec/ECField;"); + jobject field = (*env)->CallObjectMethod(env, elliptic_curve, get_field); + + jmethodID get_bits = (*env)->GetMethodID(env, fp_field_class, "getFieldSize", "()I"); + jint bits = (*env)->CallIntMethod(env, field, get_bits); + jint bytes = (bits + 7) / 8; + + jmethodID get_b = (*env)->GetMethodID(env, elliptic_curve_class, "getB", "()Ljava/math/BigInteger;"); + jobject b = (*env)->CallObjectMethod(env, elliptic_curve, get_b); + + jmethodID get_p = (*env)->GetMethodID(env, fp_field_class, "getP", "()Ljava/math/BigInteger;"); + jobject p = (*env)->CallObjectMethod(env, field, get_p); + + jmethodID get_g = (*env)->GetMethodID(env, ec_parameter_spec_class, "getGenerator", "()Ljava/security/spec/ECPoint;"); + jobject g = (*env)->CallObjectMethod(env, params, get_g); + + jmethodID get_x = (*env)->GetMethodID(env, point_class, "getAffineX", "()Ljava/math/BigInteger;"); + jobject gx = (*env)->CallObjectMethod(env, g, get_x); + + jmethodID get_y = (*env)->GetMethodID(env, point_class, "getAffineY", "()Ljava/math/BigInteger;"); + jobject gy = (*env)->CallObjectMethod(env, g, get_y); + + jmethodID get_n = (*env)->GetMethodID(env, ec_parameter_spec_class, "getOrder", "()Ljava/math/BigInteger;"); + jobject n = (*env)->CallObjectMethod(env, params, get_n); + + ltc_ecc_set_type *curve = calloc(sizeof(ltc_ecc_set_type), 1); + curve->size = bytes; + curve->name = ""; + curve->prime = biginteger_to_hex(env, p, bytes); + curve->B = biginteger_to_hex(env, b, bytes); + curve->order = biginteger_to_hex(env, n, bytes); + curve->Gx = biginteger_to_hex(env, gx, bytes); + curve->Gy = biginteger_to_hex(env, gy, bytes); + + return curve; +} + +static jobject generate_from_curve(JNIEnv *env, const ltc_ecc_set_type *curve) { + ecc_key key; + int err; + if ((err = ecc_make_key_ex(<c_prng, find_prng("yarrow"), &key, curve)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + return NULL; + } + unsigned long key_len = 2*curve->size + 1; + jbyteArray pub_bytes = (*env)->NewByteArray(env, key_len); + jbyte *key_pub = (*env)->GetByteArrayElements(env, pub_bytes, NULL); + ecc_ansi_x963_export(&key, key_pub, &key_len); + (*env)->ReleaseByteArrayElements(env, pub_bytes, key_pub, JNI_COMMIT); + + jobject ec_param_spec = create_ec_param_spec(env, curve); + + jobject ec_pub_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_pub_init = (*env)->GetMethodID(env, pubkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject pubkey = (*env)->NewObject(env, pubkey_class, ec_pub_init, pub_bytes, ec_param_spec); + + jbyteArray priv_bytes = (*env)->NewByteArray(env, curve->size); + jbyte *key_priv = (*env)->GetByteArrayElements(env, priv_bytes, NULL); + ltc_mp.unsigned_write(key.k, key_priv); + (*env)->ReleaseByteArrayElements(env, priv_bytes, key_priv, JNI_COMMIT); + + jobject ec_priv_param_spec = (*env)->NewLocalRef(env, ec_param_spec); + jmethodID ec_priv_init = (*env)->GetMethodID(env, privkey_class, "<init>", "([BLjava/security/spec/ECParameterSpec;)V"); + jobject privkey = (*env)->NewObject(env, privkey_class, ec_priv_init, priv_bytes, ec_priv_param_spec); + + jmethodID keypair_init = (*env)->GetMethodID(env, keypair_class, "<init>", "(Ljava/security/PublicKey;Ljava/security/PrivateKey;)V"); + + ecc_free(&key); + return (*env)->NewObject(env, keypair_class, keypair_init, pubkey, privkey); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__ILjava_security_SecureRandom_2(JNIEnv *env, jobject this, jint keysize, jobject random){ + int key_bytes = (keysize + 7) / 8; + + const ltc_ecc_set_type *curve = ltc_ecc_sets; + while (curve->size != 0) { + if (curve->size == key_bytes) { + break; + } + curve++; + } + + if (curve->size == 0) { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve for given bitsize not found."); + return NULL; + } + + return generate_from_curve(env, curve); +} + +JNIEXPORT jobject JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyPairGeneratorSpi_00024TomCrypt_generate__Ljava_security_spec_AlgorithmParameterSpec_2Ljava_security_SecureRandom_2(JNIEnv *env, jobject this, jobject params, jobject random){ + if ((*env)->IsInstanceOf(env, params, ec_parameter_spec_class)) { + ltc_ecc_set_type *curve = create_curve(env, params); + jobject result = generate_from_curve(env, curve); + free(curve); + return result; + } else if ((*env)->IsInstanceOf(env, params, ecgen_parameter_spec_class)) { + jmethodID get_name = (*env)->GetMethodID(env, ecgen_parameter_spec_class, "getName", "()Ljava/lang/String;"); + jstring name = (*env)->CallObjectMethod(env, params, get_name); + const char* utf_name = (*env)->GetStringUTFChars(env, name, NULL); + const ltc_ecc_set_type* curve = ltc_ecc_sets; + while (curve->size != 0) { + if (strcasecmp(utf_name, curve->name) == 0) { + break; + } + curve++; + } + (*env)->ReleaseStringUTFChars(env, name, utf_name); + + return generate_from_curve(env, curve); + } else { + throw_new(env, "java/security/InvalidAlgorithmParameterException", "Curve not found."); + return NULL; + } +} + +static jboolean privkey_from_bytes(JNIEnv *env, jbyteArray privkey, const ltc_ecc_set_type *curve, ecc_key *out) { + jsize priv_size = (*env)->GetArrayLength(env, privkey); + jbyte *priv_data = (*env)->GetByteArrayElements(env, privkey, NULL); + + if (curve->size != priv_size) { + throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the private key size."); + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_FALSE; + } + + out->type = PK_PRIVATE; + out->idx = -1; + out->dp = curve; + ltc_mp.init(&out->k); + ltc_mp.unsigned_read(out->k, priv_data, (unsigned long) curve->size); + + (*env)->ReleaseByteArrayElements(env, privkey, priv_data, JNI_ABORT); + return JNI_TRUE; +} + +static jboolean pubkey_from_bytes(JNIEnv *env, jbyteArray pubkey, const ltc_ecc_set_type *curve, ecc_key *out) { + jsize pub_size = (*env)->GetArrayLength(env, pubkey); + jbyte *pub_data = (*env)->GetByteArrayElements(env, pubkey, NULL); + + if (curve->size != (pub_size - 1) / 2) { + throw_new(env, "java/lang/IllegalStateException", "Curve size does not match the public key size."); + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + return JNI_FALSE; + } + + out->type = PK_PUBLIC; + out->idx = -1; + out->dp = curve; + ltc_init_multi(&out->pubkey.x, &out->pubkey.y, &out->pubkey.z, NULL); + ltc_mp.set_int(out->pubkey.z, 1); + ltc_mp.unsigned_read(out->pubkey.x, pub_data + 1, (unsigned long) curve->size); + ltc_mp.unsigned_read(out->pubkey.y, pub_data + 1 + curve->size, (unsigned long) curve->size); + + (*env)->ReleaseByteArrayElements(env, pubkey, pub_data, JNI_ABORT); + + return JNI_TRUE; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeKeyAgreementSpi_00024TomCrypt_generateSecret(JNIEnv *env, jobject this, jbyteArray pubkey, jbyteArray privkey, jobject params){ + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { + free(curve); + return NULL; + } + + ecc_key priv; + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } + + unsigned char result[curve->size]; + unsigned long output_len = curve->size; + int err; + if ((err = ecc_shared_secret(&priv, &pub, result, &output_len)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + return NULL; + } + + jbyteArray output = (*env)->NewByteArray(env, curve->size); + jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL); + memcpy(output_data, result, curve->size); + (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT); + + ltc_cleanup_multi(&pub.pubkey.x, &pub.pubkey.y, &pub.pubkey.z, &priv.k, NULL); + free(curve); + return output; +} + +JNIEXPORT jbyteArray JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_sign(JNIEnv *env, jobject this, jbyteArray data, jbyteArray privkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key priv; + if (!privkey_from_bytes(env, privkey, curve, &priv)) { + free(curve); + return NULL; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + unsigned char result[curve->size*4]; + unsigned long output_len = curve->size*4; + int err; + if ((err = ecc_sign_hash(data_data, data_size, result, &output_len, <c_prng, find_prng("yarrow"), &priv)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + return NULL; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + + jbyteArray output = (*env)->NewByteArray(env, output_len); + jbyte *output_data = (*env)->GetByteArrayElements(env, output, NULL); + memcpy(output_data, result, output_len); + (*env)->ReleaseByteArrayElements(env, output, output_data, JNI_COMMIT); + + free(curve); + return output; +} + +JNIEXPORT jboolean JNICALL Java_cz_crcs_ectester_standalone_libs_jni_NativeSignatureSpi_00024TomCryptRaw_verify(JNIEnv *env, jobject this, jbyteArray signature, jbyteArray data, jbyteArray pubkey, jobject params) { + ltc_ecc_set_type *curve = create_curve(env, params); + + ecc_key pub; + if (!pubkey_from_bytes(env, pubkey, curve, &pub)) { + free(curve); + return JNI_FALSE; + } + + jsize data_size = (*env)->GetArrayLength(env, data); + jbyte *data_data = (*env)->GetByteArrayElements(env, data, NULL); + + jsize sig_size = (*env)->GetArrayLength(env, signature); + jbyte *sig_data = (*env)->GetByteArrayElements(env, signature, NULL); + + int err; + int result; + if ((err = ecc_verify_hash(sig_data, sig_size, data_data, data_size, &result, &pub)) != CRYPT_OK) { + throw_new(env, "java/security/GeneralSecurityException", error_to_string(err)); + free(curve); + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + return JNI_FALSE; + } + + (*env)->ReleaseByteArrayElements(env, data, data_data, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, signature, sig_data, JNI_ABORT); + free(curve); + return result; +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/output/TextTestWriter.java b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java new file mode 100644 index 0000000..972af18 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/output/TextTestWriter.java @@ -0,0 +1,28 @@ +package cz.crcs.ectester.standalone.output; + +import cz.crcs.ectester.common.output.BaseTextTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; + +import java.io.PrintStream; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class TextTestWriter extends BaseTextTestWriter { + public TextTestWriter(PrintStream output) { + super(output); + } + + @Override + protected String testableString(Testable t) { + //TODO + return ""; + } + + @Override + protected String deviceString(TestSuite suite) { + //TODO + return ""; + } +}
\ No newline at end of file diff --git a/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java new file mode 100644 index 0000000..d2b16d8 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/output/XMLTestWriter.java @@ -0,0 +1,119 @@ +package cz.crcs.ectester.standalone.output; + +import cz.crcs.ectester.common.output.BaseXMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.standalone.test.KeyAgreementTestable; +import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; +import cz.crcs.ectester.standalone.test.SignatureTestable; +import org.w3c.dom.Element; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.OutputStream; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class XMLTestWriter extends BaseXMLTestWriter { + + public XMLTestWriter(OutputStream output) throws ParserConfigurationException { + super(output); + } + + private Element pkeyElement(PublicKey pkey) { + Element pubkey = doc.createElement("pubkey"); + if (pkey == null) { + return pubkey; + } + pubkey.setAttribute("algorithm", pkey.getAlgorithm()); + pubkey.setAttribute("format", pkey.getFormat()); + pubkey.setTextContent(ByteUtil.bytesToHex(pkey.getEncoded())); + return pubkey; + } + + private Element skeyElement(PrivateKey skey) { + Element privkey = doc.createElement("privkey"); + if (skey == null) { + return privkey; + } + privkey.setAttribute("algorithm", skey.getAlgorithm()); + privkey.setAttribute("format", skey.getFormat()); + privkey.setTextContent(ByteUtil.bytesToHex(skey.getEncoded())); + return privkey; + } + + private Element kaElement(KeyAgreementTestable kat) { + Element katElem = doc.createElement("key-agreement"); + katElem.setAttribute("algo", kat.getKa().getAlgorithm()); + + Element secret = doc.createElement("secret"); + secret.setTextContent(ByteUtil.bytesToHex(kat.getSecret())); + katElem.appendChild(secret); + + PublicKey pkey = kat.getPublicKey(); + Element pubkey = pkeyElement(pkey); + katElem.appendChild(pubkey); + + PrivateKey skey = kat.getPrivateKey(); + Element privkey = skeyElement(skey); + katElem.appendChild(privkey); + + return katElem; + } + + private Element kgtElement(KeyGeneratorTestable kgt) { + Element kgtElem = doc.createElement("key-pair-generator"); + kgtElem.setAttribute("algo", kgt.getKpg().getAlgorithm()); + + Element keyPair = doc.createElement("key-pair"); + if (kgt.getKeyPair() != null) { + PublicKey pkey = kgt.getKeyPair().getPublic(); + Element pubkey = pkeyElement(pkey); + keyPair.appendChild(pubkey); + + PrivateKey skey = kgt.getKeyPair().getPrivate(); + Element privkey = skeyElement(skey); + keyPair.appendChild(privkey); + } + + kgtElem.appendChild(keyPair); + return kgtElem; + } + + private Element sigElement(SignatureTestable sig) { + Element sigElem = doc.createElement("signature"); + sigElem.setAttribute("verified", sig.getVerified() ? "true" : "false"); + sigElem.setAttribute("algo", sig.getSig().getAlgorithm()); + + Element raw = doc.createElement("raw"); + raw.setTextContent(ByteUtil.bytesToHex(sig.getSignature())); + sigElem.appendChild(raw); + + return sigElem; + } + + @Override + protected Element testableElement(Testable t) { + Element result = doc.createElement("test"); + if (t instanceof KeyGeneratorTestable) { + result.setAttribute("type", "key-pair-generator"); + result.appendChild(kgtElement((KeyGeneratorTestable) t)); + } else if (t instanceof KeyAgreementTestable) { + result.setAttribute("type", "key-agreement"); + result.appendChild(kaElement((KeyAgreementTestable) t)); + } else if (t instanceof SignatureTestable) { + result.setAttribute("type", "signature"); + result.appendChild(sigElement((SignatureTestable) t)); + } + return result; + } + + @Override + protected Element deviceElement(TestSuite suite) { + //TODO + return null; + } +} diff --git a/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java new file mode 100644 index 0000000..dfc6813 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/output/YAMLTestWriter.java @@ -0,0 +1,98 @@ +package cz.crcs.ectester.standalone.output; + +import cz.crcs.ectester.common.output.BaseYAMLTestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.common.test.Testable; +import cz.crcs.ectester.common.util.ByteUtil; +import cz.crcs.ectester.standalone.test.KeyAgreementTestable; +import cz.crcs.ectester.standalone.test.KeyGeneratorTestable; +import cz.crcs.ectester.standalone.test.SignatureTestable; + +import java.io.PrintStream; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class YAMLTestWriter extends BaseYAMLTestWriter { + public YAMLTestWriter(PrintStream output) { + super(output); + } + + private Map<String, Object> keyObject(Key key) { + Map<String, Object> kObject = new HashMap<>(); + if (key == null) { + return kObject; + } + kObject.put("algo", key.getAlgorithm()); + kObject.put("format", key.getFormat()); + kObject.put("raw", ByteUtil.bytesToHex(key.getEncoded())); + return kObject; + } + + private Map<String, Object> kaObject(KeyAgreementTestable kat) { + Map<String, Object> katObject = new HashMap<>(); + katObject.put("algo", kat.getKa().getAlgorithm()); + katObject.put("secret", ByteUtil.bytesToHex(kat.getSecret())); + + PublicKey pkey = kat.getPublicKey(); + katObject.put("pubkey", keyObject(pkey)); + + PrivateKey skey = kat.getPrivateKey(); + katObject.put("privkey", keyObject(skey)); + return katObject; + } + + private Map<String, Object> kgtObject(KeyGeneratorTestable kgt) { + Map<String, Object> kgtObject = new HashMap<>(); + kgtObject.put("algo", kgt.getKpg().getAlgorithm()); + + Map<String, Object> keypair = new HashMap<>(); + if (kgt.getKeyPair() != null) { + PublicKey pkey = kgt.getKeyPair().getPublic(); + Map<String, Object> pubObject = keyObject(pkey); + keypair.put("pubkey", pubObject); + + PrivateKey skey = kgt.getKeyPair().getPrivate(); + Map<String, Object> privObject = keyObject(skey); + keypair.put("privkey", privObject); + } + + kgtObject.put("keypair", keypair); + return kgtObject; + } + + private Map<String, Object> sigObject(SignatureTestable sig) { + Map<String, Object> sigObject = new HashMap<>(); + sigObject.put("algo", sig.getSig().getAlgorithm()); + sigObject.put("verified", sig.getVerified()); + sigObject.put("raw", ByteUtil.bytesToHex(sig.getSignature())); + return sigObject; + } + + @Override + protected Map<String, Object> testableObject(Testable t) { + Map<String, Object> result = new HashMap<>(); + if (t instanceof KeyGeneratorTestable) { + result.put("type", "key-pair-generator"); + result.put("key-pair-generator", kgtObject((KeyGeneratorTestable) t)); + } else if (t instanceof KeyAgreementTestable) { + result.put("type", "key-agreement"); + result.put("key-agreement", kaObject((KeyAgreementTestable) t)); + } else if (t instanceof SignatureTestable) { + result.put("type", "signature"); + result.put("signature", sigObject((SignatureTestable) t)); + } + return result; + } + + @Override + protected Map<String, Object> deviceObject(TestSuite suite) { + //TODO + return null; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java new file mode 100644 index 0000000..5f697c4 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTest.java @@ -0,0 +1,57 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; + +import java.util.Arrays; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTest extends SimpleTest<KeyAgreementTestable> { + private KeyAgreementTest(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) { + super(ka, callback); + } + + public static KeyAgreementTest match(KeyAgreementTestable ka, byte[] expectedSecret) { + return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() { + @Override + public Result apply(KeyAgreementTestable ka) { + if (Arrays.equals(ka.getSecret(), expectedSecret)) { + return new Result(Result.Value.SUCCESS, "The KeyAgreement result matched the expected derived secret."); + } else { + return new Result(Result.Value.FAILURE, "The KeyAgreement result did not match the expected derived secret."); + } + } + }); + } + + public static KeyAgreementTest expect(KeyAgreementTestable ka, Result.ExpectedValue expected) { + return new KeyAgreementTest(ka, new TestCallback<KeyAgreementTestable>() { + @Override + public Result apply(KeyAgreementTestable keyAgreementTestable) { + return new Result(Result.Value.fromExpected(expected, keyAgreementTestable.ok(), keyAgreementTestable.error())); + } + }); + } + + public static KeyAgreementTest function(KeyAgreementTestable ka, TestCallback<KeyAgreementTestable> callback) { + return new KeyAgreementTest(ka, callback); + } + + @Override + public String getDescription() { + return "KeyAgreement " + testable.getKa().getAlgorithm(); + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + testable.run(); + result = callback.apply(testable); + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java new file mode 100644 index 0000000..de9356b --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyAgreementTestable.java @@ -0,0 +1,124 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.BaseTestable; +import cz.crcs.ectester.common.test.TestException; + +import javax.crypto.KeyAgreement; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyAgreementTestable extends BaseTestable { + private KeyAgreement ka; + private ECPrivateKey privateKey; + private ECPublicKey publicKey; + private KeyGeneratorTestable kgtPrivate; + private KeyGeneratorTestable kgtPublic; + private AlgorithmParameterSpec spec; + private byte[] secret; + + public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey) { + this.ka = ka; + this.privateKey = privateKey; + this.publicKey = publicKey; + } + + public KeyAgreementTestable(KeyAgreement ka, ECPrivateKey privateKey, ECPublicKey publicKey, ECParameterSpec spec) { + this(ka, privateKey, publicKey); + this.spec = spec; + } + + public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable kgt, ECPrivateKey privateKey, ECParameterSpec spec) { + this(ka, privateKey, null, spec); + this.kgtPublic = kgt; + } + + public KeyAgreementTestable(KeyAgreement ka, ECPublicKey publicKey, KeyGeneratorTestable kgt, ECParameterSpec spec) { + this(ka, null, publicKey, spec); + this.kgtPrivate = kgt; + } + + public KeyAgreementTestable(KeyAgreement ka, KeyGeneratorTestable privKgt, KeyGeneratorTestable pubKgt, ECParameterSpec spec) { + this(ka, (ECPrivateKey) null, null, spec); + this.kgtPrivate = privKgt; + this.kgtPublic = pubKgt; + } + + public KeyAgreement getKa() { + return ka; + } + + public ECPublicKey getPublicKey() { + return publicKey; + } + + public ECPrivateKey getPrivateKey() { + return privateKey; + } + + public byte[] getSecret() { + if (!hasRun) { + return null; + } + return secret; + } + + @Override + public void run() throws TestException { + if (kgtPrivate != null) { + privateKey = (ECPrivateKey) kgtPrivate.getKeyPair().getPrivate(); + } + + if (kgtPublic != null) { + publicKey = (ECPublicKey) kgtPublic.getKeyPair().getPublic(); + } + + try { + if (spec != null) { + ka.init(privateKey, spec); + } else { + ka.init(privateKey); + } + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + ok = false; + error = true; + hasRun = true; + return; + } + + try { + ka.doPhase(publicKey, true); + } catch (IllegalStateException e) { + ok = false; + hasRun = true; + return; + } catch (InvalidKeyException e) { + ok = false; + error = true; + hasRun = true; + return; + } + + try { + secret = ka.generateSecret(); + } catch (IllegalStateException isex) { + ok = false; + hasRun = true; + return; + } catch (UnsupportedOperationException uoe) { + ok = false; + error = true; + hasRun = false; + return; + } + + ok = true; + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java new file mode 100644 index 0000000..93273ca --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTest.java @@ -0,0 +1,42 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class KeyGeneratorTest extends SimpleTest<KeyGeneratorTestable> { + private KeyGeneratorTest(KeyGeneratorTestable kg, TestCallback<KeyGeneratorTestable> callback) { + super(kg, callback); + } + + public static KeyGeneratorTest expect(KeyGeneratorTestable kg, Result.ExpectedValue expected) { + return new KeyGeneratorTest(kg, new TestCallback<KeyGeneratorTestable>() { + @Override + public Result apply(KeyGeneratorTestable keyGenerationTestable) { + return new Result(Result.Value.fromExpected(expected, keyGenerationTestable.ok(), keyGenerationTestable.error())); + } + }); + } + + public static KeyGeneratorTest function(KeyGeneratorTestable ka, TestCallback<KeyGeneratorTestable> callback) { + return new KeyGeneratorTest(ka, callback); + } + + @Override + public String getDescription() { + return "KeyPairGenerator " + testable.getKpg().getAlgorithm(); + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + testable.run(); + result = callback.apply(testable); + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java new file mode 100644 index 0000000..3fca168 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/KeyGeneratorTestable.java @@ -0,0 +1,56 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.BaseTestable; +import cz.crcs.ectester.common.test.TestException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.spec.ECParameterSpec; + +public class KeyGeneratorTestable extends BaseTestable { + private KeyPair kp; + private KeyPairGenerator kpg; + private int keysize = 0; + private ECParameterSpec spec = null; + + public KeyGeneratorTestable(KeyPairGenerator kpg) { + this.kpg = kpg; + } + + public KeyGeneratorTestable(KeyPairGenerator kpg, int keysize) { + this.kpg = kpg; + this.keysize = keysize; + } + + public KeyGeneratorTestable(KeyPairGenerator kpg, ECParameterSpec spec) { + this.kpg = kpg; + this.spec = spec; + } + + public KeyPairGenerator getKpg() { + return kpg; + } + + public KeyPair getKeyPair() { + return kp; + } + + @Override + public void run() throws TestException { + try { + if (spec != null) { + kpg.initialize(spec); + } else if (keysize != 0) { + kpg.initialize(keysize); + } + } catch (InvalidAlgorithmParameterException e) { + hasRun = true; + ok = false; + return; + } + kp = kpg.genKeyPair(); + hasRun = true; + ok = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTest.java b/src/cz/crcs/ectester/standalone/test/SignatureTest.java new file mode 100644 index 0000000..9746b91 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/SignatureTest.java @@ -0,0 +1,42 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.common.test.SimpleTest; +import cz.crcs.ectester.common.test.TestCallback; +import cz.crcs.ectester.common.test.TestException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class SignatureTest extends SimpleTest<SignatureTestable> { + private SignatureTest(SignatureTestable sig, TestCallback<SignatureTestable> callback) { + super(sig, callback); + } + + public static SignatureTest expect(SignatureTestable kg, Result.ExpectedValue expected) { + return new SignatureTest(kg, new TestCallback<SignatureTestable>() { + @Override + public Result apply(SignatureTestable signatureTestable) { + return new Result(Result.Value.fromExpected(expected, signatureTestable.ok(), signatureTestable.error())); + } + }); + } + + public static SignatureTest function(SignatureTestable ka, TestCallback<SignatureTestable> callback) { + return new SignatureTest(ka, callback); + } + + @Override + public String getDescription() { + return "Signature " + testable.getSig().getAlgorithm(); + } + + @Override + public void run() throws TestException { + if (hasRun) + return; + testable.run(); + result = callback.apply(testable); + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/SignatureTestable.java b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java new file mode 100644 index 0000000..e434337 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/SignatureTestable.java @@ -0,0 +1,107 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.test.BaseTestable; +import cz.crcs.ectester.common.test.TestException; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; + +public class SignatureTestable extends BaseTestable { + private Signature sig; + private ECPrivateKey signKey; + private ECPublicKey verifyKey; + private KeyGeneratorTestable kgt; + private byte[] data; + private byte[] signature; + private boolean verified; + + public SignatureTestable(Signature sig, ECPrivateKey signKey, ECPublicKey verifyKey, byte[] data) { + this.sig = sig; + this.signKey = signKey; + this.verifyKey = verifyKey; + this.data = data; + if (data == null) { + SecureRandom random = new SecureRandom(); + this.data = new byte[32]; + random.nextBytes(this.data); + } + } + + public SignatureTestable(Signature sig, KeyGeneratorTestable kgt, byte[] data) { + this(sig, null, null, data); + this.kgt = kgt; + } + + public Signature getSig() { + return sig; + } + + public byte[] getData() { + return data; + } + + public byte[] getSignature() { + return signature; + } + + public boolean getVerified() { + return verified; + } + + @Override + public void run() throws TestException { + if (kgt != null) { + signKey = (ECPrivateKey) kgt.getKeyPair().getPrivate(); + verifyKey = (ECPublicKey) kgt.getKeyPair().getPublic(); + } + + try { + sig.initSign(signKey); + } catch (InvalidKeyException e) { + throw new TestException(e); + } + + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + signature = sig.sign(); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + sig.initVerify(verifyKey); + } catch (InvalidKeyException e) { + throw new TestException(e); + } + + try { + sig.update(data); + } catch (SignatureException e) { + ok = false; + hasRun = true; + return; + } + + try { + verified = sig.verify(signature); + } catch (SignatureException e) { + ok = false; + hasRun = true; + } + ok = true; + hasRun = true; + } +} diff --git a/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java b/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java new file mode 100644 index 0000000..42d2e54 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/StandaloneDefaultSuite.java @@ -0,0 +1,76 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.cli.TreeCommandLine; +import cz.crcs.ectester.common.ec.EC_Curve; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.Result; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.ECTesterStandalone; +import cz.crcs.ectester.standalone.consts.KeyAgreementIdent; +import cz.crcs.ectester.standalone.consts.KeyPairGeneratorIdent; +import cz.crcs.ectester.standalone.consts.SignatureIdent; + +import javax.crypto.KeyAgreement; +import java.security.KeyPairGenerator; +import java.security.Signature; +import java.security.spec.ECParameterSpec; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public class StandaloneDefaultSuite extends StandaloneTestSuite { + + public StandaloneDefaultSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli) { + super(writer, cfg, cli, "default", "The default test suite run basic support of ECDH and ECDSA."); + } + + @Override + protected void runTests() throws Exception { + String kpgAlgo = cli.getOptionValue("test.kpg-type", "EC"); + String kaAlgo = cli.getOptionValue("test.ka-type"); + String sigAlgo = cli.getOptionValue("test.sig-type"); + + KeyPairGeneratorIdent kpgIdent = cfg.selected.getKPGs().stream() + .filter((ident) -> ident.contains(kpgAlgo)) + .findFirst().get(); + KeyPairGenerator kpg = kpgIdent.getInstance(cfg.selected.getProvider()); + + KeyGeneratorTestable kgtOne; + KeyGeneratorTestable kgtOther; + ECParameterSpec spec = null; + if (cli.hasOption("test.bits")) { + int bits = Integer.parseInt(cli.getOptionValue("test.bits")); + kgtOne = new KeyGeneratorTestable(kpg, bits); + kgtOther = new KeyGeneratorTestable(kpg, bits); + } else if (cli.hasOption("test.named-curve")) { + String curveName = cli.getOptionValue("test.named-curve"); + EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, curveName); + if (curve == null) { + System.err.println("Curve not found: " + curveName); + return; + } + spec = curve.toSpec(); + kgtOne = new KeyGeneratorTestable(kpg, spec); + kgtOther = new KeyGeneratorTestable(kpg, spec); + } else { + kgtOne = new KeyGeneratorTestable(kpg); + kgtOther = new KeyGeneratorTestable(kpg); + } + + doTest(KeyGeneratorTest.expect(kgtOne, Result.ExpectedValue.SUCCESS)); + doTest(KeyGeneratorTest.expect(kgtOther, Result.ExpectedValue.SUCCESS)); + + for (KeyAgreementIdent kaIdent : cfg.selected.getKAs()) { + if (kaAlgo == null || kaIdent.contains(kaAlgo)) { + KeyAgreement ka = kaIdent.getInstance(cfg.selected.getProvider()); + doTest(KeyAgreementTest.expect(new KeyAgreementTestable(ka, kgtOne, kgtOther, spec), Result.ExpectedValue.SUCCESS)); + } + } + for (SignatureIdent sigIdent : cfg.selected.getSigs()) { + if (sigAlgo == null || sigIdent.contains(sigAlgo)) { + Signature sig = sigIdent.getInstance(cfg.selected.getProvider()); + doTest(SignatureTest.expect(new SignatureTestable(sig, kgtOne, null), Result.ExpectedValue.SUCCESS)); + } + } + } +} diff --git a/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java b/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java new file mode 100644 index 0000000..ad404c8 --- /dev/null +++ b/src/cz/crcs/ectester/standalone/test/StandaloneTestSuite.java @@ -0,0 +1,23 @@ +package cz.crcs.ectester.standalone.test; + +import cz.crcs.ectester.common.cli.TreeCommandLine; +import cz.crcs.ectester.common.output.TestWriter; +import cz.crcs.ectester.common.test.TestSuite; +import cz.crcs.ectester.data.EC_Store; +import cz.crcs.ectester.standalone.ECTesterStandalone; + +import java.security.NoSuchAlgorithmException; + +/** + * @author Jan Jancar johny@neuromancer.sk + */ +public abstract class StandaloneTestSuite extends TestSuite { + TreeCommandLine cli; + ECTesterStandalone.Config cfg; + + public StandaloneTestSuite(TestWriter writer, ECTesterStandalone.Config cfg, TreeCommandLine cli, String name, String description) { + super(writer, name, description); + this.cfg = cfg; + this.cli = cli; + } +} |
