aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2017-03-06 22:56:34 +0100
committerJ08nY2017-03-06 22:56:34 +0100
commit117b35545288df5b01173d36bde451b414d31d66 (patch)
treeadd0ecbc48e95a398662bef9e41670df1c61243e
parent66bd8469e56cbe7c6bed823b376229a02ecdd37d (diff)
downloadECTester-117b35545288df5b01173d36bde451b414d31d66.tar.gz
ECTester-117b35545288df5b01173d36bde451b414d31d66.tar.zst
ECTester-117b35545288df5b01173d36bde451b414d31d66.zip
-rw-r--r--!uploader/ectester.capbin13790 -> 13789 bytes
-rwxr-xr-x!uploader/gppro_upload.sh2
-rwxr-xr-x!uploader/gppro_upload_emv.sh1
-rw-r--r--dist/ECTester.jarbin95810 -> 207768 bytes
-rw-r--r--src/cz/crcs/ectester/applet/ECTesterApplet.java4
-rw-r--r--src/cz/crcs/ectester/data/EC_Category.java70
-rw-r--r--src/cz/crcs/ectester/data/EC_Data.java230
-rw-r--r--src/cz/crcs/ectester/data/anomalous/curves.xml7
-rw-r--r--src/cz/crcs/ectester/data/brainpool/curves.xml5
-rw-r--r--src/cz/crcs/ectester/data/categories.xml13
-rw-r--r--src/cz/crcs/ectester/data/nist/curves.xml5
-rw-r--r--src/cz/crcs/ectester/data/schema.xsd18
-rw-r--r--src/cz/crcs/ectester/data/secg/curves.xml7
-rw-r--r--src/cz/crcs/ectester/data/secg/sect233k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect233r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect239k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect283k1.csv11
-rw-r--r--src/cz/crcs/ectester/data/secg/sect409k1.csv2
-rw-r--r--src/cz/crcs/ectester/data/secg/sect409r1.csv2
-rw-r--r--src/cz/crcs/ectester/data/smallpub/curves.xml5
-rw-r--r--src/cz/crcs/ectester/data/smallpub/keys.xml19
-rw-r--r--src/cz/crcs/ectester/data/wrong/curves.xml5
-rw-r--r--src/cz/crcs/ectester/reader/ECTester.java219
-rw-r--r--src/cz/crcs/ectester/reader/ec/EC_Curve.java41
-rw-r--r--src/cz/crcs/ectester/reader/ec/EC_Key.java53
-rw-r--r--src/cz/crcs/ectester/reader/ec/EC_Keypair.java30
-rw-r--r--src/cz/crcs/ectester/reader/ec/EC_Params.java (renamed from src/cz/crcs/ectester/reader/ECParams.java)192
27 files changed, 750 insertions, 197 deletions
diff --git a/!uploader/ectester.cap b/!uploader/ectester.cap
index 56b2e2e..e650bd7 100644
--- a/!uploader/ectester.cap
+++ b/!uploader/ectester.cap
Binary files differ
diff --git a/!uploader/gppro_upload.sh b/!uploader/gppro_upload.sh
index 47c7c97..a94a948 100755
--- a/!uploader/gppro_upload.sh
+++ b/!uploader/gppro_upload.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
java -jar gp.jar -delete 4543546573746572 -deletedeps -verbose
java -jar gp.jar -deletedeps -verbose -delete 4A43416C6754657374
diff --git a/!uploader/gppro_upload_emv.sh b/!uploader/gppro_upload_emv.sh
index 8f0c994..c3b42b1 100755
--- a/!uploader/gppro_upload_emv.sh
+++ b/!uploader/gppro_upload_emv.sh
@@ -1,3 +1,4 @@
+#!/usr/bin/env bash
java -jar gp.jar --deletedeps --verbose -emv --delete 4C6162616B417070
java -jar gp.jar --deletedeps --verbose -emv --delete 4A43416C6754657374
java -jar gp.jar --deletedeps --verbose -emv --delete 4543546573746572
diff --git a/dist/ECTester.jar b/dist/ECTester.jar
index 421b6ea..b0e5d5f 100644
--- a/dist/ECTester.jar
+++ b/dist/ECTester.jar
Binary files differ
diff --git a/src/cz/crcs/ectester/applet/ECTesterApplet.java b/src/cz/crcs/ectester/applet/ECTesterApplet.java
index ae19e28..323b971 100644
--- a/src/cz/crcs/ectester/applet/ECTesterApplet.java
+++ b/src/cz/crcs/ectester/applet/ECTesterApplet.java
@@ -225,10 +225,10 @@ public class ECTesterApplet extends Applet {
short len = 0;
if ((keyPair & KEYPAIR_LOCAL) != 0) {
- len += set(localKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), (short) 0);
+ len += set(localKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 5), (short) 0);
}
if ((keyPair & KEYPAIR_REMOTE) != 0) {
- len += set(remoteKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 6), len);
+ len += set(remoteKeypair, curve, params, corruptedParams, corruptionType, apdubuf, (short) (ISO7816.OFFSET_CDATA + 5), len);
}
apdu.setOutgoingAndSend((short) 0, len);
diff --git a/src/cz/crcs/ectester/data/EC_Category.java b/src/cz/crcs/ectester/data/EC_Category.java
new file mode 100644
index 0000000..aed7e7d
--- /dev/null
+++ b/src/cz/crcs/ectester/data/EC_Category.java
@@ -0,0 +1,70 @@
+package cz.crcs.ectester.data;
+
+import cz.crcs.ectester.reader.ec.EC_Params;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Category {
+
+ private String name;
+ private String directory;
+ private String desc;
+
+ private Map<String, EC_Params> objects;
+
+
+ public EC_Category(String name, String directory) {
+ this.name = name;
+ this.directory = directory;
+ }
+
+ public EC_Category(String name, String directory, String desc) {
+ this(name, directory);
+ this.desc = desc;
+ }
+
+ public EC_Category(String name, String directory, String desc, Map<String, EC_Params> objects) {
+ this(name, directory, desc);
+ this.objects = objects;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDirectory() {
+ return directory;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public Map<String, EC_Params> getObjects() {
+ return Collections.unmodifiableMap(objects);
+ }
+
+ public <T extends EC_Params> Map<String, T> getObjects(Class<T> cls) {
+ Map<String, T> objs = new HashMap<>();
+ for (Map.Entry<String, EC_Params> entry : objects.entrySet()) {
+ if (cls.isInstance(entry.getValue())) {
+ objs.put(entry.getKey(), cls.cast(entry.getValue()));
+ }
+ }
+ return Collections.unmodifiableMap(objs);
+ }
+
+ public <T extends EC_Params> T getObject(Class<T> cls, String id) {
+ EC_Params obj = objects.get(id);
+ if (cls.isInstance(obj)) {
+ return cls.cast(obj);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/cz/crcs/ectester/data/EC_Data.java b/src/cz/crcs/ectester/data/EC_Data.java
new file mode 100644
index 0000000..a867fcf
--- /dev/null
+++ b/src/cz/crcs/ectester/data/EC_Data.java
@@ -0,0 +1,230 @@
+package cz.crcs.ectester.data;
+
+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 javacard.security.KeyPair;
+import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Data {
+
+ private DocumentBuilderFactory dbf;
+
+ private Map<String, EC_Category> categories;
+
+ public EC_Data() {
+ dbf = DocumentBuilderFactory.newInstance();
+
+ try {
+ SchemaFactory scf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ Schema sch = scf.newSchema(this.getClass().getResource("/cz/crcs/ectester/data/schema.xsd"));
+ dbf.setSchema(sch);
+ dbf.setNamespaceAware(true);
+ dbf.setIgnoringComments(true);
+ dbf.setIgnoringElementContentWhitespace(true);
+
+ parse();
+ } catch (ParserConfigurationException | IOException | SAXException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void parse() throws SAXException, ParserConfigurationException, IOException {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+
+ Document categoriesDoc = db.parse(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/categories.xml"));
+ categoriesDoc.normalize();
+
+ NodeList catList = categoriesDoc.getElementsByTagName("category");
+
+ this.categories = new HashMap<>(catList.getLength());
+ for (int i = 0; i < catList.getLength(); ++i) {
+ Node catNode = catList.item(i);
+ if (catNode instanceof Element) {
+ Element catElem = (Element) catNode;
+ Node name = catElem.getElementsByTagName("name").item(0);
+ Node dir = catElem.getElementsByTagName("directory").item(0);
+ Node desc = catElem.getElementsByTagName("desc").item(0);
+
+ EC_Category category = parseCategory(name.getTextContent(), dir.getTextContent(), desc.getTextContent());
+ this.categories.put(name.getTextContent(), category);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ }
+
+ private EC_Category parseCategory(String name, String dir, String desc) throws ParserConfigurationException, IOException, SAXException {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+
+ Map<String, EC_Params> objMap = new HashMap<>();
+
+ InputStream curvesStream = this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/curves.xml");
+ if (curvesStream != null) {
+ Document curvesDoc = db.parse(curvesStream);
+ curvesDoc.normalize();
+
+ NodeList curveList = curvesDoc.getElementsByTagName("curve");
+
+ for (int i = 0; i < curveList.getLength(); ++i) {
+ Node curveNode = curveList.item(i);
+ if (curveNode instanceof Element) {
+ Element curveElem = (Element) curveNode;
+ Node id = curveElem.getElementsByTagName("id").item(0);
+ Node bits = curveElem.getElementsByTagName("bits").item(0);
+ Node field = curveElem.getElementsByTagName("field").item(0);
+ Node file = curveElem.getElementsByTagName("file").item(0);
+
+ NodeList descc = curveElem.getElementsByTagName("desc");
+ String descs = null;
+ if (descc.getLength() != 0) {
+ descs = descc.item(0).getTextContent();
+ }
+
+ byte alg;
+ if (field.getTextContent().equalsIgnoreCase("prime")) {
+ alg = KeyPair.ALG_EC_FP;
+ } else {
+ alg = KeyPair.ALG_EC_F2M;
+ }
+ short bitsize = Short.parseShort(bits.getTextContent());
+
+ EC_Curve curve = new EC_Curve(bitsize, alg, descs);
+ if (!curve.readCSV(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.getTextContent()))) {
+ throw new IOException("Invalid csv data.");
+ }
+
+ objMap.put(id.getTextContent(), curve);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ }
+
+ InputStream keysStream = this.getClass().getResourceAsStream("/cz/crcs/ectester/data" + dir + "/keys.xml");
+ if (keysStream != null) {
+ Document keysDoc = db.parse(keysStream);
+ keysDoc.normalize();
+
+ NodeList directs = keysDoc.getDocumentElement().getChildNodes();
+ for (int i = 0; i < directs.getLength(); ++i) {
+ Node direct = directs.item(i);
+ if (direct instanceof Element) {
+ Element elem = (Element) direct;
+ String tag = elem.getTagName();
+
+ NodeList childs = elem.getChildNodes();
+ String id = null;
+ for (int j = 0; j < childs.getLength(); ++j) {
+ Node child = childs.item(j);
+ if (child instanceof Element) {
+ Element childElem = (Element) child;
+ if (childElem.getTagName().equals("id")) {
+ id = childElem.getTextContent();
+ break;
+ }
+ }
+ }
+ if (id == null) {
+ throw new SAXException("key no id?");
+ }
+
+ EC_Params result = parseKeylike(dir, elem);
+
+ objMap.put(id, result);
+ } else {
+ throw new SAXException("?");
+ }
+ }
+ }
+
+ return new EC_Category(name, dir, desc, objMap);
+ }
+
+ private EC_Params parseKeylike(String dir, Element elem) throws SAXException {
+ Node file = elem.getElementsByTagName("file").item(0);
+ Node curve = elem.getElementsByTagName("curve").item(0);
+
+ NodeList desc = elem.getElementsByTagName("desc");
+ String descs = null;
+ if (desc.getLength() != 0) {
+ descs = desc.item(0).getTextContent();
+ }
+
+ EC_Params result;
+ if (elem.getTagName().equals("pubkey")) {
+ result = new EC_Key.Public(curve.getTextContent(), descs);
+ } else if (elem.getTagName().equals("privkey")) {
+ result = new EC_Key.Private(curve.getTextContent(), descs);
+ } else if (elem.getTagName().equals("keypair")) {
+ result = new EC_Keypair(curve.getTextContent(), descs);
+ } else {
+ throw new SAXException("?");
+ }
+ result.readCSV(this.getClass().getResourceAsStream("/cz/crcs/ectester/data/" + dir + "/" + file.getTextContent()));
+ return result;
+ }
+
+ public Map<String, EC_Category> getCategories() {
+ return Collections.unmodifiableMap(categories);
+ }
+
+ public EC_Category getCategory(String category) {
+ return categories.get(category);
+ }
+
+ public Map<String, EC_Params> getObjects(String category) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObjects();
+ }
+ return null;
+ }
+
+ public <T extends EC_Params> Map<String, T> getObjects(Class<T> objClass, String category) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObjects(objClass);
+ }
+ return null;
+ }
+
+ public <T extends EC_Params> T getObject(Class<T> objClass, String category, String id) {
+ EC_Category cat = categories.get(category);
+ if (cat != null) {
+ return cat.getObject(objClass, id);
+ }
+ return null;
+ }
+
+ public <T extends EC_Params> T getObject(Class<T> objClass, String query) {
+ String[] parts = query.split("/");
+ if (parts.length != 2) {
+ return null;
+ }
+ return getObject(objClass, parts[0], parts[1]);
+ }
+
+
+}
diff --git a/src/cz/crcs/ectester/data/anomalous/curves.xml b/src/cz/crcs/ectester/data/anomalous/curves.xml
index 8ac0238..c478657 100644
--- a/src/cz/crcs/ectester/data/anomalous/curves.xml
+++ b/src/cz/crcs/ectester/data/anomalous/curves.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
+ <!--
<curve>
<id>anomalousp128</id>
<bits>128</bits>
@@ -44,4 +44,5 @@
<field>prime</field>
<file>anomalousp521.csv</file>
</curve>
+ -->
</curves> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/brainpool/curves.xml b/src/cz/crcs/ectester/data/brainpool/curves.xml
index 0395ba1..2cb7fc5 100644
--- a/src/cz/crcs/ectester/data/brainpool/curves.xml
+++ b/src/cz/crcs/ectester/data/brainpool/curves.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
<curve>
<id>brainpoolP160r1</id>
<bits>160</bits>
diff --git a/src/cz/crcs/ectester/data/categories.xml b/src/cz/crcs/ectester/data/categories.xml
index 5537c98..5913d42 100644
--- a/src/cz/crcs/ectester/data/categories.xml
+++ b/src/cz/crcs/ectester/data/categories.xml
@@ -1,26 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<categories xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves schema.xsd">
+<categories xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="schema.xsd">
<category>
<name>anomalous</name>
<directory>anomalous</directory>
- <desc>These prime field curves have the same order as the field order, and are susceptible to attacks reducing ECDLP over a multiplicative group of the curve, to DLP over an additive group of the underlying field, which is easy.</desc>
+ <desc>These prime field curves have the same order as the field order, and are susceptible to attacks reducing ECDLP over a multiplicative group of the curve, to DLP over an additive group of the underlying field, which is easy (linear time).</desc>
</category>
<category>
<name>brainpool</name>
<directory>brainpool</directory>
- <desc>ECC Brainpool Standard Curves and Curve Generation v. 1.0 19.10.2005"</desc>
+ <desc>ECC Brainpool Standard Curves and Curve Generation v. 1.0 19.10.2005</desc>
</category>
<category>
<name>nist</name>
<directory>nist</directory>
- <desc>RECOMMENDED ELLIPTIC CURVES FOR FEDERAL GOVERNMENT USE July 1999"</desc>
+ <desc>RECOMMENDED ELLIPTIC CURVES FOR FEDERAL GOVERNMENT USE July 1999</desc>
</category>
<category>
<name>secg</name>
<directory>secg</directory>
- <desc>SEC 2: Recommended Elliptic Curve Domain Parameters version 2.0 January 27, 2010 </desc>
+ <desc>SEC 2: Recommended Elliptic Curve Domain Parameters version 2.0 January 27, 2010</desc>
</category>
<category>
<name>smallpub</name>
diff --git a/src/cz/crcs/ectester/data/nist/curves.xml b/src/cz/crcs/ectester/data/nist/curves.xml
index d9c1717..00b109c 100644
--- a/src/cz/crcs/ectester/data/nist/curves.xml
+++ b/src/cz/crcs/ectester/data/nist/curves.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
<curve>
<id>P-192</id>
<bits>192</bits>
diff --git a/src/cz/crcs/ectester/data/schema.xsd b/src/cz/crcs/ectester/data/schema.xsd
index d2bc85c..66566c9 100644
--- a/src/cz/crcs/ectester/data/schema.xsd
+++ b/src/cz/crcs/ectester/data/schema.xsd
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://crcs.cz/ectester/curves"
- xmlns="http://crcs.cz/ectester/curves"
elementFormDefault="qualified">
+ <!-- /<category>/curves.xml -->
+
<xs:element name="id" type="xs:string"/>
<xs:element name="desc" type="xs:string"/>
<xs:element name="bits" type="xs:positiveInteger"/>
@@ -32,14 +32,17 @@
<xs:element name="curves">
<xs:complexType>
<xs:sequence>
- <xs:element ref="curve" maxOccurs="unbounded"/>
+ <xs:element ref="curve" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
+ <!-- /<category>/keys.xml -->
+
<xs:element name="privkey">
<xs:complexType>
<xs:sequence>
+ <xs:element ref="id" />
<xs:element ref="file"/>
<xs:element name="curve" type="xs:string"/>
<xs:element ref="desc" minOccurs="0"/>
@@ -50,6 +53,7 @@
<xs:element name="pubkey">
<xs:complexType>
<xs:sequence>
+ <xs:element ref="id" />
<xs:element ref="file"/>
<xs:element name="curve" type="xs:string"/>
<xs:element ref="desc" minOccurs="0"/>
@@ -60,8 +64,10 @@
<xs:element name="keypair">
<xs:complexType>
<xs:sequence>
- <xs:element ref="pubkey"/>
- <xs:element ref="privkey"/>
+ <xs:element ref="id" />
+ <xs:element ref="file"/>
+ <xs:element name="curve" type="xs:string"/>
+ <xs:element ref="desc" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@@ -78,6 +84,8 @@
</xs:complexType>
</xs:element>
+ <!-- /categories.xml -->
+
<xs:element name="category">
<xs:complexType>
<xs:sequence>
diff --git a/src/cz/crcs/ectester/data/secg/curves.xml b/src/cz/crcs/ectester/data/secg/curves.xml
index d3295cb..1807ec3 100644
--- a/src/cz/crcs/ectester/data/secg/curves.xml
+++ b/src/cz/crcs/ectester/data/secg/curves.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
<curve>
<id>secp192k1</id>
<bits>192</bits>
@@ -42,7 +41,7 @@
<id>secp521r1</id>
<bits>521</bits>
<field>prime</field>
- <file>secp521r.csv</file>
+ <file>secp521r1.csv</file>
</curve>
<curve>
diff --git a/src/cz/crcs/ectester/data/secg/sect233k1.csv b/src/cz/crcs/ectester/data/secg/sect233k1.csv
index 4aeebd2..6a306ff 100644
--- a/src/cz/crcs/ectester/data/secg/sect233k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect233k1.csv
@@ -1 +1 @@
-004A,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126,01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3,8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF,4 \ No newline at end of file
+00E9,004A,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126,01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3,8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF,4 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/secg/sect233r1.csv b/src/cz/crcs/ectester/data/secg/sect233r1.csv
index 57ef35d..9a7b82a 100644
--- a/src/cz/crcs/ectester/data/secg/sect233r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect233r1.csv
@@ -1 +1 @@
-004A,000000000000000000000000000000000000000000000000000000000001,0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD,00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B,01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052,01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7,2 \ No newline at end of file
+00E9,004A,0000,0000,000000000000000000000000000000000000000000000000000000000001,0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD,00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B,01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052,01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7,2 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/secg/sect239k1.csv b/src/cz/crcs/ectester/data/secg/sect239k1.csv
index fdb64a9..496891d 100644
--- a/src/cz/crcs/ectester/data/secg/sect239k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect239k1.csv
@@ -1 +1 @@
-009E,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC,76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA,2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5,4 \ No newline at end of file
+00EF,009E,0000,0000,000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000001,29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC,76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA,2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5,4 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/secg/sect283k1.csv b/src/cz/crcs/ectester/data/secg/sect283k1.csv
index 07e7db2..908cdf7 100644
--- a/src/cz/crcs/ectester/data/secg/sect283k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect283k1.csv
@@ -1,10 +1 @@
-011B,
-000C,
-0007,
-0005,
-000000000000000000000000000000000000000000000000000000000000000000000000,
-000000000000000000000000000000000000000000000000000000000000000000000001,
-0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836,
-01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259,
-01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61,
-4
+011B,000C,0007,0005,000000000000000000000000000000000000000000000000000000000000000000000000,000000000000000000000000000000000000000000000000000000000000000000000001,0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836,01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259,01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61,4
diff --git a/src/cz/crcs/ectester/data/secg/sect409k1.csv b/src/cz/crcs/ectester/data/secg/sect409k1.csv
index 887d921..9190a26 100644
--- a/src/cz/crcs/ectester/data/secg/sect409k1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect409k1.csv
@@ -1 +1 @@
-0057,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746,01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B,7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF,4 \ No newline at end of file
+0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746,01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B,7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF,4 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/secg/sect409r1.csv b/src/cz/crcs/ectester/data/secg/sect409r1.csv
index a646e97..a277a07 100644
--- a/src/cz/crcs/ectester/data/secg/sect409r1.csv
+++ b/src/cz/crcs/ectester/data/secg/sect409r1.csv
@@ -1 +1 @@
-0057,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F,015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7,0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706,010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173,2 \ No newline at end of file
+0199,0057,0000,0000,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F,015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7,0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706,010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173,2 \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/smallpub/curves.xml b/src/cz/crcs/ectester/data/smallpub/curves.xml
index 1f1f146..50c1d0c 100644
--- a/src/cz/crcs/ectester/data/smallpub/curves.xml
+++ b/src/cz/crcs/ectester/data/smallpub/curves.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
<curve>
<id>ecsp128</id>
<bits>128</bits>
diff --git a/src/cz/crcs/ectester/data/smallpub/keys.xml b/src/cz/crcs/ectester/data/smallpub/keys.xml
index e3a7237..83e98b0 100644
--- a/src/cz/crcs/ectester/data/smallpub/keys.xml
+++ b/src/cz/crcs/ectester/data/smallpub/keys.xml
@@ -1,35 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
-<keys xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd"
+<keys xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd"
category="smallpub"
desc="Points on the Non-prime smallpub curves, very small point orders(3-5).">
<pubkey>
+ <id>ecsp128-pub</id>
<file>ecsp128_pub.csv</file>
<curve>ecsp128</curve>
+ <desc>order = 5</desc>
</pubkey>
<pubkey>
+ <id>ecsp160-pub</id>
<file>ecsp160_pub.csv</file>
<curve>ecsp160</curve>
+ <desc>order = 3</desc>
</pubkey>
<pubkey>
+ <id>ecsp192-pub</id>
<file>ecsp192_pub.csv</file>
<curve>ecsp192</curve>
+ <desc>order = 3</desc>
</pubkey>
<pubkey>
+ <id>ecsp224-pub</id>
<file>ecsp224_pub.csv</file>
<curve>ecsp224</curve>
+ <desc>order = 5</desc>
</pubkey>
<pubkey>
+ <id>ecsp256-pub</id>
<file>ecsp256_pub.csv</file>
<curve>ecsp256</curve>
+ <desc>order = 3</desc>
</pubkey>
<pubkey>
+ <id>ecsp384-pub</id>
<file>ecsp384_pub.csv</file>
<curve>ecsp384</curve>
+ <desc>order = 3</desc>
</pubkey>
<pubkey>
+ <id>ecsp521-pub</id>
<file>ecsp521_pub.csv</file>
<curve>ecsp521</curve>
+ <desc>order = 5</desc>
</pubkey>
</keys> \ No newline at end of file
diff --git a/src/cz/crcs/ectester/data/wrong/curves.xml b/src/cz/crcs/ectester/data/wrong/curves.xml
index 5f7ef9f..396dc4e 100644
--- a/src/cz/crcs/ectester/data/wrong/curves.xml
+++ b/src/cz/crcs/ectester/data/wrong/curves.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<curves xmlns="http://crcs.cz/ectester/curves"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://crcs.cz/ectester/curves ../schema.xsd">
+<curves xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../schema.xsd">
<curve>
<id>wrongp128</id>
<bits>128</bits>
diff --git a/src/cz/crcs/ectester/reader/ECTester.java b/src/cz/crcs/ectester/reader/ECTester.java
index f55e943..6ccbbbe 100644
--- a/src/cz/crcs/ectester/reader/ECTester.java
+++ b/src/cz/crcs/ectester/reader/ECTester.java
@@ -23,18 +23,22 @@ package cz.crcs.ectester.reader;
import cz.crcs.ectester.applet.ECTesterApplet;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.data.EC_Category;
+import cz.crcs.ectester.data.EC_Data;
+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 javacard.security.KeyPair;
import org.apache.commons.cli.*;
import javax.smartcardio.CardException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
+import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
/**
* Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
@@ -46,6 +50,7 @@ public class ECTester {
private CardMngr cardManager = null;
private DirtyLogger systemOutLogger = null;
+ private EC_Data dataDB = null;
//Options
private int optBits;
@@ -86,7 +91,6 @@ public class ECTester {
private void run(String[] args) {
try {
-
CommandLine cli = parseArgs(args);
//if help, print and quit
@@ -94,22 +98,35 @@ public class ECTester {
help();
return;
}
+
+ dataDB = new EC_Data();
+ //if list, print and quit
+ if (cli.hasOption("list-named")) {
+ Map<String, EC_Category> categories = dataDB.getCategories();
+ for (EC_Category cat : categories.values()) {
+ System.out.println("\t- " + cat.getName() + ": " + (cat.getDesc() == null ? "" : cat.getDesc()));
+ }
+ return;
+ }
+
//if not, read other options first, into attributes, then do action
if (!readOptions(cli)) {
return;
}
+
+ //init CardManager
cardManager = new CardMngr(optSimulate);
//connect or simulate connection
if (optSimulate) {
if (!cardManager.prepareLocalSimulatorApplet(AID, INSTALL_DATA, ECTesterApplet.class)) {
System.err.println("Failed to establish a simulator.");
- return;
+ System.exit(1);
}
} else {
if (!cardManager.connectToCardSelect()) {
System.err.println("Failed to connect to card.");
- return;
+ System.exit(1);
}
cardManager.send(SELECT_ECTESTERAPPLET);
}
@@ -171,6 +188,7 @@ public class ECTester {
* -t / --test
* -dh / --ecdh
* -dsa / --ecdsa [data_file]
+ * --list-named
*
* Options:
* -b / --bit-size [b] // -a / --all
@@ -179,19 +197,26 @@ public class ECTester {
* -f2m / --binary-field
*
* -u / --custom
- * -n / --named [cat/id|id|cat]
+ * -n / --named [cat/id]
* -c / --curve [curve_file] field,a,b,gx,gy,r,k
*
* -pub / --public [pubkey_file] wx,wy
+ * -npub / --named-public [cat/id]
+ *
* -priv / --private [privkey_file] s
+ * -npriv / --named-private [cat/id]
+ *
* -k / --key [key_file] wx,wy,s
+ * -nk / --named-key [cat/id]
*
* -o / --output [output_file]
+ * -f / --fresh
* -s / --simulate
*/
OptionGroup actions = new OptionGroup();
actions.setRequired(true);
actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
+ actions.addOption(Option.builder().longOpt("list-named").desc("Print the list of supported named curves and keys.").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.").build());
@@ -205,7 +230,7 @@ public class ECTester {
opts.addOptionGroup(size);
OptionGroup curve = new OptionGroup();
- curve.addOption(Option.builder("n").longOpt("named").desc("Use a named curve.").hasArg().argName("[cat/id|id|cat]").build());
+ curve.addOption(Option.builder("n").longOpt("named").desc("Use a named curve.").hasArg().argName("cat/id").build());
curve.addOption(Option.builder("c").longOpt("curve").desc("Use curve from file [curve_file] (field,a,b,gx,gy,r,k).").hasArg().argName("curve_file").build());
curve.addOption(Option.builder("u").longOpt("custom").desc("Use a custom curve(applet-side embedded, SECG curves).").build());
opts.addOptionGroup(curve);
@@ -214,12 +239,12 @@ public class ECTester {
opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use binary field curve.").build());
OptionGroup pub = new OptionGroup();
- pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: [cat/id|cat|id]").hasArg().argName("[cat/id|id|cat]").build());
+ pub.addOption(Option.builder("npub").longOpt("named-public").desc("Use public key from KeyDB: [cat/id]").hasArg().argName("cat/id").build());
pub.addOption(Option.builder("pub").longOpt("public").desc("Use public key from file [pubkey_file] (wx,wy).").hasArg().argName("pubkey_file").build());
opts.addOptionGroup(pub);
OptionGroup priv = new OptionGroup();
- priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: [cat/id|id|cat]").hasArg().argName("[cat/id|id|cat]").build());
+ priv.addOption(Option.builder("npriv").longOpt("named-private").desc("Use private key from KeyDB: [cat/id]").hasArg().argName("cat/id").build());
priv.addOption(Option.builder("priv").longOpt("private").desc("Use private key from file [privkey_file] (s).").hasArg().argName("privkey_file").build());
opts.addOptionGroup(priv);
@@ -282,6 +307,10 @@ public class ECTester {
return false;
}
+ if (optKey != null && optNamedKey != null || optPublic != null && optNamedPublic != null || optPrivate != null && optNamedPrivate != null) {
+ System.err.println("You cannot specify both a named key and a key file.");
+ return false;
+ }
if (cli.hasOption("export")) {
if (optPrimeField == optBinaryField) {
@@ -292,6 +321,10 @@ public class ECTester {
System.err.println("Keys should not be specified when exporting curve params.");
return false;
}
+ if (optNamedCurve != null || optCustomCurve || optCurveFile != null) {
+ System.err.println("Specifying a curve for curve export makes no sense.");
+ return false;
+ }
if (optOutput == null) {
System.err.println("You have to specify an output file for curve parameter export.");
return false;
@@ -381,19 +414,30 @@ public class ECTester {
*/
private void export() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- //skip cofactor in domain export, since it doesnt need to be initialized for the key to be initialized.
- //and generally isn't initialized on cards with default domain params(TODO, check, is it assumed to be ==1?)
- short domain = (short) ((optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M) ^ EC_Consts.PARAMETER_K);
- List<Response> sent = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> sent = new LinkedList<>();
+ sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send());
sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
+
+ // Cofactor generally isn't set on the default curve parameters on cards,
+ // since its not necessary for ECDH, only ECDHC which not many cards implement
+ // TODO: check if its assumend to be == 1?
+ short domain_all = optPrimeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
+ short domain = (short) (domain_all ^ EC_Consts.PARAMETER_K);
+ Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain_all).send();
+ if (!export.successful()) {
+ export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
+ }
sent.add(export);
systemOutLogger.println(Response.toString(sent));
- ECParams.writeFile(optOutput, ECParams.expand(export.getParams(), domain));
+ EC_Params exported = new EC_Params(domain, export.getParams());
+
+ FileOutputStream out = new FileOutputStream(optOutput);
+ exported.writeCSV(out);
+ out.close();
}
/**
@@ -405,7 +449,7 @@ public class ECTester {
private void generate() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send();
List<Command> curve = prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass);
FileWriter keysFile = new FileWriter(optOutput);
@@ -454,24 +498,58 @@ public class ECTester {
private void test() throws IOException, CardException {
List<Command> commands = new LinkedList<>();
if (optAll) {
- if (optPrimeField) {
- //iterate over prime curve sizes used: EC_Consts.FP_SIZES
- for (short keyLength : EC_Consts.FP_SIZES) {
- commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_FP));
+ if (optNamedCurve != null) {
+ Map<String, EC_Curve> curves = dataDB.getObjects(EC_Curve.class, optNamedCurve);
+ if (optPrimeField) {
+ for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
+ EC_Curve curve = entry.getValue();
+ if (curve.getField() == KeyPair.ALG_EC_FP) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_FP));
+ byte[] external = curve.flatten();
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ commands.addAll(testCurve(curve.getBits(), KeyPair.ALG_EC_FP));
+ }
+ }
}
- }
- if (optBinaryField) {
- //iterate over binary curve sizes used: EC_Consts.F2M_SIZES
- for (short keyLength : EC_Consts.F2M_SIZES) {
- commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M));
+ if (optBinaryField) {
+ for (Map.Entry<String, EC_Curve> entry : curves.entrySet()) {
+ EC_Curve curve = entry.getValue();
+ if (curve.getField() == KeyPair.ALG_EC_F2M) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_F2M));
+ byte[] external = curve.flatten();
+ commands.add(new Command.Set(cardManager, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
+ commands.addAll(testCurve(curve.getBits(), KeyPair.ALG_EC_F2M));
+ }
+ }
+ }
+ } else {
+ if (optPrimeField) {
+ //iterate over prime curve sizes used: EC_Consts.FP_SIZES
+ for (short keyLength : EC_Consts.FP_SIZES) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP));
+ commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_FP));
+ }
+ }
+ if (optBinaryField) {
+ //iterate over binary curve sizes used: EC_Consts.F2M_SIZES
+ for (short keyLength : EC_Consts.F2M_SIZES) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M));
+ commands.addAll(testCurve(keyLength, KeyPair.ALG_EC_F2M));
+ }
}
}
} else {
if (optPrimeField) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_FP));
commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_FP));
}
if (optBinaryField) {
+ commands.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M));
+ commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, KeyPair.ALG_EC_F2M));
commands.addAll(testCurve((short) optBits, KeyPair.ALG_EC_F2M));
}
}
@@ -487,7 +565,8 @@ public class ECTester {
*/
private void ecdh() throws IOException, CardException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> ecdh = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass));
+ List<Response> ecdh = new LinkedList<>();
+ ecdh.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass).send());
ecdh.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, (short) optBits, keyClass)));
if (optPublic != null || optPrivate != null || optKey != null) {
@@ -520,7 +599,8 @@ public class ECTester {
*/
private void ecdsa() throws CardException, IOException {
byte keyClass = optPrimeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> ecdsa = Command.sendAll(prepareKeyPair(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass));
+ List<Response> ecdsa = new LinkedList<>();
+ ecdsa.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass).send());
ecdsa.addAll(Command.sendAll(prepareCurve(ECTesterApplet.KEYPAIR_LOCAL, (short) optBits, keyClass)));
Response keys;
@@ -558,18 +638,6 @@ public class ECTester {
}
/**
- * @param keyPair which keyPair/s (local/remote) to allocate
- * @param keyLength key length to allocate
- * @param keyClass key class to allocate
- * @return a list of Commands to send in order to prepare the keyPair.
- */
- private List<Command> prepareKeyPair(byte keyPair, short keyLength, byte keyClass) {
- List<Command> commands = new ArrayList<>();
- commands.add(new Command.Allocate(cardManager, keyPair, keyLength, keyClass));
- return commands;
- }
-
- /**
* @param keyPair which keyPair/s (local/remote) to set curve domain parameters on
* @param keyLength key length to choose
* @param keyClass key class to choose
@@ -586,9 +654,28 @@ public class ECTester {
} else if (optNamedCurve != null) {
// Set a named curve.
// parse optNamedCurve -> cat / id | cat | id
+ EC_Curve curve = dataDB.getObject(EC_Curve.class, optNamedCurve);
+ if (curve == null) {
+ throw new IOException("Curve could no be found.");
+ }
+ if (curve.getBits() != keyLength) {
+ throw new IOException("Curve bits mismatch: " + curve.getBits() + " vs " + keyLength + " entered.");
+ }
+
+ byte[] external = curve.flatten();
+ if (external == null) {
+ throw new IOException("Couldn't read named curve data.");
+ }
+ commands.add(new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, domainParams, EC_Consts.PARAMETERS_NONE, EC_Consts.CORRUPTION_NONE, external));
} else if (optCurveFile != null) {
// Set curve loaded from a file
- byte[] external = ECParams.flatten(domainParams, ECParams.readFile(optCurveFile));
+ EC_Params params = new EC_Params(domainParams);
+
+ FileInputStream in = new FileInputStream(optCurveFile);
+ params.readCSV(in);
+ in.close();
+
+ byte[] external = params.flatten();
if (external == null) {
throw new IOException("Couldn't read the curve file correctly.");
}
@@ -609,25 +696,59 @@ public class ECTester {
private Command prepareKey(byte keyPair) throws IOException {
short params = EC_Consts.PARAMETERS_NONE;
byte[] data = null;
- if (optKey != null) {
+
+ if (optKey != null || optNamedKey != null) {
params |= EC_Consts.PARAMETERS_KEYPAIR;
- data = ECParams.flatten(EC_Consts.PARAMETERS_KEYPAIR, ECParams.readFile(optKey));
+ EC_Params keypair;
+ if (optKey != null) {
+ keypair = new EC_Params(EC_Consts.PARAMETERS_KEYPAIR);
+
+ FileInputStream in = new FileInputStream(optKey);
+ keypair.readCSV(in);
+ in.close();
+ } else {
+ keypair = dataDB.getObject(EC_Keypair.class, optNamedKey);
+ }
+
+ data = keypair.flatten();
if (data == null) {
throw new IOException("Couldn't read the key file correctly.");
}
}
- if (optPublic != null) {
+ if (optPublic != null || optNamedPublic != null) {
params |= EC_Consts.PARAMETER_W;
- byte[] pubkey = ECParams.flatten(EC_Consts.PARAMETER_W, ECParams.readFile(optPublic));
+ EC_Params pub;
+ if (optPublic != null) {
+ pub = new EC_Params(EC_Consts.PARAMETER_W);
+
+ FileInputStream in = new FileInputStream(optPublic);
+ pub.readCSV(in);
+ in.close();
+ } else {
+ pub = dataDB.getObject(EC_Key.Public.class, optNamedPublic);
+ }
+
+ byte[] pubkey = pub.flatten();
if (pubkey == null) {
throw new IOException("Couldn't read the key file correctly.");
}
data = pubkey;
}
- if (optPrivate != null) {
+ if (optPrivate != null || optNamedPrivate != null) {
params |= EC_Consts.PARAMETER_S;
- byte[] privkey = ECParams.flatten(EC_Consts.PARAMETER_S, ECParams.readFile(optPrivate));
+ EC_Params priv;
+ if (optPublic != null) {
+ priv = new EC_Params(EC_Consts.PARAMETER_S);
+
+ FileInputStream in = new FileInputStream(optPrivate);
+ priv.readCSV(in);
+ in.close();
+ } else {
+ priv = dataDB.getObject(EC_Key.Public.class, optNamedPrivate);
+ }
+
+ byte[] privkey = priv.flatten();
if (privkey == null) {
throw new IOException("Couldn't read the key file correctly.");
}
@@ -644,8 +765,6 @@ public class ECTester {
*/
private List<Command> testCurve(short keyLength, byte keyClass) throws IOException {
List<Command> commands = new LinkedList<>();
- commands.addAll(prepareKeyPair(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
- commands.addAll(prepareCurve(ECTesterApplet.KEYPAIR_BOTH, keyLength, keyClass));
commands.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH));
commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 0));
commands.add(new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, (byte) 1));
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Curve.java b/src/cz/crcs/ectester/reader/ec/EC_Curve.java
new file mode 100644
index 0000000..08a0b8a
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/ec/EC_Curve.java
@@ -0,0 +1,41 @@
+package cz.crcs.ectester.reader.ec;
+
+import cz.crcs.ectester.applet.EC_Consts;
+import javacard.security.KeyPair;
+
+/**
+ * @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;
+ }
+
+ public EC_Curve(short bits, byte field, String desc) {
+ this(bits, field);
+ this.desc = desc;
+ }
+
+ public short getBits() {
+ return bits;
+ }
+
+ public byte getField() {
+ return field;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Key.java b/src/cz/crcs/ectester/reader/ec/EC_Key.java
new file mode 100644
index 0000000..b78aaee
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/ec/EC_Key.java
@@ -0,0 +1,53 @@
+package cz.crcs.ectester.reader.ec;
+
+import cz.crcs.ectester.applet.EC_Consts;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Key extends EC_Params {
+
+ private String curve;
+ private String desc;
+
+ private EC_Key(short mask, String curve) {
+ super(mask);
+ this.curve = curve;
+ }
+
+ private EC_Key(short mask, String curve, String desc) {
+ this(mask, curve);
+ this.desc = desc;
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public static class Public extends EC_Key {
+
+ public Public(String curve) {
+ super(EC_Consts.PARAMETER_W, curve);
+ }
+
+ public Public(String curve, String desc) {
+ super(EC_Consts.PARAMETER_W, curve, desc);
+ }
+ }
+
+ public static class Private extends EC_Key {
+
+ public Private(String curve) {
+ super(EC_Consts.PARAMETER_S, curve);
+ }
+
+ public Private(String curve, String desc) {
+ super(EC_Consts.PARAMETER_S, curve, desc);
+ }
+
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/ec/EC_Keypair.java b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java
new file mode 100644
index 0000000..0ee3801
--- /dev/null
+++ b/src/cz/crcs/ectester/reader/ec/EC_Keypair.java
@@ -0,0 +1,30 @@
+package cz.crcs.ectester.reader.ec;
+
+import cz.crcs.ectester.applet.EC_Consts;
+
+/**
+ * @author Jan Jancar johny@neuromancer.sk
+ */
+public class EC_Keypair extends EC_Params {
+
+ private String curve;
+ private String desc;
+
+ public EC_Keypair(String curve) {
+ super(EC_Consts.PARAMETERS_KEYPAIR);
+ this.curve = curve;
+ }
+
+ public EC_Keypair(String curve, String desc) {
+ this(curve);
+ this.desc = desc;
+ }
+
+ public String getCurve() {
+ return curve;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+}
diff --git a/src/cz/crcs/ectester/reader/ECParams.java b/src/cz/crcs/ectester/reader/ec/EC_Params.java
index 76347b1..fa5515c 100644
--- a/src/cz/crcs/ectester/reader/ECParams.java
+++ b/src/cz/crcs/ectester/reader/ec/EC_Params.java
@@ -1,6 +1,7 @@
-package cz.crcs.ectester.reader;
+package cz.crcs.ectester.reader.ec;
import cz.crcs.ectester.applet.EC_Consts;
+import cz.crcs.ectester.reader.Util;
import java.io.*;
import java.util.ArrayList;
@@ -12,40 +13,75 @@ import java.util.regex.Pattern;
/**
* @author Jan Jancar johny@neuromancer.sk
*/
-public class ECParams {
+public class EC_Params {
private static final Pattern hex = Pattern.compile("(0x|0X)?[a-fA-F\\d]+");
- /**
- * Flattens params read from String[] data into a byte[] with their lengths prepended as short entries.
- *
- * @param params (EC_Consts.PARAMETER_* | ...)
- * @param data data read by readString, readFile, readResource
- * @return byte[] with params flattened, or null
- */
- public static byte[] flatten(short params, String[] data) {
- if (!validate(data)) {
- return null;
+ private short params;
+ private byte[][] data;
+
+ public EC_Params(short params) {
+ this.params = params;
+ this.data = new byte[numParams()][];
+ }
+
+ public EC_Params(short params, byte[][] data) {
+ this.params = params;
+ this.data = data;
+ }
+
+ public short getParams() {
+ return params;
+ }
+
+ public boolean hasParam(short param) {
+ return (params & param) != 0;
+ }
+
+ public int numParams() {
+ short paramMask = EC_Consts.PARAMETER_FP;
+ int num = 0;
+ while (paramMask <= EC_Consts.PARAMETER_S) {
+ if ((paramMask & params) != 0) {
+ if (paramMask == EC_Consts.PARAMETER_F2M) {
+ num += 3;
+ }
+ if (paramMask == EC_Consts.PARAMETER_W || paramMask == EC_Consts.PARAMETER_G){
+ num += 1;
+ }
+ ++num;
+ }
+ paramMask = (short) (paramMask << 1);
}
+ return num;
+ }
+
+ public byte[][] getData() {
+ return data;
+ }
+ public boolean hasData() {
+ return data != null;
+ }
+
+ public byte[] flatten() {
ByteArrayOutputStream out = new ByteArrayOutputStream();
short paramMask = EC_Consts.PARAMETER_FP;
int i = 0;
while (paramMask <= EC_Consts.PARAMETER_S) {
short masked = (short) (params & paramMask);
if (masked != 0) {
- byte[] param = parse(data[i]);
+ byte[] param = data[i];
if (masked == EC_Consts.PARAMETER_F2M) {
//add m, e_1, e_2, e_3
- param = Util.concatenate(param, parse(data[i + 1]), parse(data[i + 2]), parse(data[i + 3]));
+ param = Util.concatenate(param, data[i + 1], data[i + 2], data[i + 3]);
i += 3;
if (param.length != 8)
throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)");
}
if (masked == EC_Consts.PARAMETER_G || masked == EC_Consts.PARAMETER_W) {
//read another param (the y coord) and put into X962 format.
- byte[] y = parse(data[i + 1]);
+ byte[] y = data[++i];
param = Util.concatenate(new byte[]{4}, param, y); //<- ugly but works!
- i++;
}
if (param.length == 0)
throw new RuntimeException("Empty parameter read?");
@@ -64,12 +100,7 @@ public class ECParams {
return (out.size() == 0) ? null : out.toByteArray();
}
- /**
- * @param data
- * @param params
- * @return
- */
- public static String[] expand(byte[][] data, short params) {
+ public String[] expand() {
List<String> out = new ArrayList<>();
short paramMask = EC_Consts.PARAMETER_FP;
@@ -80,12 +111,11 @@ public class ECParams {
byte[] param = data[index];
if (masked == EC_Consts.PARAMETER_F2M) {
- //split into m, e1, [e2, e3]
- if (!((param.length == 4) || (param.length == 8))) {
- throw new RuntimeException("PARAMETER_F2M length is not 4 or 8.(should be)");
+ //split into m, e1, e2, e3
+ if (param.length != 8) {
+ throw new RuntimeException("PARAMETER_F2M length is not 8.(should be)");
}
- int max = param.length == 4 ? 2 : 4;
- for (int i = 0; i < max; ++i) {
+ for (int i = 0; i < 4; ++i) {
out.add(String.format("%04x", Util.getShort(param, i * 2)));
}
@@ -106,49 +136,41 @@ public class ECParams {
return out.toArray(new String[out.size()]);
}
- /**
- * @param filePath
- * @param data
- * @throws IOException
- */
- public static void writeFile(String filePath, String[] data) throws IOException {
- FileOutputStream out = new FileOutputStream(filePath);
- write(out, data);
- out.close();
+ private static byte[] pad(byte[] data) {
+ if (data.length == 1) {
+ return new byte[]{(byte) 0, data[0]};
+ } else if (data.length == 0 || data.length > 2) {
+ return data;
+ }
+ return null;
}
- /**
- * Reads hex params from a CSV String data.
- *
- * @param data String containing CSV data(hex)
- * @return String array containing the CSV entries
- */
- public static String[] readString(String data) {
- return read(new ByteArrayInputStream(data.getBytes()));
+ private static byte[] parse(String param) {
+ byte[] data;
+ if (param.startsWith("0x") || param.startsWith("0X")) {
+ data = Util.hexToBytes(param.substring(2));
+ } else {
+ data = Util.hexToBytes(param);
+ }
+ if (data == null)
+ return new byte[0];
+ if (data.length < 2)
+ return pad(data);
+ return data;
}
- /**
- * Reads hex params from a CSV Resource (inside jar).
- *
- * @param resourcePath path to the resourse
- * @return String array containing the CSV entries
- */
- public static String[] readResource(String resourcePath) {
- return read(ECParams.class.getResourceAsStream(resourcePath));
- }
+ private boolean readHex(String[] hex) {
+ if (hex.length != numParams()) {
+ return false;
+ }
- /**
- * Reads hex params from a CSV file.
- *
- * @param filePath path to the file
- * @return String array containing the CSV entries
- * @throws FileNotFoundException if the file cannot be opened
- */
- public static String[] readFile(String filePath) throws FileNotFoundException {
- return read(new FileInputStream(filePath));
+ for (int i = 0; i < numParams(); ++i) {
+ this.data[i] = parse(hex[i]);
+ }
+ return true;
}
- private static String[] read(InputStream in) {
+ public boolean readCSV(InputStream in) {
Scanner s = new Scanner(in);
s.useDelimiter(",|;");
@@ -157,11 +179,8 @@ public class ECParams {
String field = s.next();
data.add(field.replaceAll("\\s+", ""));
}
- return data.toArray(new String[data.size()]);
- }
- private static boolean validate(String[] data) {
- if (data == null || data.length == 0) {
+ if (data.isEmpty()) {
return false;
}
for (String param : data) {
@@ -169,40 +188,23 @@ public class ECParams {
return false;
}
}
- return true;
- }
-
- private static byte[] parse(String param) {
- byte[] data;
- if (param.startsWith("0x") || param.startsWith("0X")) {
- data = Util.hexToBytes(param.substring(2));
- } else {
- data = Util.hexToBytes(param);
- }
- if (data == null)
- return new byte[0];
- if (data.length < 2)
- return pad(data);
- return data;
- }
-
- private static byte[] pad(byte[] data) {
- if (data.length == 1) {
- return new byte[]{(byte) 0, data[0]};
- } else if (data.length == 0 || data.length > 2) {
- return data;
- }
- return null;
+ return readHex(data.toArray(new String[data.size()]));
}
- private static void write(OutputStream out, String[] data) throws IOException {
+ public void writeCSV(OutputStream out) throws IOException {
+ String[] hex = expand();
Writer w = new OutputStreamWriter(out);
- for (int i = 0; i < data.length; ++i) {
- w.write(data[i]);
- if (i < data.length - 1) {
+ for (int i = 0; i < hex.length; ++i) {
+ w.write(hex[i]);
+ if (i < hex.length - 1) {
w.write(",");
}
}
w.flush();
}
+
+ public boolean readBytes(byte[] data) {
+ //TODO
+ return false;
+ }
}