diff options
| author | J08nY | 2017-03-06 22:56:34 +0100 |
|---|---|---|
| committer | J08nY | 2017-03-06 22:56:34 +0100 |
| commit | 117b35545288df5b01173d36bde451b414d31d66 (patch) | |
| tree | add0ecbc48e95a398662bef9e41670df1c61243e /src | |
| parent | 66bd8469e56cbe7c6bed823b376229a02ecdd37d (diff) | |
| download | ECTester-117b35545288df5b01173d36bde451b414d31d66.tar.gz ECTester-117b35545288df5b01173d36bde451b414d31d66.tar.zst ECTester-117b35545288df5b01173d36bde451b414d31d66.zip | |
Diffstat (limited to 'src')
23 files changed, 748 insertions, 196 deletions
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; + } } |
