aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/reader
diff options
context:
space:
mode:
authorJ08nY2024-03-22 23:58:55 +0100
committerJ08nY2024-03-25 14:52:43 +0100
commit73af477a8774e1ede5dd8de6491eb353dc0b12bd (patch)
tree2d4e3b19bc5fb55308b886032312be76341736d4 /src/cz/crcs/ectester/reader
parent64b95fa059295e1dc23371c849f2302c1c18f5b4 (diff)
downloadECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.gz
ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.tar.zst
ECTester-73af477a8774e1ede5dd8de6491eb353dc0b12bd.zip
Basic Gradle setup.
Diffstat (limited to 'src/cz/crcs/ectester/reader')
-rw-r--r--src/cz/crcs/ectester/reader/CardMngr.java478
-rw-r--r--src/cz/crcs/ectester/reader/ECTesterReader.java1104
-rw-r--r--src/cz/crcs/ectester/reader/ISO7816_status_words.txt71
-rw-r--r--src/cz/crcs/ectester/reader/command/Command.java920
-rw-r--r--src/cz/crcs/ectester/reader/output/FileTestWriter.java53
-rw-r--r--src/cz/crcs/ectester/reader/output/ResponseWriter.java43
-rw-r--r--src/cz/crcs/ectester/reader/output/TextTestWriter.java71
-rw-r--r--src/cz/crcs/ectester/reader/output/XMLTestWriter.java159
-rw-r--r--src/cz/crcs/ectester/reader/output/YAMLTestWriter.java119
-rw-r--r--src/cz/crcs/ectester/reader/response/Response.java526
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCofactorSuite.java65
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompositeSuite.java122
-rw-r--r--src/cz/crcs/ectester/reader/test/CardCompressionSuite.java155
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDefaultSuite.java141
-rw-r--r--src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java69
-rw-r--r--src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java336
-rw-r--r--src/cz/crcs/ectester/reader/test/CardInvalidSuite.java72
-rw-r--r--src/cz/crcs/ectester/reader/test/CardMiscSuite.java77
-rw-r--r--src/cz/crcs/ectester/reader/test/CardSignatureSuite.java68
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestSuite.java94
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java235
-rw-r--r--src/cz/crcs/ectester/reader/test/CardTwistSuite.java67
-rw-r--r--src/cz/crcs/ectester/reader/test/CardWrongSuite.java232
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTest.java85
-rw-r--r--src/cz/crcs/ectester/reader/test/CommandTestable.java44
-rw-r--r--src/cz/crcs/ectester/reader/test/PerformanceTest.java141
26 files changed, 0 insertions, 5547 deletions
diff --git a/src/cz/crcs/ectester/reader/CardMngr.java b/src/cz/crcs/ectester/reader/CardMngr.java
deleted file mode 100644
index 0a01d9e..0000000
--- a/src/cz/crcs/ectester/reader/CardMngr.java
+++ /dev/null
@@ -1,478 +0,0 @@
-package cz.crcs.ectester.reader;
-
-import com.licel.jcardsim.io.JavaxSmartCardInterface;
-import cz.crcs.ectester.common.util.ByteUtil;
-import javacard.framework.AID;
-import javacard.framework.Applet;
-import javacard.framework.ISO7816;
-
-import javax.smartcardio.*;
-import java.util.*;
-
-/**
- * @author Petr Svenda petr@svenda.com
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardMngr {
- private CardTerminal terminal = null;
- private CardChannel channel = null;
- private Card card = null;
-
- // Simulator related attributes
- private JavaxSmartCardInterface simulator = null;
-
- private boolean simulate = false;
- private boolean verbose = true;
- private boolean chunking = false;
-
- private final byte[] selectCM = {
- (byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x07, (byte) 0xa0, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x18, (byte) 0x43, (byte) 0x4d};
-
- public static final byte OFFSET_CLA = 0x00;
- public static final byte OFFSET_INS = 0x01;
- public static final byte OFFSET_P1 = 0x02;
- public static final byte OFFSET_P2 = 0x03;
- public static final byte OFFSET_LC = 0x04;
- public static final byte OFFSET_DATA = 0x05;
- public static final byte HEADER_LENGTH = 0x05;
-
- public static final short DATA_RECORD_LENGTH = (short) 0x80; // 128B per record
- public static final short NUMBER_OF_RECORDS = (short) 0x0a; // 10 records
-
- public CardMngr() {
- }
-
- public CardMngr(boolean verbose) {
- this.verbose = verbose;
- }
-
- public CardMngr(boolean verbose, boolean simulate) {
- this(verbose);
- this.simulate = simulate;
- }
-
- private void connectWithHighest() throws CardException {
- try {
- card = terminal.connect("T=1");
- } catch (CardException ex) {
- if (verbose)
- System.out.println("T=1 failed, trying protocol '*'");
- card = terminal.connect("*");
- if (card.getProtocol().equals("T=0")) {
- chunking = true;
- }
- }
- }
-
- public boolean connectToCard() throws CardException {
- if (simulate)
- return true;
-
- // TRY ALL READERS, FIND FIRST SELECTABLE
- List<CardTerminal> terminalList = getReaderList();
-
- if (terminalList == null || terminalList.isEmpty()) {
- System.err.println("No terminals found");
- return false;
- }
-
- //List numbers of Card readers
- boolean cardFound = false;
- for (int i = 0; i < terminalList.size(); i++) {
-
- if (verbose)
- System.out.println(i + " : " + terminalList.get(i));
-
- terminal = terminalList.get(i);
- if (terminal.isCardPresent()) {
- connectWithHighest();
-
- if (verbose)
- System.out.println("card: " + card);
- channel = card.getBasicChannel();
-
- //reset the card
- if (verbose)
- System.out.println(ByteUtil.bytesToHex(card.getATR().getBytes()));
-
- cardFound = true;
- }
- }
-
- return cardFound;
- }
-
- public boolean connectToCardSelect() throws CardException {
- if (simulate)
- return true;
-
- // Test available card - if more present, let user to select one
- List<CardTerminal> terminalList = CardMngr.getReaderList();
- if (terminalList == null || terminalList.isEmpty()) {
- System.err.println("ERROR: No suitable reader with card detected. Please check your reader connection");
- return false;
- } else {
- if (terminalList.size() == 1) {
- terminal = terminalList.get(0); // return first and only reader
- } else {
- int terminalIndex = 1;
- // Let user select target terminal
- for (CardTerminal terminal : terminalList) {
- Card card;
- try {
- card = terminal.connect("*");
- ATR atr = card.getATR();
- System.out.println(terminalIndex + " : " + terminal.getName() + " - " + ByteUtil.bytesToHex(atr.getBytes()));
- terminalIndex++;
- } catch (CardException ex) {
- ex.printStackTrace(System.out);
- }
- }
- System.out.print("Select index of target reader you like to use 1.." + (terminalIndex - 1) + ": ");
- Scanner sc = new Scanner(System.in);
- int answ = sc.nextInt();
- System.out.println(String.format("%d", answ));
- answ--; // is starting with 0
- // BUGBUG; verify allowed index range
- terminal = terminalList.get(answ);
- }
- }
-
- if (terminal != null) {
- connectWithHighest();
- if (verbose)
- System.out.println("card: " + card);
- channel = card.getBasicChannel();
- }
-
- return true;
- }
-
- public boolean reconnectToCard(byte[] selectAPDU) throws CardException {
- if (simulate)
- return true;
-
- if (connected()) {
- disconnectFromCard();
- }
-
- boolean result = connectToCard();
- if (result) {
- // Select our application on card
- send(selectAPDU);
- }
- return result;
- }
-
- public boolean connected() {
- return simulate || card != null;
- }
-
- public void disconnectFromCard() throws CardException {
- if (simulate)
- return;
-
- if (card != null) {
- card.disconnect(false);
- card = null;
- }
- }
-
- public void setChunking(boolean state) {
- chunking = state;
- }
-
- public String getProtocol() {
- if (simulate) {
- return simulator.getProtocol();
- } else {
- if (card != null) {
- return card.getProtocol();
- } else {
- return null;
- }
- }
- }
-
- // Functions for CPLC taken and modified from https://github.com/martinpaljak/GlobalPlatformPro
- private static final byte CLA_GP = (byte) 0x80;
- private static final byte ISO7816_INS_GET_DATA = (byte) 0xCA;
- private static final byte[] FETCH_GP_CPLC_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00};
- private static final byte[] FETCH_ISO_CPLC_APDU = {ISO7816.CLA_ISO7816, ISO7816_INS_GET_DATA, (byte) 0x9F, (byte) 0x7F, (byte) 0x00};
- private static final byte[] FETCH_GP_CARDDATA_APDU = {CLA_GP, ISO7816_INS_GET_DATA, (byte) 0x00, (byte) 0x66, (byte) 0x00};
-
- public byte[] fetchCPLC() throws CardException {
- // Try CPLC via GP
- ResponseAPDU resp = send(FETCH_GP_CPLC_APDU);
- // If GP CLA fails, try with ISO
- if (resp.getSW() == (ISO7816.SW_CLA_NOT_SUPPORTED & 0xffff)) {
- resp = send(FETCH_ISO_CPLC_APDU);
- }
- if (resp.getSW() == (ISO7816.SW_NO_ERROR & 0xffff)) {
- return resp.getData();
- }
- return null;
- }
-
- public static final class CPLC {
- public enum Field {
- ICFabricator,
- ICType,
- OperatingSystemID,
- OperatingSystemReleaseDate,
- OperatingSystemReleaseLevel,
- ICFabricationDate,
- ICSerialNumber,
- ICBatchIdentifier,
- ICModuleFabricator,
- ICModulePackagingDate,
- ICCManufacturer,
- ICEmbeddingDate,
- ICPrePersonalizer,
- ICPrePersonalizationEquipmentDate,
- ICPrePersonalizationEquipmentID,
- ICPersonalizer,
- ICPersonalizationDate,
- ICPersonalizationEquipmentID
- }
-
- private Map<Field, byte[]> values = new TreeMap<>();
-
- public CPLC(byte[] data) {
- if (data == null) {
- return;
- }
- if (data.length < 3 || data[2] != 0x2A) {
- throw new IllegalArgumentException("CPLC must be 0x2A bytes long");
- }
- //offset = TLVUtils.skipTag(data, offset, (short)0x9F7F);
- short offset = 3;
- values.put(Field.ICFabricator, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICType, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.OperatingSystemID, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.OperatingSystemReleaseDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.OperatingSystemReleaseLevel, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICFabricationDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICSerialNumber, Arrays.copyOfRange(data, offset, offset + 4));
- offset += 4;
- values.put(Field.ICBatchIdentifier, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICModuleFabricator, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICModulePackagingDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICCManufacturer, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICEmbeddingDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICPrePersonalizer, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICPrePersonalizationEquipmentDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICPrePersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4));
- offset += 4;
- values.put(Field.ICPersonalizer, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICPersonalizationDate, Arrays.copyOfRange(data, offset, offset + 2));
- offset += 2;
- values.put(Field.ICPersonalizationEquipmentID, Arrays.copyOfRange(data, offset, offset + 4));
- offset += 4;
- }
-
- public Map<Field, byte[]> values() {
- return values;
- }
- }
-
- public ATR getATR() {
- if (simulate) {
- return new ATR(simulator.getATR());
- } else {
- if (card != null) {
- return card.getATR();
- } else {
- return null;
- }
- }
- }
-
- public CPLC getCPLC() throws CardException {
- byte[] data = fetchCPLC();
- return new CPLC(data);
- }
-
- public static String mapCPLCField(CPLC.Field field, byte[] value) {
- switch (field) {
- case ICFabricator:
- String id = ByteUtil.bytesToHex(value, false);
- String fabricatorName = "unknown";
- if (id.equals("3060")) {
- fabricatorName = "Renesas";
- }
- if (id.equals("4090")) {
- fabricatorName = "Infineon";
- }
- if (id.equals("4180")) {
- fabricatorName = "Atmel";
- }
- if (id.equals("4250")) {
- fabricatorName = "Samsung";
- }
- if (id.equals("4790")) {
- fabricatorName = "NXP";
- }
- return id + " (" + fabricatorName + ")";
- default:
- return ByteUtil.bytesToHex(value, false);
- }
- }
-
-
- public static List<CardTerminal> getReaderList() {
- try {
- TerminalFactory factory = TerminalFactory.getDefault();
- return factory.terminals().list();
- } catch (CardException ex) {
- System.err.println("Exception : " + ex);
- return null;
- }
- }
-
- private CommandAPDU chunk(CommandAPDU apdu) throws CardException {
- if (verbose) {
- System.out.print("Chunking:");
- }
- byte[] data = apdu.getBytes();
- int numChunks = (data.length + 254) / 255;
- for (int i = 0; i < numChunks; ++i) {
- int chunkStart = i * 255;
- int chunkLength = 255;
- if (chunkStart + chunkLength > data.length) {
- chunkLength = data.length - chunkStart;
- }
- if (verbose) {
- System.out.print(" " + chunkLength);
- }
- byte[] chunk = new byte[chunkLength];
- System.arraycopy(data, chunkStart, chunk, 0, chunkLength);
- CommandAPDU cmd = new CommandAPDU(apdu.getCLA(), 0x7a, 0, 0, chunk);
- ResponseAPDU resp;
- if (simulate) {
- resp = simulator.transmitCommand(cmd);
- } else {
- resp = channel.transmit(cmd);
- }
- if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) {
- throw new CardException("Chunking failed!");
- }
- }
- if (verbose)
- System.out.println();
- return new CommandAPDU(apdu.getCLA(), 0x7b, 0, 0, 0xff);
- }
-
- public ResponseAPDU sendAPDU(CommandAPDU apdu) throws CardException {
- if (verbose) {
- System.out.println(">>>>");
- System.out.println(apdu);
-
- System.out.println(ByteUtil.bytesToHex(apdu.getBytes()));
- }
-
- long elapsed;
- if (chunking && apdu.getNc() >= 0xff) {
- apdu = chunk(apdu);
- }
-
- elapsed = -System.nanoTime();
-
- ResponseAPDU responseAPDU = channel.transmit(apdu);
-
- elapsed += System.nanoTime();
-
- if (verbose) {
- System.out.println(responseAPDU);
- System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes()));
- }
-
- if (responseAPDU.getSW1() == (byte) 0x61) {
- CommandAPDU apduToSend = new CommandAPDU((byte) 0x00,
- (byte) 0xC0, (byte) 0x00, (byte) 0x00,
- responseAPDU.getSW2());
-
- responseAPDU = channel.transmit(apduToSend);
- if (verbose)
- System.out.println(ByteUtil.bytesToHex(responseAPDU.getBytes()));
- }
-
- if (verbose) {
- System.out.println("<<<<");
- System.out.println("Elapsed time (ms): " + elapsed / 1000000);
- System.out.println("---------------------------------------------------------");
- }
- return responseAPDU;
- }
-
- public ResponseAPDU sendAPDU(byte[] apdu) throws CardException {
- CommandAPDU commandAPDU = new CommandAPDU(apdu);
- return sendAPDU(commandAPDU);
- }
-
- public boolean prepareLocalSimulatorApplet(byte[] appletAIDArray, byte[] installData, Class<? extends Applet> appletClass) {
- simulator = new JavaxSmartCardInterface();
- AID appletAID = new AID(appletAIDArray, (short) 0, (byte) appletAIDArray.length);
-
- simulator.installApplet(appletAID, appletClass, installData, (short) 0, (byte) installData.length);
- return simulator.selectApplet(appletAID);
- }
-
- public ResponseAPDU sendAPDUSimulator(CommandAPDU apdu) throws CardException {
- if (verbose) {
- System.out.println(">>>>");
- System.out.println(apdu);
- System.out.println(ByteUtil.bytesToHex(apdu.getBytes()));
- }
-
- if (chunking && apdu.getNc() >= 0xff) {
- apdu = chunk(apdu);
- }
-
- ResponseAPDU response = simulator.transmitCommand(apdu);
- byte[] responseBytes = response.getBytes();
-
- if (verbose) {
- System.out.println(response);
- System.out.println(ByteUtil.bytesToHex(responseBytes));
- System.out.println("<<<<");
- }
-
- return response;
- }
-
- public ResponseAPDU sendAPDUSimulator(byte[] apdu) throws CardException {
- CommandAPDU commandAPDU = new CommandAPDU(apdu);
- return sendAPDUSimulator(commandAPDU);
- }
-
- public ResponseAPDU send(CommandAPDU apdu) throws CardException {
- ResponseAPDU response;
- if (simulate) {
- response = sendAPDUSimulator(apdu);
- } else {
- response = sendAPDU(apdu);
- }
- return response;
- }
-
- public ResponseAPDU send(byte[] apdu) throws CardException {
- CommandAPDU commandAPDU = new CommandAPDU(apdu);
- return send(commandAPDU);
- }
-}
diff --git a/src/cz/crcs/ectester/reader/ECTesterReader.java b/src/cz/crcs/ectester/reader/ECTesterReader.java
deleted file mode 100644
index fdfb4cb..0000000
--- a/src/cz/crcs/ectester/reader/ECTesterReader.java
+++ /dev/null
@@ -1,1104 +0,0 @@
-/*
- * ECTester, tool for testing Elliptic curve cryptography implementations.
- * Copyright (c) 2016-2019 Petr Svenda <petr@svenda.com>
- * Copyright (c) 2016-2019 Jan Jancar <johny@neuromancer.sk>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package cz.crcs.ectester.reader;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.cli.CLITools;
-import cz.crcs.ectester.common.cli.Colors;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.output.OutputLogger;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.util.Util;
-import cz.crcs.ectester.common.util.*;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.output.FileTestWriter;
-import cz.crcs.ectester.reader.output.ResponseWriter;
-import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.*;
-import javacard.framework.ISO7816;
-import javacard.security.KeyPair;
-import org.apache.commons.cli.*;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import javax.smartcardio.CardException;
-import javax.smartcardio.ResponseAPDU;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.*;
-import java.math.BigInteger;
-import java.net.URL;
-import java.nio.file.Files;
-import java.security.Security;
-import java.security.spec.ECParameterSpec;
-import java.util.*;
-import java.util.jar.Manifest;
-
-import static cz.crcs.ectester.applet.EC_Consts.KeyAgreement_ALG_EC_SVDP_DH;
-import static cz.crcs.ectester.applet.EC_Consts.Signature_ALG_ECDSA_SHA;
-
-/**
- * Reader part of ECTester, a tool for testing Elliptic curve support on javacards.
- *
- * @author Petr Svenda petr@svenda.com
- * @author Jan Jancar johny@neuromancer.sk
- * @version v0.3.3
- */
-public class ECTesterReader {
- private CardMngr cardManager;
- private OutputLogger logger;
- private ResponseWriter respWriter;
- private Config cfg;
-
- private Options opts = new Options();
- public static final String VERSION = "v0.3.3";
- public static String GIT_COMMIT = "";
- private static String DESCRIPTION;
- private static String LICENSE = "MIT Licensed\nCopyright © 2016-2019 Petr Svenda <petr@svenda.com>\nCopyright © 2016-2019 Jan Jancar <johny@neuromancer.sk>";
- private static String CLI_HEADER;
- private static String CLI_FOOTER = "\n" + LICENSE;
-
- private static final byte[] SELECT_PREFIX = {(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x0c};
- private static final byte[] AID_PREFIX = {(byte) 0x45, (byte) 0x43, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x72};
- private static final byte[] AID_CURRENT_VERSION = {(byte) 0x30, (byte) 0x33, (byte) 0x33}; // VERSION v0.3.3
- private static final byte[] AID_SUFFIX_221 = {(byte) 0x62};
- private static final byte[] AID_SUFFIX_222 = {(byte) 0x78};
- private static final byte[] INSTALL_DATA = new byte[10];
- private static final int TRY_VERSIONS = 10;
-
- static {
- ClassLoader cl = ECTesterReader.class.getClassLoader();
- try {
- URL url = cl.getResource("META-INF/MANIFEST.MF");
- Manifest manifest = new Manifest(url.openStream());
- String commit = manifest.getMainAttributes().getValue("Git-Commit");
- GIT_COMMIT = (commit == null) ? "" : "(git " + commit + ")";
- } catch (Exception ignored) {
- }
-
- DESCRIPTION = "ECTesterReader " + VERSION + GIT_COMMIT + ", a javacard Elliptic Curve Cryptography support tester/utility.";
- CLI_HEADER = "\n" + DESCRIPTION + "\n\n";
- }
-
- private void run(String[] args) {
- try {
- CommandLine cli = parseArgs(args);
-
- cfg = new Config();
- boolean optsOk = cfg.readOptions(cli);
-
- //if help, print and quit
- if (cli.hasOption("help")) {
- CLITools.help("ECTesterReader.jar", CLI_HEADER, opts, CLI_FOOTER, true);
- return;
- } else if (cli.hasOption("version")) {
- CLITools.version(DESCRIPTION, LICENSE);
- return;
- }
-
- //if opts failed, quit
- if (!optsOk) {
- return;
- }
-
- //if list, print and quit
- if (cli.hasOption("list-named")) {
- CLITools.listNamed(EC_Store.getInstance(), cli.getOptionValue("list-named"));
- return;
- }
-
- if (cli.hasOption("list-suites")) {
- listSuites();
- return;
- }
-
- //init CardManager
- cardManager = new CardMngr(cfg.verbose, cfg.simulate);
-
- //connect or simulate connection
- if (cfg.simulate) {
- if (!cardManager.prepareLocalSimulatorApplet(ByteUtil.concatenate(AID_PREFIX, AID_CURRENT_VERSION, AID_SUFFIX_221), INSTALL_DATA, ECTesterApplet.class)) {
- System.err.println(Colors.error("Failed to establish a simulator."));
- System.exit(1);
- } else {
- cardManager.setChunking(true);
- }
- } else {
- if (!cardManager.connectToCardSelect()) {
- System.err.println(Colors.error("Failed to connect to card."));
- System.exit(1);
- }
- //Try the highest known version first
- byte[] versionByte = AID_CURRENT_VERSION.clone();
- boolean selected = false;
- for (int i = 0; i < TRY_VERSIONS; ++i) {
- byte[] select222 = ByteUtil.concatenate(SELECT_PREFIX, AID_PREFIX, versionByte, AID_SUFFIX_222);
- ResponseAPDU selectResp = cardManager.send(select222);
- if ((short) selectResp.getSW() != ISO7816.SW_NO_ERROR) {
- byte[] select221 = ByteUtil.concatenate(SELECT_PREFIX, AID_PREFIX, versionByte, AID_SUFFIX_221);
- selectResp = cardManager.send(select221);
- if ((short) selectResp.getSW() == ISO7816.SW_NO_ERROR) {
- cardManager.setChunking(true);
- selected = true;
- break;
- }
- } else {
- selected = true;
- break;
- }
- // Count down by versions
- if (versionByte[2] == 0x30) {
- if (versionByte[1] == 0x30) {
- if (versionByte[0] == 0x30) {
- break;
- } else {
- versionByte[0]--;
- versionByte[1] = 0x39;
- versionByte[2] = 0x39;
- }
- } else {
- versionByte[1]--;
- versionByte[2] = 0x39;
- }
- } else {
- versionByte[2]--;
- }
- }
- if (!selected) {
- System.err.println(Colors.error("Failed to select ECTester applet, is it installed?"));
- cardManager.disconnectFromCard();
- System.exit(1);
- }
- }
-
- // Setup logger and respWriter
- logger = new OutputLogger(true, cfg.log);
- respWriter = new ResponseWriter(logger.getPrintStream());
-
- // Try adding the BouncyCastleProvider, which might be used in some parts of ECTester.
- try {
- Security.addProvider(new BouncyCastleProvider());
- } catch (SecurityException | NoClassDefFoundError ignored) {
- }
- // Make BouncyCastle more lenient when we work with signatures in ASN.1 DER format,
- // cards sometimes are not fully compliant.
- System.setProperty("org.bouncycastle.asn1.allow_unsafe_integer", "true");
-
- //do action
- if (cli.hasOption("export")) {
- export();
- } else if (cli.hasOption("generate")) {
- generate();
- } else if (cli.hasOption("test")) {
- test();
- } else if (cli.hasOption("ecdh") || cli.hasOption("ecdhc")) {
- ecdh();
- } else if (cli.hasOption("ecdsa")) {
- ecdsa();
- } else if (cli.hasOption("info")) {
- info();
- }
-
- //disconnect
- cardManager.disconnectFromCard();
- logger.close();
-
- } catch (MissingOptionException moex) {
- System.err.println(Colors.error("Missing required options, one of:"));
- for (Object opt : moex.getMissingOptions().toArray()) {
- if (opt instanceof OptionGroup) {
- for (Option o : ((OptionGroup) opt).getOptions()) {
- System.err.print("-" + o.getOpt());
-
- if (o.hasLongOpt()) {
- System.err.print("\t/ --" + o.getLongOpt() + " ");
- }
-
- if (o.hasArg()) {
- if (o.hasOptionalArg()) {
- System.err.print("[" + o.getArgName() + "] ");
- } else {
- System.err.print("<" + o.getArgName() + "> ");
- }
- }
-
- if (o.getDescription() != null) {
- System.err.print("\t\t\t" + o.getDescription());
- }
- System.err.println();
- }
- } else if (opt instanceof String) {
- System.err.println(opt);
- }
- }
- } catch (MissingArgumentException maex) {
- System.err.println(Colors.error("Option, " + maex.getOption().getOpt() + " requires an argument: " + maex.getOption().getArgName()));
- } catch (NumberFormatException nfex) {
- System.err.println(Colors.error("Not a number. " + nfex.getMessage()));
- } catch (FileNotFoundException fnfe) {
- System.err.println(Colors.error("File " + fnfe.getMessage() + " not found."));
- } catch (ParseException | IOException ex) {
- System.err.println(Colors.error(ex.getMessage()));
- } catch (CardException ex) {
- if (logger != null)
- logger.println(ex.getMessage());
- ex.printStackTrace();
- } catch (ParserConfigurationException e) {
- e.printStackTrace();
- } finally {
- if (logger != null)
- logger.flush();
- }
- }
-
- /**
- * Parses command-line options.
- *
- * @param args cli arguments
- * @return parsed CommandLine object
- * @throws ParseException if there are any problems encountered while parsing the command line tokens
- */
- private CommandLine parseArgs(String[] args) throws ParseException {
- OptionGroup actions = new OptionGroup();
- actions.setRequired(true);
- actions.addOption(Option.builder("V").longOpt("version").desc("Print version info.").build());
- actions.addOption(Option.builder("h").longOpt("help").desc("Print help.").build());
- actions.addOption(Option.builder("ln").longOpt("list-named").desc("Print the list of supported named curves and keys.").hasArg().argName("what").optionalArg(true).build());
- actions.addOption(Option.builder("ls").longOpt("list-suites").desc("List supported test suites.").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. Optionally specify a test number to run only a part of a test suite. <test_suite>:\n- default\n- compression\n- invalid\n- twist\n- degenerate\n- cofactor\n- wrong\n- signature\n- composite\n- test-vectors\n- edge-cases\n- miscellaneous").hasArg().argName("test_suite[:from[:to]]").optionalArg(true).build());
- actions.addOption(Option.builder("dh").longOpt("ecdh").desc("Do EC KeyAgreement (ECDH...), [count] times.").hasArg().argName("count").optionalArg(true).build());
- actions.addOption(Option.builder("dsa").longOpt("ecdsa").desc("Sign data with ECDSA, [count] times.").hasArg().argName("count").optionalArg(true).build());
- actions.addOption(Option.builder("nf").longOpt("info").desc("Get applet info.").build());
-
- opts.addOptionGroup(actions);
-
- opts.addOption(Option.builder("b").longOpt("bit-size").desc("Set curve size.").hasArg().argName("bits").build());
- opts.addOption(Option.builder("fp").longOpt("prime-field").desc("Use a prime field.").build());
- opts.addOption(Option.builder("f2m").longOpt("binary-field").desc("Use a binary field.").build());
-
- OptionGroup curve = new OptionGroup();
- curve.addOption(Option.builder("nc").longOpt("named-curve").desc("Use a named curve, from CurveDB: <cat/id>").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);
-
- OptionGroup pub = new OptionGroup();
- 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>").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);
-
- OptionGroup key = new OptionGroup();
- key.addOption(Option.builder("nk").longOpt("named-key").desc("Use keyPair from KeyDB: <cat/id>").hasArg().argName("cat/id").build());
- key.addOption(Option.builder("k").longOpt("key").desc("Use keyPair from file <key_file> (wx,wy,s).").hasArg().argName("key_file").build());
- opts.addOptionGroup(key);
-
- opts.addOption(Option.builder("i").longOpt("input").desc("Input from file <input_file>, for ECDSA signing.").hasArg().argName("input_file").build());
- opts.addOption(Option.builder("o").longOpt("output").desc("Output into file <output_file>. The file can be prefixed by the format (one of text,yml,xml), such as: xml:<output_file>.").hasArgs().argName("output_file").build());
- opts.addOption(Option.builder("l").longOpt("log").desc("Log output into file [log_file].").hasArg().argName("log_file").optionalArg(true).build());
- opts.addOption(Option.builder("v").longOpt("verbose").desc("Turn on verbose logging.").build());
- opts.addOption(Option.builder().longOpt("format").desc("Output format to use. One of: text,yml,xml.").hasArg().argName("format").build());
-
- opts.addOption(Option.builder("kb").longOpt("key-builder").desc("Allocate KeyPair using KeyBuilder.").build());
- opts.addOption(Option.builder().longOpt("fixed").desc("Generate key(s) only once, keep them for later operations.").build());
- opts.addOption(Option.builder().longOpt("fixed-private").desc("Generate private key only once, keep it for later ECDH.").build());
- opts.addOption(Option.builder().longOpt("fixed-public").desc("Generate public key only once, keep it for later ECDH.").build());
- opts.addOption(Option.builder("f").longOpt("fresh").desc("Generate fresh keys (set domain parameters before every generation).").build());
- opts.addOption(Option.builder().longOpt("time").desc("Output better timing values, by running command in dry run mode and normal mode, and subtracting the two.").build());
- opts.addOption(Option.builder().longOpt("time-unit").desc("Use given time unit in measurement, one of: milli, micro, nano.").hasArg().argName("unit").build());
- opts.addOption(Option.builder().longOpt("cleanup").desc("Send the cleanup command trigerring JCSystem.requestObjectDeletion() after some operations.").build());
- opts.addOption(Option.builder("s").longOpt("simulate").desc("Simulate a card with jcardsim instead of using a terminal.").build());
- opts.addOption(Option.builder("y").longOpt("yes").desc("Accept all warnings and prompts.").build());
- opts.addOption(Option.builder("to").longOpt("test-options").desc("Test options to use:\n- preset: Use preset semi-random private keys (derived from curve) instead of generating keypairs on the cards when the test needs one.\n- random: Use fully random private keys instead of generating keypairs.").hasArg().argName("options").build());
-
- opts.addOption(Option.builder("ka").longOpt("ka-type").desc("Set KeyAgreement object [type], corresponds to JC.KeyAgreement constants.").hasArg().argName("type").optionalArg(true).build());
- opts.addOption(Option.builder("sig").longOpt("sig-type").desc("Set Signature object [type], corresponds to JC.Signature constants.").hasArg().argName("type").optionalArg(true).build());
- opts.addOption(Option.builder("C").longOpt("color").desc("Print stuff with color, requires ANSI terminal.").build());
-
- CommandLineParser parser = new DefaultParser();
- return parser.parse(opts, args);
- }
-
- private void listSuites() {
- CardTestSuite[] suites = new CardTestSuite[]{
- new CardDefaultSuite(null, null, null),
- new CardTestVectorSuite(null, null, null),
- new CardCompressionSuite(null, null, null),
- new CardWrongSuite(null, null, null),
- new CardDegenerateSuite(null, null, null),
- new CardCofactorSuite(null, null, null),
- new CardCompositeSuite(null, null, null),
- new CardInvalidSuite(null, null, null),
- new CardEdgeCasesSuite(null, null, null),
- new CardSignatureSuite(null, null, null),
- new CardTwistSuite(null, null, null),
- new CardMiscSuite(null, null, null)};
- for (CardTestSuite suite : suites) {
- System.out.println(" - " + Colors.bold(suite.getName()));
- for (String line : suite.getDescription()) {
- System.out.println("\t" + line);
- }
- if (suite.getOptions() != null) {
- System.out.println("\t" + Colors.underline("Options:") + " " + Arrays.toString(suite.getOptions()));
- }
- }
- System.out.println();
- System.out.println("For more information, look at the documentation at https://github.com/crocs-muni/ECTester.");
- }
-
- private void info() throws CardException {
- Response.GetInfo info = new Command.GetInfo(cardManager).send();
- System.out.println(String.format("Card ATR:\t\t\t\t%s", ByteUtil.bytesToHex(cardManager.getATR().getBytes(), false)));
- System.out.println(String.format("Card protocol:\t\t\t\t%s", cardManager.getProtocol()));
- System.out.println(String.format("ECTester applet version:\t\t%s", info.getVersion()));
- System.out.println(String.format("ECTester applet APDU support:\t\t%s", (info.getBase() == ECTesterApplet.BASE_221) ? "basic" : "extended length"));
- System.out.println(String.format("JavaCard API version:\t\t\t%.1f", info.getJavaCardVersion()));
- System.out.println(String.format("JavaCard supports system cleanup:\t%s", info.getCleanupSupport()));
- System.out.println(String.format("Array sizes (apduBuf,ram,ram2,apduArr):\t%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength()));
- }
-
- /**
- * Exports default card/simulation EC domain parameters to output file.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void export() throws CardException, IOException {
- byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
-
- List<Response> sent = new LinkedList<>();
- sent.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.keyBuilder, cfg.bits, keyClass).send());
- //sent.add(new Command.Clear(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
- sent.add(new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL).send());
-
- // Also support exporting set parameters, to verify they are set correctly.
- Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
- if (curve != null) {
- sent.add(curve.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 = cfg.primeField ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
- if (!export.successful()) {
- domain = (short) (domain ^ EC_Consts.PARAMETER_K);
- export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, domain).send();
- }
- sent.add(export);
-
- for (Response r : sent) {
- respWriter.outputResponse(r);
- }
- if (cfg.cleanup) {
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
- }
-
- PrintStream out = new PrintStream(FileUtil.openStream(cfg.outputs));
- byte[][] params = export.getParams();
- for (int i = 0; i < params.length; ++i) {
- out.print(ByteUtil.bytesToHex(params[i], false));
- if (i != params.length - 1) {
- out.print(",");
- }
- }
- out.close();
- }
-
- /**
- * Generates EC keyPairs and outputs them to output file.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void generate() throws CardException, IOException {
- byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
-
- Response allocate = new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.keyBuilder, cfg.bits, keyClass).send();
- respWriter.outputResponse(allocate);
-
- OutputStreamWriter keysFile = FileUtil.openFiles(cfg.outputs);
- keysFile.write(String.format("index;genTime[%s];exportTime[%s];pubW;privS\n", cfg.timeUnit, cfg.timeUnit));
-
- int generated = 0;
- int retry = 0;
- while (generated < cfg.generateAmount || cfg.generateAmount == 0) {
- if ((cfg.fresh || generated == 0) && curve != null) {
- Response fresh = curve.send();
- respWriter.outputResponse(fresh);
- }
-
- Command.Generate generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
- long time = 0;
- if (cfg.time) {
- time = -Command.dryRunTime(cardManager, generate, 2, respWriter);
- }
- Response.Generate response = generate.send();
- time += response.getDuration();
- respWriter.outputResponse(response);
-
- Response.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR).send();
- respWriter.outputResponse(export);
-
- if (!response.successful() || !export.successful()) {
- if (retry < 10) {
- retry++;
- continue;
- } else {
- System.err.println(Colors.error("Keys could not be generated/exported."));
- break;
- }
- }
-
- String pub = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
- String priv = ByteUtil.bytesToHex(export.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String line = String.format("%d;%d;%d;%s;%s\n", generated, Util.convertTime(time, cfg.timeUnit), Util.convertTime(export.getDuration(), cfg.timeUnit), pub, priv);
- keysFile.write(line);
- keysFile.flush();
- generated++;
- }
- if (cfg.cleanup) {
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
- }
-
- keysFile.close();
- }
-
- /**
- * Tests Elliptic curve support for a given curve/curves.
- *
- * @throws IOException if an IO error occurs
- */
- private void test() throws ParserConfigurationException, IOException {
- TestWriter writer = new FileTestWriter(cfg.format, true, cfg.outputs);
-
- CardTestSuite suite;
-
- switch (cfg.testSuite) {
- case "default":
- suite = new CardDefaultSuite(writer, cfg, cardManager);
- break;
- case "test-vectors":
- suite = new CardTestVectorSuite(writer, cfg, cardManager);
- break;
- case "compression":
- suite = new CardCompressionSuite(writer, cfg, cardManager);
- break;
- case "miscellaneous":
- suite = new CardMiscSuite(writer, cfg, cardManager);
- break;
- case "signature":
- suite = new CardSignatureSuite(writer, cfg, cardManager);
- break;
- default:
- // These run are dangerous, prompt before them.
- System.out.println("The test you selected (" + cfg.testSuite + ") is potentially dangerous.");
- System.out.println("Some of these run have caused temporary(or even permanent) DoS of some cards.");
- if (!cfg.yes) {
- System.out.print("Do you want to proceed? (y/n): ");
- Scanner in = new Scanner(System.in);
- String confirmation = in.nextLine().toLowerCase();
- if (!Arrays.asList("yes", "y").contains(confirmation)) {
- return;
- }
- in.close();
- }
- switch (cfg.testSuite) {
- case "wrong":
- suite = new CardWrongSuite(writer, cfg, cardManager);
- break;
- case "composite":
- suite = new CardCompositeSuite(writer, cfg, cardManager);
- break;
- case "invalid":
- suite = new CardInvalidSuite(writer, cfg, cardManager);
- break;
- case "degenerate":
- suite = new CardDegenerateSuite(writer, cfg, cardManager);
- break;
- case "twist":
- suite = new CardTwistSuite(writer, cfg, cardManager);
- break;
- case "cofactor":
- suite = new CardCofactorSuite(writer, cfg, cardManager);
- break;
- case "edge-cases":
- suite = new CardEdgeCasesSuite(writer, cfg, cardManager);
- break;
- default:
- System.err.println(Colors.error("Unknown test suite."));
- return;
- }
- break;
- }
-
- suite.run(cfg.testFrom, cfg.testTo);
- }
-
- /**
- * Performs ECDH key exchange.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void ecdh() throws IOException, CardException {
- byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_BOTH, cfg.bits, keyClass);
- List<Response> prepare = new LinkedList<>();
- prepare.add(new Command.AllocateKeyAgreement(cardManager, cfg.ECKAType).send()); // Prepare KeyAgreement or required type
- prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_BOTH, cfg.keyBuilder, cfg.bits, keyClass).send());
- if (curve != null)
- prepare.add(curve.send());
-
- for (Response r : prepare) {
- respWriter.outputResponse(r);
- }
-
- OutputStreamWriter out = null;
- if (cfg.outputs != null) {
- out = FileUtil.openFiles(cfg.outputs);
- out.write(String.format("index;time[%s];pubW;privS;secret[%s]\n", cfg.timeUnit, CardUtil.getKexHashName(cfg.ECKAType)));
- }
-
- Response gen = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_BOTH).send();
- respWriter.outputResponse(gen);
- if (cfg.anyPublicKey || cfg.anyKey) {
- Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W).send();
- respWriter.outputResponse(prep);
- }
- if (cfg.anyPrivateKey || cfg.anyKey) {
- Response prep = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S).send();
- respWriter.outputResponse(prep);
- }
-
- byte kp = ECTesterApplet.KEYPAIR_BOTH;
- if (cfg.fixedPrivate || cfg.anyPrivateKey) {
- kp ^= ECTesterApplet.KEYPAIR_LOCAL;
- }
- if (cfg.fixedPublic || cfg.anyPublicKey) {
- kp ^= ECTesterApplet.KEYPAIR_REMOTE;
- }
- if (cfg.fixedKey || cfg.anyKey) {
- kp = 0;
- }
-
- Command generate = null;
- if (kp != 0) {
- generate = new Command.Generate(cardManager, kp);
- }
-
- int retry = 0;
- int done = 0;
- while (done < cfg.ECKACount || cfg.ECKACount == 0) {
- if (generate != null) {
- Response regen = generate.send();
- respWriter.outputResponse(regen);
- }
-
- Response.Export exportRemote = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
- respWriter.outputResponse(exportRemote);
- Response.Export exportLocal = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S).send();
- respWriter.outputResponse(exportLocal);
- byte[] pubkey_bytes = exportRemote.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_W);
- byte[] privkey_bytes = exportLocal.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S);
-
- Command.ECDH perform = new Command.ECDH(cardManager, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, cfg.ECKAType);
-
- long time = 0;
- if (cfg.time) {
- time = -Command.dryRunTime(cardManager, perform, 2, respWriter);
- }
-
- Response.ECDH result = perform.send();
- respWriter.outputResponse(result);
-
- if (!result.successful() || !result.hasSecret()) {
- if (retry < 10) {
- ++retry;
- continue;
- } else {
- System.err.println(Colors.error("Couldn't obtain ECDH secret from card response."));
- break;
- }
- }
-
- if (out != null) {
- time += result.getDuration();
-
- out.write(String.format("%d;%d;%s;%s;%s\n", done, Util.convertTime(time, cfg.timeUnit), ByteUtil.bytesToHex(pubkey_bytes, false), ByteUtil.bytesToHex(privkey_bytes, false), ByteUtil.bytesToHex(result.getSecret(), false)));
- out.flush();
- }
-
- ++done;
- }
- if (cfg.cleanup) {
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
- }
-
- if (out != null)
- out.close();
- }
-
- /**
- * Performs ECDSA signature, on random or provided data.
- *
- * @throws CardException if APDU transmission fails
- * @throws IOException if an IO error occurs when writing to key file.
- */
- private void ecdsa() throws CardException, IOException {
- //read file, if asked to sign
- byte[] data;
- if (cfg.input != null) {
- File in = new File(cfg.input);
- long len = in.length();
- if (len == 0) {
- throw new FileNotFoundException(cfg.input);
- }
- data = Files.readAllBytes(in.toPath());
- } else {
- Random rand = new Random();
- data = new byte[32];
- rand.nextBytes(data);
- }
-
- Command generate;
- if (cfg.anyKeypart) {
- generate = Command.prepareKey(cardManager, EC_Store.getInstance(), cfg, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETERS_KEYPAIR);
- } else {
- generate = new Command.Generate(cardManager, ECTesterApplet.KEYPAIR_LOCAL);
- }
-
- byte keyClass = cfg.primeField ? KeyPair.ALG_EC_FP : KeyPair.ALG_EC_F2M;
- List<Response> prepare = new LinkedList<>();
- prepare.add(new Command.AllocateSignature(cardManager, cfg.ECDSAType).send());
- prepare.add(new Command.Allocate(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.keyBuilder, cfg.bits, keyClass).send());
- Command curve = Command.prepareCurve(cardManager, cfg, ECTesterApplet.KEYPAIR_LOCAL, cfg.bits, keyClass);
- if (curve != null)
- prepare.add(curve.send());
-
- for (Response r : prepare) {
- respWriter.outputResponse(r);
- }
-
- OutputStreamWriter out = FileUtil.openFiles(cfg.outputs);
- if (out != null) {
- out.write(String.format("index;signTime[%s];verifyTime[%s];data;pubW;privS;signature[%s];nonce;valid\n", cfg.timeUnit, cfg.timeUnit, CardUtil.getSigHashAlgo(cfg.ECDSAType)));
- }
-
- Command.Export export = new Command.Export(cardManager, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_BOTH, EC_Consts.PARAMETERS_KEYPAIR);
- Response.Export exported = null;
- if (cfg.fixedKey) {
- respWriter.outputResponse(generate.send());
- exported = export.send();
- respWriter.outputResponse(exported);
- }
-
- int retry = 0;
- int done = 0;
- while (done < cfg.ECDSACount || cfg.ECDSACount == 0) {
- if (!cfg.fixedKey) {
- respWriter.outputResponse(generate.send());
- exported = export.send();
- respWriter.outputResponse(exported);
- }
-
- Command.ECDSA_sign sign = new Command.ECDSA_sign(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, ECTesterApplet.EXPORT_TRUE, data);
-
- long signTime = 0;
- if (cfg.time) {
- signTime = -Command.dryRunTime(cardManager, sign, 2, respWriter);
- }
-
- Response.ECDSA signResp = sign.send();
- signTime += signResp.getDuration();
- respWriter.outputResponse(signResp);
- if (!signResp.successful() || !signResp.hasSignature()) {
- if (retry < 10) {
- ++retry;
- continue;
- } else {
- System.err.println(Colors.error("Couldn't obtain ECDSA signature from card response."));
- break;
- }
- }
- byte[] signature = signResp.getSignature();
- Command.ECDSA_verify verify = new Command.ECDSA_verify(cardManager, ECTesterApplet.KEYPAIR_LOCAL, cfg.ECDSAType, data, signature);
- long verifyTime = 0;
- if (cfg.time) {
- verifyTime = -Command.dryRunTime(cardManager, verify, 2, respWriter);
- }
- Response.ECDSA verifyResp = verify.send();
- verifyTime += verifyResp.getDuration();
- respWriter.outputResponse(verifyResp);
-
- if (verifyResp.error()) {
- if (retry < 10) {
- ++retry;
- continue;
- } else {
- System.err.println(Colors.error("Couldn't obtain ECDSA signature from card response."));
- break;
- }
- }
-
- if (out != null) {
- String pub = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W), false);
- String priv = ByteUtil.bytesToHex(exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S), false);
- String dataString = (cfg.input != null) ? "" : ByteUtil.bytesToHex(data, false);
- BigInteger privkey = new BigInteger(1, exported.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_S));
- EC_Curve actualCurve = Command.findCurve(cfg, cfg.bits, keyClass);
- String k = "";
- if (actualCurve != null) {
- ECParameterSpec params = actualCurve.toSpec();
- BigInteger kValue = ECUtil.recoverSignatureNonce(signature, data, privkey, params, CardUtil.getSigHashName(cfg.ECDSAType), "ECDSA");
- if (kValue != null) {
- k = ByteUtil.bytesToHex(kValue.toByteArray(), false);
- }
- }
- out.write(String.format("%d;%d;%d;%s;%s;%s;%s;%s;%d\n", done, Util.convertTime(signTime, cfg.timeUnit), Util.convertTime(verifyTime, cfg.timeUnit), dataString, pub, priv, ByteUtil.bytesToHex(signature, false), k, verifyResp.successful() ? 1 : 0));
- out.flush();
- }
-
- ++done;
- }
- if (cfg.cleanup) {
- Response cleanup = new Command.Cleanup(cardManager).send();
- respWriter.outputResponse(cleanup);
- }
- if (out != null)
- out.close();
- }
-
- public static void main(String[] args) {
- ECTesterReader app = new ECTesterReader();
- app.run(args);
- }
-
- public static class Config {
-
- //Options
- public short bits;
- public boolean all;
- public boolean primeField = false;
- public boolean binaryField = false;
-
-
- public String namedCurve;
- public String curveFile;
- public boolean customCurve = false;
-
- public boolean anyPublicKey = false;
- public String namedPublicKey;
- public String publicKey;
-
- public boolean anyPrivateKey = false;
- public String namedPrivateKey;
- public String privateKey;
-
- public boolean anyKey = false;
- public String namedKey;
- public String key;
-
- public boolean anyKeypart = false;
- public boolean fixedKey = false;
- public boolean fixedPrivate = false;
- public boolean fixedPublic = false;
- public byte keyBuilder;
-
- public String log;
-
- public boolean verbose = false;
- public String input;
- public String[] outputs;
- public boolean fresh = false;
- public boolean time = false;
- public String timeUnit;
- public boolean cleanup = false;
- public boolean simulate = false;
- public boolean yes = false;
- public String format;
- public boolean color;
-
- //Action-related options
- public String listNamed;
- public String testSuite;
- public int testFrom;
- public int testTo;
- public int generateAmount;
- public int ECKACount;
- public byte ECKAType = KeyAgreement_ALG_EC_SVDP_DH;
- public int ECDSACount;
- public byte ECDSAType = Signature_ALG_ECDSA_SHA;
- public Set<String> testOptions;
-
- /**
- * Reads and validates options, also sets defaults.
- *
- * @param cli cli object, with parsed args
- * @return whether the options are valid.
- */
- boolean readOptions(CommandLine cli) {
- bits = Short.parseShort(cli.getOptionValue("bit-size", "0"));
- all = cli.hasOption("all");
- primeField = cli.hasOption("fp");
- binaryField = cli.hasOption("f2m");
-
-
- namedCurve = cli.getOptionValue("named-curve");
- customCurve = cli.hasOption("custom");
- curveFile = cli.getOptionValue("curve");
-
- namedPublicKey = cli.getOptionValue("named-public");
- publicKey = cli.getOptionValue("public");
- anyPublicKey = (publicKey != null) || (namedPublicKey != null);
-
- namedPrivateKey = cli.getOptionValue("named-private");
- privateKey = cli.getOptionValue("private");
- anyPrivateKey = (privateKey != null) || (namedPrivateKey != null);
-
- namedKey = cli.getOptionValue("named-key");
- key = cli.getOptionValue("key");
- anyKey = (key != null) || (namedKey != null);
- anyKeypart = anyKey || anyPublicKey || anyPrivateKey;
- fixedKey = cli.hasOption("fixed");
- fixedPrivate = cli.hasOption("fixed-private");
- fixedPublic = cli.hasOption("fixed-public");
- keyBuilder = cli.hasOption("key-builder") ? ECTesterApplet.BUILD_KEYBUILDER : ECTesterApplet.BUILD_KEYPAIR;
-
- if (cli.hasOption("log")) {
- log = cli.getOptionValue("log", String.format("ECTESTER_log_%d.log", System.currentTimeMillis() / 1000));
- }
-
- verbose = cli.hasOption("verbose");
- input = cli.getOptionValue("input");
- outputs = cli.getOptionValues("output");
- fresh = cli.hasOption("fresh");
- time = cli.hasOption("time");
- cleanup = cli.hasOption("cleanup");
- simulate = cli.hasOption("simulate");
- yes = cli.hasOption("yes");
- color = cli.hasOption("color");
- Colors.enabled = color;
-
- timeUnit = cli.getOptionValue("time-unit", "micro");
- String[] times = new String[]{"milli", "micro", "nano"};
- if (!Arrays.asList(times).contains(timeUnit)) {
- System.err.println(Colors.error("Wrong time unit " + timeUnit + ". Should be one of " + Arrays.toString(times)));
- return false;
- }
-
- if (cli.hasOption("list-named")) {
- listNamed = cli.getOptionValue("list-named");
- return true;
- }
-
- format = cli.getOptionValue("format");
- String[] formats = new String[]{"text", "xml", "yaml", "yml"};
- if (format != null && !Arrays.asList(formats).contains(format)) {
- System.err.println(Colors.error("Wrong output format " + format + ". Should be one of " + Arrays.toString(formats)));
- return false;
- }
-
- if ((key != null || namedKey != null) && (anyPublicKey || anyPrivateKey)) {
- System.err.print(Colors.error("Can only specify the whole key with --key/--named-key or pubkey and privkey with --public/--named-public and --private/--named-private."));
- return false;
- }
- if (bits < 0) {
- System.err.println(Colors.error("Bit-size must not be negative."));
- return false;
- }
-
- if (key != null && namedKey != null || publicKey != null && namedPublicKey != null || privateKey != null && namedPrivateKey != null) {
- System.err.println(Colors.error("You cannot specify both a named key and a key file."));
- return false;
- }
-
- if (cli.hasOption("export")) {
- if (primeField == binaryField) {
- System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));
- return false;
- }
- if (anyKeypart) {
- System.err.println(Colors.error("Keys should not be specified when exporting curve params."));
- return false;
- }
- if (outputs == null) {
- System.err.println(Colors.error("You have to specify an output file for curve parameter export."));
- return false;
- }
- if (all || bits == 0) {
- System.err.println(Colors.error("You have to specify curve bit-size with -b"));
- return false;
- }
- } else if (cli.hasOption("generate")) {
- if (primeField == binaryField) {
- System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));
- return false;
- }
- if (anyKeypart) {
- System.err.println(Colors.error("Keys should not be specified when generating keys."));
- return false;
- }
- if (outputs == null) {
- System.err.println(Colors.error("You have to specify an output file for the key generation process."));
- return false;
- }
- if (all || bits == 0) {
- System.err.println(Colors.error("You have to specify curve bit-size with -b"));
- return false;
- }
-
- generateAmount = Integer.parseInt(cli.getOptionValue("generate", "0"));
- if (generateAmount < 0) {
- System.err.println(Colors.error("Amount of keys generated cant be negative."));
- return false;
- }
- } else if (cli.hasOption("test")) {
- if (!(binaryField || primeField)) {
- binaryField = true;
- primeField = true;
- }
-
- String suiteOpt = cli.getOptionValue("test", "default").toLowerCase();
- if (suiteOpt.contains(":")) {
- String[] parts = suiteOpt.split(":");
- testSuite = parts[0];
- try {
- testFrom = Integer.parseInt(parts[1]);
- } catch (NumberFormatException nfe) {
- System.err.println("Invalid test_from number: " + parts[1] + ".");
- return false;
- }
- if (parts.length == 3) {
- try {
- testTo = Integer.parseInt(parts[2]);
- } catch (NumberFormatException nfe) {
- System.err.println("Invalid test_to number: " + parts[2] + ".");
- return false;
- }
- } else if (parts.length != 2) {
- System.err.println("Invalid test suite selection.");
- return false;
- } else {
- testTo = -1;
- }
- } else {
- testSuite = suiteOpt;
- testFrom = 0;
- testTo = -1;
- }
-
- String[] tests = new String[]{"default", "composite", "compression", "invalid", "degenerate", "test-vectors", "wrong", "twist", "cofactor", "edge-cases", "miscellaneous", "signature"};
- String selected = null;
- for (String test : tests) {
- if (test.startsWith(testSuite)) {
- if (selected != null) {
- System.err.println(Colors.error("Test suite ambiguous " + test + " or " + selected + "?"));
- return false;
- } else {
- selected = test;
- }
- }
- }
- if (selected == null) {
- System.err.println(Colors.error("Unknown test suite " + testSuite + ". Should be one of: " + Arrays.toString(tests)));
- return false;
- } else {
- testSuite = selected;
- }
-
- String[] opts = cli.getOptionValue("test-options", "").split(",");
- List<String> validOpts = Arrays.asList("preset", "random");
- testOptions = new HashSet<>();
- for (String opt : opts) {
- if (opt.equals("")) {
- continue;
- }
- if (!validOpts.contains(opt)) {
- System.err.println(Colors.error("Unknown test option " + opt + ". Should be one of: " + Arrays.toString(validOpts.toArray())));
- return false;
- } else {
- testOptions.add(opt);
- }
- }
-
- if (testOptions.contains("preset") && testOptions.contains("random")) {
- System.err.println("Cannot have both preset and random option enabled.");
- return false;
- }
- } else if (cli.hasOption("ecdh")) {
- if (primeField == binaryField) {
- System.err.print(Colors.error("Need to specify field with -fp or -f2m. (not both)"));
- return false;
- }
- if (all || bits == 0) {
- System.err.println(Colors.error("You have to specify curve bit-size with -b"));
- return false;
- }
-
- ECKACount = Integer.parseInt(cli.getOptionValue("ecdh", "1"));
- if (ECKACount < 0) {
- System.err.println(Colors.error("ECDH count cannot be < 0."));
- return false;
- }
-
- ECKAType = CardUtil.parseKAType(cli.getOptionValue("ka-type", "1"));
- } else if (cli.hasOption("ecdsa")) {
- if (primeField == binaryField) {
- System.err.print(Colors.error("Need to specify field with -fp or -f2m. (but not both)"));
- return false;
- }
- if (all || bits == 0) {
- System.err.println(Colors.error("You have to specify curve bit-size with -b"));
- return false;
- }
-
- if ((anyPublicKey) != (anyPrivateKey) && !anyKey) {
- System.err.println(Colors.error("You cannot only specify a part of a keypair."));
- return false;
- }
-
- ECDSACount = Integer.parseInt(cli.getOptionValue("ecdsa", "1"));
- if (ECDSACount < 0) {
- System.err.println(Colors.error("ECDSA count cannot be < 0."));
- return false;
- }
-
- ECDSAType = CardUtil.parseSigType(cli.getOptionValue("sig-type", "17"));
- }
- return true;
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/ISO7816_status_words.txt b/src/cz/crcs/ectester/reader/ISO7816_status_words.txt
deleted file mode 100644
index bf5af2b..0000000
--- a/src/cz/crcs/ectester/reader/ISO7816_status_words.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-public interface ISO7816 {
-
- // Fields
- public static final byte INS_EXTERNAL_AUTHENTICATE = -126;
- public static final byte INS_SELECT = -92;
- public static final byte CLA_ISO7816 = 0;
- public static final byte OFFSET_CDATA = 5;
- public static final byte OFFSET_LC = 4;
- public static final byte OFFSET_P2 = 3;
- public static final byte OFFSET_P1 = 2;
- public static final byte OFFSET_INS = 1;
- public static final byte OFFSET_CLA = 0;
- public static final short SW_FILE_FULL = 27268; 0x6A84
- public static final short SW_UNKNOWN = 28416; 0x6F00
- public static final short SW_CLA_NOT_SUPPORTED = 28160; 0x6E00
- public static final short SW_INS_NOT_SUPPORTED = 27904; 0x6D00
- public static final short SW_CORRECT_LENGTH_00 = 27648; 0x6C00
- public static final short SW_WRONG_P1P2 = 27392; 0x6B00
- public static final short SW_INCORRECT_P1P2 = 27270; 0x6A86
- public static final short SW_RECORD_NOT_FOUND = 27267; 0x6A83
- public static final short SW_FILE_NOT_FOUND = 27266; 0x6A82
- public static final short SW_FUNC_NOT_SUPPORTED = 27265; 0x6A81
- public static final short SW_WRONG_DATA = 27264; 0x6A80
- public static final short SW_APPLET_SELECT_FAILED = 27033; 0x6999
- public static final short SW_COMMAND_NOT_ALLOWED = 27014; 0x6986
- public static final short SW_CONDITIONS_NOT_SATISFIED = 27013; 0x6985
- public static final short SW_DATA_INVALID = 27012; 0x6984
- public static final short SW_FILE_INVALID = 27011; 0x6983
- public static final short SW_SECURITY_STATUS_NOT_SATISFIED = 27010; 0x6982
- public static final short SW_WRONG_LENGTH = 26368; 0x6700
- public static final short SW_BYTES_REMAINING_00 = 24832; 0x6100
- public static final short SW_NO_ERROR = -28672; 0x9000
-}
-
-public interface JCStatus {
-static int ALGORITHM_NOT_SUPPORTED = 0x9484;
-static int APPLET_INVALIDATED = 0x6283;
-static int APPLET_SELECT_FAILED = 0x6999
-static int AUTHENTICATION_FAILED = 0x6300
-static int AUTHORIZATION_FAILED = 0x9482
-static int CHECKSUM_FAILED = 0x9584
-static int CLA_NOT_SUPPORTED = 0x6E00
-static int COMMAND_NOT_ALLOWED = 0x6986
-static int CONDITIONS_NOT_SATISFIED = 0x6985
-static int CORRECT_LENGTH_00 = 0x6C00
-static int DATA_INVALID = 0x6984
-static int DECRYPTION_FAILED = 0x9583
-static int FILE_FULL = 0x6A84
-static int FILE_INVALID = 0x6983
-static int FILE_NOT_FOUND = 0x6A82
-static int FUNC_NOT_SUPPORTED = 0x6A81
-static int INCORRECT_P1P2 = 0x6A86
-static int INS_NOT_SUPPORTED = 0x6D00
-static int INSTALLATION_FAILED = 0x9585
-static int INVALID_STATE = 0x9481
-static int NO_ERROR = 0x9000
-static int NO_SPECIFIC_DIAGNOSIS = 0x6400
-static int PIN_REQUIRED = 0x6982
-static int RECORD_NOT_FOUND = 0x6A83
-static int REFERENCE_DATA_NOT_FOUND = 0x6A88
-static int REGISTRATION_FAILED = 0x9586
-static int SECURITY_STATUS_NOT_SATISFIED = 0x6982
-static int SIGNATURE_CHECK_FAILED = 0x9582
-static int SM_INCORRECT = 0x6988
-static int SM_MISSING = 0x6987
-static int TRUNCATED_DATA = 0x6100
-static int UNKNOWN = 0x6F00
-static int WRONG_DATA = 0x6A80
-static int WRONG_LENGTH = 0x6700
-static int WRONG_P1P2 = 0x6B00
-} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/reader/command/Command.java b/src/cz/crcs/ectester/reader/command/Command.java
deleted file mode 100644
index 61e3900..0000000
--- a/src/cz/crcs/ectester/reader/command/Command.java
+++ /dev/null
@@ -1,920 +0,0 @@
-package cz.crcs.ectester.reader.command;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Params;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.output.ResponseWriter;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.KeyPair;
-
-import javax.smartcardio.CardException;
-import javax.smartcardio.CommandAPDU;
-import javax.smartcardio.ResponseAPDU;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class Command implements Cloneable {
- CommandAPDU cmd;
- CardMngr cardManager;
- // Workaround for a stupid Java bug that went unfixed for !12! years,
- // and for the even more stupid module system, which cannot properly work
- // with the fact that JCardSim has some java.* packages...
- final byte[] GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM = new byte[]{0};
-
-
- Command(CardMngr cardManager) {
- this.cardManager = cardManager;
- }
-
- public CommandAPDU getAPDU() {
- return cmd;
- }
-
- public abstract Response send() throws CardException;
-
- public static List<Response> sendAll(List<Command> commands) throws CardException {
- List<Response> result = new ArrayList<>();
- for (Command cmd : commands) {
- result.add(cmd.send());
- }
- return result;
- }
-
- public abstract String getDescription();
-
- @Override
- protected Command clone() throws CloneNotSupportedException {
- return (Command) super.clone();
- }
-
- public static EC_Curve findCurve(ECTesterReader.Config cfg, short keyLength, byte keyClass) throws IOException {
- if (cfg.customCurve) {
- byte curveId = EC_Consts.getCurve(keyLength, keyClass);
- return EC_Store.getInstance().getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
- } else if (cfg.namedCurve != null) {
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, cfg.namedCurve);
- 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.");
- }
- if (curve.getField() != keyClass) {
- throw new IOException("Curve field mismatch.");
- }
- return curve;
- } else if (cfg.curveFile != null) {
- EC_Curve curve = new EC_Curve(null, keyLength, keyClass);
-
- FileInputStream in = new FileInputStream(cfg.curveFile);
- curve.readCSV(in);
- in.close();
- return curve;
- } else {
- return null;
- }
- }
-
-
- /**
- * @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
- * @return a Command to send in order to prepare the curve on the keypairs.
- * @throws IOException if curve file cannot be found/opened
- */
- public static Command prepareCurve(CardMngr cardManager, ECTesterReader.Config cfg, byte keyPair, short keyLength, byte keyClass) throws IOException {
- if (cfg.customCurve) {
- // Set custom curve (one of the SECG curves embedded applet-side)
- short domainParams = keyClass == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
- return new Command.Set(cardManager, keyPair, EC_Consts.getCurve(keyLength, keyClass), domainParams, null);
- }
-
- EC_Curve curve = findCurve(cfg, keyLength, keyClass);
- if ((curve == null || curve.flatten() == null) && (cfg.namedCurve != null || cfg.curveFile != null)) {
- if (cfg.namedCurve != null) {
- throw new IOException("Couldn't read named curve data.");
- }
- throw new IOException("Couldn't read the curve file correctly.");
- } else if (curve == null) {
- return null;
- }
- return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, curve.getParams(), curve.flatten());
- }
-
-
- /**
- * @param cardManager
- * @param dataStore
- * @param cfg
- * @param keyPair which keyPair/s to set the key params on
- * @param allowedParams
- * @return a CommandAPDU setting params loaded on the keyPair/s
- * @throws IOException if any of the key files cannot be found/opened
- */
- public static Command prepareKey(CardMngr cardManager, EC_Store dataStore, ECTesterReader.Config cfg, byte keyPair, short allowedParams) throws IOException {
- short params = EC_Consts.PARAMETERS_NONE;
- byte[] data = null;
-
- if (cfg.key != null || cfg.namedKey != null) {
- params |= EC_Consts.PARAMETERS_KEYPAIR;
- EC_Params keypair = ECUtil.loadParams(EC_Consts.PARAMETERS_KEYPAIR, cfg.namedKey, cfg.key);
- if (keypair == null) {
- throw new IOException("KeyPair not found.");
- }
-
- data = keypair.flatten();
- if (data == null) {
- throw new IOException("Couldn't read the key file correctly.");
- }
- }
-
- if ((cfg.publicKey != null || cfg.namedPublicKey != null) && ((allowedParams & EC_Consts.PARAMETER_W) != 0)) {
- params |= EC_Consts.PARAMETER_W;
- EC_Params pub = ECUtil.loadParams(EC_Consts.PARAMETER_W, cfg.namedPublicKey, cfg.publicKey);
- if (pub == null) {
- throw new IOException("Public key not found.");
- }
-
- byte[] pubkey = pub.flatten(EC_Consts.PARAMETER_W);
- if (pubkey == null) {
- throw new IOException("Couldn't read the public key file correctly.");
- }
- data = pubkey;
- }
-
- if ((cfg.privateKey != null || cfg.namedPrivateKey != null) && ((allowedParams & EC_Consts.PARAMETER_S) != 0)) {
- params |= EC_Consts.PARAMETER_S;
- EC_Params priv = ECUtil.loadParams(EC_Consts.PARAMETER_S, cfg.namedPrivateKey, cfg.privateKey);
- if (priv == null) {
- throw new IOException("Private key not found.");
- }
-
- byte[] privkey = priv.flatten(EC_Consts.PARAMETER_S);
- if (privkey == null) {
- throw new IOException("Couldn't read the private key file correctly.");
- }
- data = ByteUtil.concatenate(data, privkey);
- }
- return new Command.Set(cardManager, keyPair, EC_Consts.CURVE_external, params, data);
- }
-
- public static long dryRunTime(CardMngr cardManager, Command cmd, int num, ResponseWriter respWriter) throws CardException {
- long time = 0;
- respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send());
- for (int i = 0; i < num; ++i) {
- Response dry = cmd.send();
- respWriter.outputResponse(dry);
- time += dry.getDuration();
- }
- time /= num;
- respWriter.outputResponse(new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send());
- return time;
- }
-
- /**
- *
- */
- public static class AllocateKeyAgreement extends Command {
- private byte kaType;
-
- /**
- * Creates the INS_ALLOCATE_KA instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param kaType which type of KeyAgreement to use
- */
- public AllocateKeyAgreement(CardMngr cardManager, byte kaType) {
- super(cardManager);
- this.kaType = kaType;
- byte[] data = new byte[]{kaType};
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_KA, 0x00, 0x00, data);
- }
-
- @Override
- public Response.AllocateKeyAgreement send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.AllocateKeyAgreement(response, getDescription(), elapsed, kaType);
- }
-
- @Override
- public String getDescription() {
- return String.format("Allocate KeyAgreement(%s) object", CardUtil.getKATypeString(kaType));
- }
- }
-
- /**
- *
- */
- public static class AllocateSignature extends Command {
- private byte sigType;
-
- /**
- * Creates the INS_ALLOCATE_SIG instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param sigType which type of Signature to use
- */
- public AllocateSignature(CardMngr cardManager, byte sigType) {
- super(cardManager);
- this.sigType = sigType;
- byte[] data = new byte[]{sigType};
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE_SIG, 0x00, 0x00, data);
- }
-
- @Override
- public Response.AllocateSignature send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.AllocateSignature(response, getDescription(), elapsed, sigType);
- }
-
- @Override
- public String getDescription() {
- return String.format("Allocate Signature(%s) object", CardUtil.getSigTypeString(sigType));
- }
- }
-
- /**
- *
- */
- public static class Allocate extends Command {
- private byte keyPair;
- private byte build;
- private short keyLength;
- private byte keyClass;
-
- /**
- * Creates the INS_ALLOCATE instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair which keyPair to use, local/remote (KEYPAIR_* | ...)
- * @param build whether to use KeyBuilder or Keypair alloc
- * @param keyLength key length to set
- * @param keyClass key class to allocate
- */
- public Allocate(CardMngr cardManager, byte keyPair, byte build, short keyLength, byte keyClass) {
- super(cardManager);
- this.keyPair = keyPair;
- this.build = build;
- this.keyLength = keyLength;
- this.keyClass = keyClass;
-
- byte[] data = new byte[]{0, 0, keyClass};
- ByteUtil.setShort(data, 0, keyLength);
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ALLOCATE, keyPair, build, data);
- }
-
- public Allocate(CardMngr cardManager, byte keyPair, short keyLength, byte keyClass) {
- this(cardManager, keyPair, (byte) (ECTesterApplet.BUILD_KEYPAIR | ECTesterApplet.BUILD_KEYBUILDER), keyLength, keyClass);
- }
-
- @Override
- public Response.Allocate send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Allocate(response, getDescription(), elapsed, keyPair, keyLength, keyClass);
- }
-
- @Override
- public String getDescription() {
- String field = keyClass == KeyPair.ALG_EC_FP ? "ALG_EC_FP" : "ALG_EC_F2M";
- String key;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- key = "both keypairs";
- } else {
- key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Allocate %s %db %s", key, keyLength, field);
- }
- }
-
- /**
- *
- */
- public static class Clear extends Command {
- private byte keyPair;
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param keyPair which keyPair clear, local/remote (KEYPAIR_* || ...)
- */
- public Clear(CardMngr cardManager, byte keyPair) {
- super(cardManager);
- this.keyPair = keyPair;
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEAR, keyPair, 0x00, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
- }
-
- @Override
- public Response.Clear send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Clear(response, getDescription(), elapsed, keyPair);
- }
-
- @Override
- public String getDescription() {
- String key;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- key = "both keypairs";
- } else {
- key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Clear %s", key);
- }
- }
-
- /**
- *
- */
- public static class Set extends Command {
- private byte keyPair;
- private byte curve;
- private short params;
- private byte[] external;
-
- /**
- * Creates the INS_SET instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair which keyPair to set params on, local/remote (KEYPAIR_* || ...)
- * @param curve curve to set (EC_Consts.CURVE_*)
- * @param params parameters to set (EC_Consts.PARAMETER_* | ...)
- * @param external external curve data, can be null
- */
- public Set(CardMngr cardManager, byte keyPair, byte curve, short params, byte[] external) {
- super(cardManager);
- this.keyPair = keyPair;
- this.curve = curve;
- this.params = params;
- this.external = external;
-
- int len = external != null ? 2 + external.length : 2;
- byte[] data = new byte[len];
- ByteUtil.setShort(data, 0, params);
- if (external != null) {
- System.arraycopy(external, 0, data, 2, external.length);
- }
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET, keyPair, curve, data);
- }
-
- @Override
- public Response.Set send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Set(response, getDescription(), elapsed, keyPair, curve, params);
- }
-
- @Override
- public String getDescription() {
- String name = CardUtil.getCurveName(curve);
- String what = CardUtil.getParameterString(params);
-
- String pair;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- pair = "both keypairs";
- } else {
- pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Set %s %s parameters on %s", name, what, pair);
- }
- }
-
- /**
- *
- */
- public static class Transform extends Command {
- private byte keyPair;
- private byte key;
- private short params;
- private short transformation;
-
- /**
- * @param cardManager cardManager to send APDU through
- * @param keyPair which keyPair to transform, local/remote (KEYPAIR_* || ...)
- * @param key key to transform (EC_Consts.KEY_* | ...)
- * @param params parameters to transform (EC_Consts.PARAMETER_* | ...)
- * @param transformation transformation type (EC_Consts.TRANSFORMATION_*)
- */
- public Transform(CardMngr cardManager, byte keyPair, byte key, short params, short transformation) {
- super(cardManager);
- this.keyPair = keyPair;
- this.key = key;
- this.params = params;
- this.transformation = transformation;
-
- byte[] data = new byte[4];
- ByteUtil.setShort(data, 0, params);
- ByteUtil.setShort(data, 2, transformation);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_TRANSFORM, keyPair, key, data);
- }
-
- @Override
- public Response.Transform send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Transform(response, getDescription(), elapsed, keyPair, key, params, transformation);
- }
-
- @Override
- public String getDescription() {
- String stringParams = CardUtil.getParams(params);
- String transform = CardUtil.getTransformation(transformation);
-
- String pair;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- pair = "both keypairs";
- } else {
- pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Transform params %s of %s, %s", stringParams, pair, transform);
- }
- }
-
- /**
- *
- */
- public static class Generate extends Command {
- private byte keyPair;
-
- /**
- * Creates the INS_GENERATE instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair which keyPair to generate, local/remote (KEYPAIR_* || ...)
- */
- public Generate(CardMngr cardManager, byte keyPair) {
- super(cardManager);
- this.keyPair = keyPair;
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GENERATE, keyPair, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
- }
-
- @Override
- public Response.Generate send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Generate(response, getDescription(), elapsed, keyPair);
- }
-
- @Override
- public String getDescription() {
- String key;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- key = "both keypairs";
- } else {
- key = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Generate %s", key);
- }
- }
-
- /**
- *
- */
- public static class Export extends Command {
- private byte keyPair;
- private byte key;
- private short params;
-
- /**
- * Creates the INS_EXPORT instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair keyPair to export from (KEYPAIR_* | ...)
- * @param key key to export from (EC_Consts.KEY_* | ...)
- * @param params params to export (EC_Consts.PARAMETER_* | ...)
- */
- public Export(CardMngr cardManager, byte keyPair, byte key, short params) {
- super(cardManager);
- this.keyPair = keyPair;
- this.key = key;
- this.params = params;
-
- byte[] data = new byte[2];
- ByteUtil.setShort(data, 0, params);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_EXPORT, keyPair, key, data);
- }
-
- @Override
- public Response.Export send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Export(response, getDescription(), elapsed, keyPair, key, params);
- }
-
- @Override
- public String getDescription() {
- String what = CardUtil.getParameterString(params);
-
- String source;
- if (key == EC_Consts.KEY_BOTH) {
- source = "both keys";
- } else {
- source = ((key == EC_Consts.KEY_PUBLIC) ? "public" : "private") + " key";
- }
- String pair;
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- pair = "both keypairs";
- } else {
- pair = ((keyPair == ECTesterApplet.KEYPAIR_LOCAL) ? "local" : "remote") + " keypair";
- }
- return String.format("Export %s params from %s of %s", what, source, pair);
- }
- }
-
- /**
- *
- */
- public static class ECDH extends Command {
- private byte pubkey;
- private byte privkey;
- private byte export;
- private short transformation;
- private byte type;
-
- /**
- * Creates the INS_ECDH instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param pubkey keyPair to use for public key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param export whether to export ECDH secret
- * @param transformation whether to transform the pubkey before ECDH (EC_Consts.TRANSFORMATION_* | ...)
- * @param type ECDH algorithm type (EC_Consts.KA_* | ...)
- */
- public ECDH(CardMngr cardManager, byte pubkey, byte privkey, byte export, short transformation, byte type) {
- super(cardManager);
- this.pubkey = pubkey;
- this.privkey = privkey;
- this.export = export;
- this.transformation = transformation;
- this.type = type;
-
- byte[] data = new byte[]{export, 0, 0, type};
- ByteUtil.setShort(data, 1, transformation);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH, pubkey, privkey, data);
- }
-
- @Override
- public Response.ECDH send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.ECDH(response, getDescription(), elapsed, pubkey, privkey, export, transformation, type);
- }
-
- @Override
- public String getDescription() {
- String algo = CardUtil.getKATypeString(type);
-
- String pub = pubkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
- String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
-
- String validity;
- if (transformation == EC_Consts.TRANSFORMATION_NONE) {
- validity = "";
- } else {
- validity = String.format("(%s point)", CardUtil.getTransformation(transformation));
- }
- return String.format("%s of %s pubkey and %s privkey%s", algo, pub, priv, validity);
- }
- }
-
- /**
- *
- */
- public static class ECDH_direct extends Command {
- private byte privkey;
- private byte export;
- private short transformation;
- private byte type;
- private byte[] pubkey;
-
- /**
- * Creates the INS_ECDH_DIRECT instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param privkey keyPair to use for private key, (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param export whether to export ECDH secret
- * @param transformation whether to transform the pubkey before ECDH (EC_Consts.TRANSFORMATION_* | ...)
- * @param type EC KeyAgreement type
- * @param pubkey pubkey data to do ECDH with.
- */
- public ECDH_direct(CardMngr cardManager, byte privkey, byte export, short transformation, byte type, byte[] pubkey) {
- super(cardManager);
- this.privkey = privkey;
- this.export = export;
- this.transformation = transformation;
- this.type = type;
- this.pubkey = pubkey;
-
- byte[] data = new byte[3 + pubkey.length];
- ByteUtil.setShort(data, 0, transformation);
- data[2] = type;
- System.arraycopy(pubkey, 0, data, 3, pubkey.length);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDH_DIRECT, privkey, export, data);
- }
-
- @Override
- public Response.ECDH send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.ECDH(response, getDescription(), elapsed, ECTesterApplet.KEYPAIR_REMOTE, privkey, export, transformation, type);
- }
-
- @Override
- public String getDescription() {
- String algo = CardUtil.getKATypeString(type);
-
- String priv = privkey == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
-
- String validity;
- if (transformation == EC_Consts.TRANSFORMATION_NONE) {
- validity = "";
- } else {
- validity = String.format("(%s point)", CardUtil.getTransformation(transformation));
- }
- return String.format("%s of external pubkey and %s privkey%s", algo, priv, validity);
- }
- }
-
- public static class ECDSA extends Command {
- private byte keyPair;
- private byte sigType;
- private byte export;
- private byte[] raw;
-
- /**
- * Creates the INS_ECDSA instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param sigType Signature type to use
- * @param export whether to export ECDSA signature
- * @param raw data to sign, can be null, in which case random data is signed.
- */
- public ECDSA(CardMngr cardManager, byte keyPair, byte sigType, byte export, byte[] raw) {
- super(cardManager);
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- throw new IllegalArgumentException();
- }
-
- this.keyPair = keyPair;
- this.sigType = sigType;
- this.export = export;
- this.raw = raw;
-
- int len = raw != null ? raw.length : 0;
- byte[] data = new byte[3 + len];
- data[0] = sigType;
- ByteUtil.setShort(data, 1, (short) len);
- if (raw != null) {
- System.arraycopy(raw, 0, data, 3, len);
- }
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDSA, keyPair, export, data);
- }
-
- @Override
- public Response.ECDSA send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.ECDSA(response, getDescription(), elapsed, keyPair, sigType, export, raw);
- }
-
- @Override
- public String getDescription() {
- String algo = CardUtil.getSigTypeString(sigType);
- String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
- String data = raw == null ? "random" : "provided";
- return String.format("%s with %s keypair(%s data)", algo, key, data);
- }
- }
-
- public static class ECDSA_sign extends Command {
- private byte keyPair;
- private byte sigType;
- private byte export;
- private byte[] raw;
-
- /**
- * Creates the INS_ECDSA_SIGN instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param sigType Signature type to use
- * @param export whether to export ECDSA signature
- * @param raw data to sign, can be null, in which case random data is signed.
- */
- public ECDSA_sign(CardMngr cardManager, byte keyPair, byte sigType, byte export, byte[] raw) {
- super(cardManager);
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- throw new IllegalArgumentException();
- }
-
- this.keyPair = keyPair;
- this.sigType = sigType;
- this.export = export;
- this.raw = raw;
-
- int len = raw != null ? raw.length : 0;
- byte[] data = new byte[3 + len];
- data[0] = sigType;
- ByteUtil.setShort(data, 1, (short) len);
- if (raw != null) {
- System.arraycopy(raw, 0, data, 3, len);
- }
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDSA_SIGN, keyPair, export, data);
- }
-
- @Override
- public Response.ECDSA send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.ECDSA(response, getDescription(), elapsed, keyPair, sigType, export, raw);
- }
-
- @Override
- public String getDescription() {
- String algo = CardUtil.getSigTypeString(sigType);
- String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
- String data = raw == null ? "random" : "provided";
- return String.format("%s signature with %s keypair(%s data)", algo, key, data);
- }
- }
-
- public static class ECDSA_verify extends Command {
- private byte keyPair;
- private byte sigType;
- private byte[] raw;
- private byte[] signature;
-
- /**
- * Creates the INS_ECDSA_VERIFY instruction.
- *
- * @param cardManager cardManager to send APDU through
- * @param keyPair keyPair to use for signing and verification (KEYPAIR_LOCAL || KEYPAIR_REMOTE)
- * @param sigType Signature type to use
- * @param raw data to sign
- * @param signature signature data
- */
- public ECDSA_verify(CardMngr cardManager, byte keyPair, byte sigType, byte[] raw, byte[] signature) {
- super(cardManager);
- if (keyPair == ECTesterApplet.KEYPAIR_BOTH) {
- throw new IllegalArgumentException();
- }
- if (raw == null || signature == null) {
- throw new IllegalArgumentException();
- }
-
- this.keyPair = keyPair;
- this.sigType = sigType;
- this.raw = raw;
- this.signature = signature;
-
- byte[] data = new byte[4 + raw.length + signature.length];
- ByteUtil.setShort(data, 0, (short) raw.length);
- System.arraycopy(raw, 0, data, 2, raw.length);
- ByteUtil.setShort(data, 2 + raw.length, (short) signature.length);
- System.arraycopy(signature, 0, data, 2 + raw.length + 2, signature.length);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_ECDSA_VERIFY, keyPair, sigType, data);
- }
-
- @Override
- public Response.ECDSA send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.ECDSA(response, getDescription(), elapsed, keyPair, sigType, ECTesterApplet.EXPORT_FALSE, raw);
- }
-
- @Override
- public String getDescription() {
- String algo = CardUtil.getSigTypeString(sigType);
- String key = keyPair == ECTesterApplet.KEYPAIR_LOCAL ? "local" : "remote";
- String data = raw == null ? "random" : "provided";
- return String.format("%s verification with %s keypair(%s data)", algo, key, data);
- }
- }
-
- /**
- *
- */
- public static class Cleanup extends Command {
-
- /**
- * @param cardManager cardManager to send APDU through
- */
- public Cleanup(CardMngr cardManager) {
- super(cardManager);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_CLEANUP, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
- }
-
- @Override
- public Response.Cleanup send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.Cleanup(response, getDescription(), elapsed);
- }
-
- @Override
- public String getDescription() {
- return "Request JCSystem object deletion";
- }
- }
-
- /**
- *
- */
- public static class GetInfo extends Command {
-
- /**
- * @param cardManager cardManager to send APDU through
- */
- public GetInfo(CardMngr cardManager) {
- super(cardManager);
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_GET_INFO, 0, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
- }
-
- @Override
- public Response.GetInfo send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.GetInfo(response, getDescription(), elapsed);
- }
-
- @Override
- public String getDescription() {
- return "Get applet info";
- }
- }
-
- /**
- *
- */
- public static class SetDryRunMode extends Command {
- private byte dryRunMode;
-
- /**
- * @param cardManager
- * @param dryRunMode
- */
- public SetDryRunMode(CardMngr cardManager, byte dryRunMode) {
- super(cardManager);
- this.dryRunMode = dryRunMode;
-
- this.cmd = new CommandAPDU(ECTesterApplet.CLA_ECTESTERAPPLET, ECTesterApplet.INS_SET_DRY_RUN_MODE, dryRunMode, 0, GOD_DAMN_JAVA_BUG_6474858_AND_GOD_DAMN_JAVA_12_MODULE_SYSTEM);
- }
-
- @Override
- public Response.SetDryRunMode send() throws CardException {
- long elapsed = -System.nanoTime();
- ResponseAPDU response = cardManager.send(cmd);
- elapsed += System.nanoTime();
- return new Response.SetDryRunMode(response, getDescription(), elapsed);
- }
-
- @Override
- public String getDescription() {
- return (dryRunMode == ECTesterApplet.MODE_NORMAL ? "Disable" : "Enable") + " dry run mode";
- }
- }
-}
-
diff --git a/src/cz/crcs/ectester/reader/output/FileTestWriter.java b/src/cz/crcs/ectester/reader/output/FileTestWriter.java
deleted file mode 100644
index 69e5f41..0000000
--- a/src/cz/crcs/ectester/reader/output/FileTestWriter.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package cz.crcs.ectester.reader.output;
-
-import cz.crcs.ectester.common.output.TeeTestWriter;
-import cz.crcs.ectester.common.output.TestWriter;
-
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
-import java.util.regex.Pattern;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class FileTestWriter extends TeeTestWriter {
-
- private static final Pattern PREFIX = Pattern.compile("(text|xml|yaml|yml):.+");
-
- public FileTestWriter(String defaultFormat, boolean systemOut, String[] files) throws ParserConfigurationException, FileNotFoundException {
- int fLength = files == null ? 0 : files.length;
- writers = new TestWriter[systemOut ? fLength + 1 : fLength];
- if (systemOut) {
- writers[0] = createWriter(defaultFormat, System.out);
- }
- for (int i = 0; i < fLength; ++i) {
- String fName = files[i];
- String format = null;
- if (PREFIX.matcher(fName).matches()) {
- String[] split = fName.split(":", 2);
- format = split[0];
- fName = split[1];
- }
- writers[i + 1] = createWriter(format, new PrintStream(new FileOutputStream(fName)));
- }
- }
-
- private TestWriter createWriter(String format, PrintStream out) throws ParserConfigurationException {
- if (format == null) {
- return new TextTestWriter(out);
- }
- switch (format) {
- case "text":
- return new TextTestWriter(out);
- case "xml":
- return new XMLTestWriter(out);
- case "yaml":
- case "yml":
- return new YAMLTestWriter(out);
- default:
- return null;
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/output/ResponseWriter.java b/src/cz/crcs/ectester/reader/output/ResponseWriter.java
deleted file mode 100644
index 85bf79a..0000000
--- a/src/cz/crcs/ectester/reader/output/ResponseWriter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package cz.crcs.ectester.reader.output;
-
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.reader.response.Response;
-
-import java.io.PrintStream;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class ResponseWriter {
- private PrintStream output;
-
- public ResponseWriter(PrintStream output) {
- this.output = output;
- }
-
- public String responseSuffix(Response r) {
- StringBuilder suffix = new StringBuilder();
- for (int j = 0; j < r.getNumSW(); ++j) {
- short sw = r.getSW(j);
- if (sw != 0) {
- suffix.append(" ").append(CardUtil.getSWString(sw));
- }
- }
- if (suffix.length() == 0) {
- suffix.append(" [").append(CardUtil.getSW(r.getNaturalSW())).append(String.format(" 0x%04x", r.getNaturalSW())).append("]");
- }
- return String.format("%4d ms ┃ %s", r.getDuration() / 1000000, suffix);
- }
-
- public String responseString(Response r) {
- String out = "";
- out += String.format("%-70s", r.getDescription()) + " ┃ ";
- out += responseSuffix(r);
- return out;
- }
-
- public void outputResponse(Response r) {
- output.println(responseString(r));
- output.flush();
- }
-}
diff --git a/src/cz/crcs/ectester/reader/output/TextTestWriter.java b/src/cz/crcs/ectester/reader/output/TextTestWriter.java
deleted file mode 100644
index 2775647..0000000
--- a/src/cz/crcs/ectester/reader/output/TextTestWriter.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package cz.crcs.ectester.reader.output;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.common.cli.Colors;
-import cz.crcs.ectester.common.output.BaseTextTestWriter;
-import cz.crcs.ectester.common.test.TestSuite;
-import cz.crcs.ectester.common.test.Testable;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.CardTestSuite;
-import cz.crcs.ectester.reader.test.CommandTestable;
-
-import javax.smartcardio.CardException;
-import java.io.PrintStream;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class TextTestWriter extends BaseTextTestWriter {
- private ResponseWriter writer;
-
- public TextTestWriter(PrintStream output) {
- super(output);
- this.writer = new ResponseWriter(output);
- }
-
- @Override
- protected String testableString(Testable t) {
- if (t instanceof CommandTestable) {
- CommandTestable cmd = (CommandTestable) t;
- Response response = cmd.getResponse();
- if (response != null) {
- return writer.responseSuffix(response);
- }
- }
- return "";
- }
-
- @Override
- protected String deviceString(TestSuite suite) {
- if (suite instanceof CardTestSuite) {
- CardTestSuite cardSuite = (CardTestSuite) suite;
- StringBuilder sb = new StringBuilder();
- try {
- sb.append("═══ ").append(Colors.underline("ECTester version:")).append(" ").append(ECTesterReader.VERSION).append(ECTesterReader.GIT_COMMIT).append(System.lineSeparator());
- Response.GetInfo info = new Command.GetInfo(cardSuite.getCard()).send();
- sb.append("═══ ").append(Colors.underline("ECTester applet version:")).append(" ").append(info.getVersion()).append(info.getBase() == ECTesterApplet.BASE_221 ? "" : " (extended length)").append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Card ATR:")).append(" ").append(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false)).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("JavaCard version:")).append(" ").append(info.getJavaCardVersion()).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Array sizes (apduBuf, ram, ram2, apduArr):")).append(" ").append(String.format("%d %d %d %d", info.getApduBufferLength(), info.getRamArrayLength(), info.getRamArray2Length(), info.getApduArrayLength())).append(System.lineSeparator());
- sb.append("═══ ").append(Colors.underline("Test options:")).append(" ").append(String.join(",", cardSuite.getCfg().testOptions)).append(System.lineSeparator());
- CardMngr.CPLC cplc = cardSuite.getCard().getCPLC();
- if (!cplc.values().isEmpty()) {
- sb.append("═══ ").append(Colors.underline("Card CPLC data:")).append(System.lineSeparator());
- for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
- CardMngr.CPLC.Field field = entry.getKey();
- byte[] value = entry.getValue();
- sb.append("═══ ").append(field.name()).append(": ").append(CardMngr.mapCPLCField(field, value));
- }
- }
- } catch (CardException ignored) {
- }
- return sb.toString();
- }
- return "";
- }
-}
diff --git a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java b/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
deleted file mode 100644
index fc41805..0000000
--- a/src/cz/crcs/ectester/reader/output/XMLTestWriter.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package cz.crcs.ectester.reader.output;
-
-import cz.crcs.ectester.common.output.BaseXMLTestWriter;
-import cz.crcs.ectester.common.test.TestSuite;
-import cz.crcs.ectester.common.test.Testable;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.CardTestSuite;
-import cz.crcs.ectester.reader.test.CommandTestable;
-import org.w3c.dom.Element;
-
-import javax.smartcardio.CardException;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.OutputStream;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class XMLTestWriter extends BaseXMLTestWriter {
- public XMLTestWriter(OutputStream output) throws ParserConfigurationException {
- super(output);
- }
-
- private Element commandElement(Command c) {
- Element commandElem = doc.createElement("command");
- if (c == null) {
- return commandElem;
- }
-
- Element apdu = doc.createElement("apdu");
- apdu.setTextContent(ByteUtil.bytesToHex(c.getAPDU().getBytes()));
- commandElem.appendChild(apdu);
-
- Element description = doc.createElement("desc");
- description.setTextContent(c.getDescription());
- commandElem.appendChild(description);
-
- return commandElem;
- }
-
- private Element responseElement(Response r) {
- Element responseElem = doc.createElement("response");
- if (r == null) {
- return responseElem;
- }
-
- responseElem.setAttribute("successful", r.successful() ? "true" : "false");
-
- Element apdu = doc.createElement("apdu");
- apdu.setTextContent(ByteUtil.bytesToHex(r.getAPDU().getBytes()));
- responseElem.appendChild(apdu);
-
- Element naturalSW = doc.createElement("natural-sw");
- naturalSW.setTextContent(String.valueOf(Short.toUnsignedInt(r.getNaturalSW())));
- responseElem.appendChild(naturalSW);
-
- Element sws = doc.createElement("sws");
- for (int i = 0; i < r.getNumSW(); ++i) {
- Element sw = doc.createElement("sw");
- sw.setTextContent(String.valueOf(Short.toUnsignedInt(r.getSW(i))));
- sws.appendChild(sw);
- }
- responseElem.appendChild(sws);
-
- Element duration = doc.createElement("duration");
- duration.setTextContent(String.valueOf(r.getDuration()));
- responseElem.appendChild(duration);
-
- Element description = doc.createElement("desc");
- description.setTextContent(r.getDescription());
- responseElem.appendChild(description);
-
- return responseElem;
- }
-
- @Override
- protected Element testableElement(Testable t) {
- if (t instanceof CommandTestable) {
- CommandTestable cmd = (CommandTestable) t;
- Element result = doc.createElement("test");
- result.setAttribute("type", "command");
- result.appendChild(commandElement(cmd.getCommand()));
- result.appendChild(responseElement(cmd.getResponse()));
- return result;
- }
- return null;
- }
-
- private Element cplcElement(CardMngr card) {
- Element result = doc.createElement("cplc");
- try {
- CardMngr.CPLC cplc = card.getCPLC();
- if (!cplc.values().isEmpty()) {
- for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
- CardMngr.CPLC.Field field = entry.getKey();
- byte[] value = entry.getValue();
- Element keyVal = doc.createElement(field.name());
- keyVal.setTextContent(ByteUtil.bytesToHex(value, false));
- result.appendChild(keyVal);
- }
- }
- } catch (CardException ignored) {
- }
- return result;
- }
-
- private Element appletElement(CardMngr card) {
- Element result = doc.createElement("applet");
- try {
- Response.GetInfo info = new Command.GetInfo(card).send();
- result.setAttribute("version", info.getVersion());
- result.setAttribute("javacard", String.format("%.1f", info.getJavaCardVersion()));
- result.setAttribute("base", String.format("%#x", info.getBase()));
- result.setAttribute("cleanup", String.valueOf(info.getCleanupSupport()));
- Element arrays = doc.createElement("arrays");
- Element apduBuf = doc.createElement("length");
- apduBuf.setAttribute("name", "apduBuf");
- apduBuf.setTextContent(String.valueOf(info.getApduBufferLength()));
- Element ramArray = doc.createElement("length");
- ramArray.setAttribute("name", "ramArray");
- ramArray.setTextContent(String.valueOf(info.getRamArrayLength()));
- Element ramArray2 = doc.createElement("length");
- ramArray2.setAttribute("name", "ramArray2");
- ramArray2.setTextContent(String.valueOf(info.getRamArray2Length()));
- Element apduArray = doc.createElement("length");
- apduArray.setAttribute("name", "apduArray");
- apduArray.setTextContent(String.valueOf(info.getApduArrayLength()));
- arrays.appendChild(apduBuf);
- arrays.appendChild(ramArray);
- arrays.appendChild(ramArray2);
- arrays.appendChild(apduArray);
- result.appendChild(arrays);
- } catch (CardException ignored) {
- }
- return result;
- }
-
- @Override
- protected Element deviceElement(TestSuite suite) {
- if (suite instanceof CardTestSuite) {
- CardTestSuite cardSuite = (CardTestSuite) suite;
- Element result = doc.createElement("device");
- result.setAttribute("type", "card");
- result.setAttribute("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
- result.appendChild(cplcElement(cardSuite.getCard()));
- result.appendChild(appletElement(cardSuite.getCard()));
-
- Element atr = doc.createElement("ATR");
- atr.setTextContent(ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
- result.appendChild(atr);
- return result;
- }
- return null;
- }
-} \ No newline at end of file
diff --git a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java b/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
deleted file mode 100644
index 56ecb71..0000000
--- a/src/cz/crcs/ectester/reader/output/YAMLTestWriter.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package cz.crcs.ectester.reader.output;
-
-import cz.crcs.ectester.common.output.BaseYAMLTestWriter;
-import cz.crcs.ectester.common.test.TestSuite;
-import cz.crcs.ectester.common.test.Testable;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import cz.crcs.ectester.reader.test.CardTestSuite;
-import cz.crcs.ectester.reader.test.CommandTestable;
-
-import javax.smartcardio.CardException;
-import java.io.PrintStream;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class YAMLTestWriter extends BaseYAMLTestWriter {
- public YAMLTestWriter(PrintStream output) {
- super(output);
- }
-
- private Map<String, Object> commandObject(Command c) {
- Map<String, Object> commandObj = new LinkedHashMap<>();
- if (c == null) {
- return commandObj;
- }
- commandObj.put("apdu", ByteUtil.bytesToHex(c.getAPDU().getBytes()));
- commandObj.put("desc", c.getDescription());
- return commandObj;
- }
-
- private Map<String, Object> responseObject(Response r) {
- Map<String, Object> responseObj = new LinkedHashMap<>();
- if (r == null) {
- return responseObj;
- }
- responseObj.put("successful", r.successful());
- responseObj.put("apdu", ByteUtil.bytesToHex(r.getAPDU().getBytes()));
- responseObj.put("natural_sw", Short.toUnsignedInt(r.getNaturalSW()));
- List<Integer> sws = new LinkedList<>();
- for (int i = 0; i < r.getNumSW(); ++i) {
- sws.add(Short.toUnsignedInt(r.getSW(i)));
- }
- responseObj.put("sws", sws);
- responseObj.put("duration", r.getDuration());
- responseObj.put("desc", r.getDescription());
- return responseObj;
- }
-
- @Override
- protected Map<String, Object> testableObject(Testable t) {
- if (t instanceof CommandTestable) {
- CommandTestable cmd = (CommandTestable) t;
- Map<String, Object> result = new LinkedHashMap<>();
- result.put("type", "command");
- result.put("command", commandObject(cmd.getCommand()));
- result.put("response", responseObject(cmd.getResponse()));
- return result;
- }
- return null;
- }
-
- private Map<String, Object> cplcObject(CardMngr card) {
- Map<String, Object> result = new LinkedHashMap<>();
- try {
- CardMngr.CPLC cplc = card.getCPLC();
- if (!cplc.values().isEmpty()) {
- for (Map.Entry<CardMngr.CPLC.Field, byte[]> entry : cplc.values().entrySet()) {
- CardMngr.CPLC.Field field = entry.getKey();
- byte[] value = entry.getValue();
- result.put(field.name(), ByteUtil.bytesToHex(value, false));
- }
- }
- } catch (CardException ignored) {
- }
- return result;
- }
-
- private Map<String, Object> appletObject(CardMngr card) {
- Map<String, Object> result = new LinkedHashMap<>();
- try {
- Response.GetInfo info = new Command.GetInfo(card).send();
- result.put("version", info.getVersion());
- result.put("javacard", info.getJavaCardVersion());
- result.put("base", info.getBase());
- result.put("cleanup", info.getCleanupSupport());
- Map<String, Integer> arrays = new LinkedHashMap<>();
- arrays.put("apduBuf", Short.toUnsignedInt(info.getApduBufferLength()));
- arrays.put("ramArray", Short.toUnsignedInt(info.getRamArrayLength()));
- arrays.put("ramArray2", Short.toUnsignedInt(info.getRamArray2Length()));
- arrays.put("apduArray", Short.toUnsignedInt(info.getApduArrayLength()));
- result.put("arrays", arrays);
- } catch (CardException ignored) {
- }
- return result;
- }
-
- @Override
- protected Map<String, Object> deviceObject(TestSuite suite) {
- if (suite instanceof CardTestSuite) {
- CardTestSuite cardSuite = (CardTestSuite) suite;
- Map<String, Object> result = new LinkedHashMap<>();
- result.put("type", "card");
- result.put("ectester", ECTesterReader.VERSION + ECTesterReader.GIT_COMMIT);
- result.put("cplc", cplcObject(cardSuite.getCard()));
- result.put("applet", appletObject(cardSuite.getCard()));
- result.put("ATR", ByteUtil.bytesToHex(cardSuite.getCard().getATR().getBytes(), false));
- return result;
- }
- return null;
- }
-}
diff --git a/src/cz/crcs/ectester/reader/response/Response.java b/src/cz/crcs/ectester/reader/response/Response.java
deleted file mode 100644
index f36d087..0000000
--- a/src/cz/crcs/ectester/reader/response/Response.java
+++ /dev/null
@@ -1,526 +0,0 @@
-package cz.crcs.ectester.reader.response;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.util.ByteUtil;
-import javacard.framework.ISO7816;
-
-import javax.smartcardio.ResponseAPDU;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class Response {
- private ResponseAPDU resp;
- private long time;
- private short[] sws;
- private int numSW = 0;
- private byte[][] params;
- private boolean success = true;
- private boolean error = false;
- private String description;
-
- public Response(ResponseAPDU response, String description, long time) {
- this.resp = response;
- this.description = description;
- this.time = time;
- }
-
- boolean parse(int numSW, int numParams) {
- this.numSW = numSW;
- this.sws = new short[numSW];
-
- byte[] data = resp.getData();
- int offset = 0;
-
- //parse SWs in response
- for (int i = 0; i < numSW; ++i) {
- if (getLength() >= (offset + 2)) {
- short sw = ByteUtil.getShort(data, offset);
- offset += 2;
- sws[i] = sw;
- if (sw != ISO7816.SW_NO_ERROR) {
- success = false;
- }
- } else {
- success = false;
- error = true;
- }
- }
-
- if ((short) resp.getSW() != ISO7816.SW_NO_ERROR) {
- success = false;
- error = true;
- }
-
-
- //try to parse numParams..
- params = new byte[numParams][];
- for (int i = 0; i < numParams; i++) {
- if (data.length - offset < 2) {
- success = false;
- error = true;
- break;
- }
- short paramLength = ByteUtil.getShort(data, offset);
- offset += 2;
- if (data.length < offset + paramLength) {
- error = true;
- success = false;
- break;
- }
- params[i] = new byte[paramLength];
- System.arraycopy(data, offset, params[i], 0, paramLength);
- offset += paramLength;
- }
- return success;
- }
-
- public ResponseAPDU getAPDU() {
- return resp;
- }
-
- public byte[] getData() {
- return resp.getData();
- }
-
- public long getDuration() {
- return time;
- }
-
- public short getNaturalSW() {
- return (short) resp.getSW();
- }
-
- public short[] getSWs() {
- return sws;
- }
-
- public short getSW(int index) {
- return sws[index];
- }
-
- public int getNumSW() {
- return numSW;
- }
-
- public boolean hasParam(int index) {
- return params.length >= index + 1 && params[index] != null;
- }
-
- public int getParamLength(int index) {
- return params[index].length;
- }
-
- public byte[] getParam(int index) {
- return params[index];
- }
-
- public byte[][] getParams() {
- return params;
- }
-
- public int getLength() {
- return resp.getNr();
- }
-
- public boolean successful() {
- return this.success;
- }
-
- public boolean error() {
- return this.error;
- }
-
- public String getDescription() {
- return description;
- }
-
- /**
- *
- */
- public static class AllocateKeyAgreement extends Response {
- private byte kaType;
-
- public AllocateKeyAgreement(ResponseAPDU response, String description, long time, byte kaType) {
- super(response, description, time);
- this.kaType = kaType;
-
- parse(1, 0);
- }
- }
-
- /**
- *
- */
- public static class AllocateSignature extends Response {
- private byte sigType;
-
- public AllocateSignature(ResponseAPDU response, String description, long time, byte sigType) {
- super(response, description, time);
- this.sigType = sigType;
-
- parse(1, 0);
- }
- }
-
- /**
- *
- */
- public static class Allocate extends Response {
- private byte keyPair;
- private short keyLength;
- private byte keyClass;
-
- public Allocate(ResponseAPDU response, String description, long time, byte keyPair, short keyLength, byte keyClass) {
- super(response, description, time);
- this.keyPair = keyPair;
- this.keyLength = keyLength;
- this.keyClass = keyClass;
-
- int pairs = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
- parse(pairs, 0);
- }
- }
-
- /**
- *
- */
- public static class Clear extends Response {
- private byte keyPair;
-
- public Clear(ResponseAPDU response, String description, long time, byte keyPair) {
- super(response, description, time);
- this.keyPair = keyPair;
-
- int pairs = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
- parse(pairs, 0);
- }
- }
-
- /**
- *
- */
- public static class Set extends Response {
- private byte keyPair;
- private byte curve;
- private short parameters;
-
- public Set(ResponseAPDU response, String description, long time, byte keyPair, byte curve, short parameters) {
- super(response, description, time);
- this.keyPair = keyPair;
- this.curve = curve;
- this.parameters = parameters;
-
- int pairs = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
-
- parse(pairs, 0);
- }
- }
-
- /**
- *
- */
- public static class Transform extends Response {
- private byte keyPair;
- private byte key;
- private short params;
- private short transformation;
-
- public Transform(ResponseAPDU response, String description, long time, byte keyPair, byte key, short params, short transformation) {
- super(response, description, time);
- this.keyPair = keyPair;
- this.key = key;
- this.params = params;
- this.transformation = transformation;
-
- int pairs = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) pairs++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) pairs++;
-
- parse(pairs, 0);
- }
- }
-
- /**
- *
- */
- public static class Generate extends Response {
- private byte keyPair;
-
- public Generate(ResponseAPDU response, String description, long time, byte keyPair) {
- super(response, description, time);
- this.keyPair = keyPair;
-
- int generated = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) generated++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) generated++;
- parse(generated, 0);
- }
- }
-
- /**
- *
- */
- public static class Export extends Response {
- private byte keyPair;
- private byte key;
- private short parameters;
-
- public Export(ResponseAPDU response, String description, long time, byte keyPair, byte key, short parameters) {
- super(response, description, time);
- this.keyPair = keyPair;
- this.key = key;
- this.parameters = parameters;
-
- int exported = 0;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) exported++;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) exported++;
- int keys = 0;
- if ((key & EC_Consts.KEY_PUBLIC) != 0) keys++;
- if ((key & EC_Consts.KEY_PRIVATE) != 0) keys++;
- int paramCount = 0;
- short mask = EC_Consts.PARAMETER_FP;
- while (mask <= EC_Consts.PARAMETER_K) {
- if ((mask & parameters) != 0) {
- paramCount++;
- }
- mask = (short) (mask << 1);
- }
- int other = 0;
- if ((key & EC_Consts.KEY_PUBLIC) != 0 && (parameters & EC_Consts.PARAMETER_W) != 0) other++;
- if ((key & EC_Consts.KEY_PRIVATE) != 0 && (parameters & EC_Consts.PARAMETER_S) != 0) other++;
-
- parse(exported, exported * keys * paramCount + exported * other);
- }
-
- private int getIndex(byte keyPair, short param) {
- byte pair = ECTesterApplet.KEYPAIR_LOCAL;
- int index = 0;
- while (pair <= ECTesterApplet.KEYPAIR_REMOTE) {
- short mask = EC_Consts.PARAMETER_FP;
- while (mask <= EC_Consts.PARAMETER_S) {
- if (pair == keyPair && param == mask) {
- return index;
- }
- if ((parameters & mask) != 0 && (pair & this.keyPair) != 0) {
- if (mask == EC_Consts.PARAMETER_W) {
- if ((key & EC_Consts.KEY_PUBLIC) != 0)
- index++;
- } else if (mask == EC_Consts.PARAMETER_S) {
- if ((key & EC_Consts.KEY_PRIVATE) != 0)
- index++;
- } else {
- index++;
- }
- }
- mask = (short) (mask << 1);
- }
-
- pair = (byte) (pair << 1);
- }
- return -1;
- }
-
- public boolean hasParameters(byte keyPair, short params) {
- if ((keyPair & this.keyPair) == 0 || (params ^ parameters) != 0) {
- return false;
- }
- short param = EC_Consts.PARAMETER_FP;
- while (param <= EC_Consts.PARAMETER_S) {
- short masked = (short) (param & params);
- if (masked != 0 && !hasParameter(keyPair, masked)) {
- return false;
- }
- param = (short) (param << 1);
- }
- return true;
- }
-
- public boolean hasParameter(byte keyPair, short param) {
- if ((keyPair & this.keyPair) == 0 || (parameters & param) == 0) {
- return false;
- }
- int index = getIndex(keyPair, param);
- return index != -1 && hasParam(index);
- }
-
- public byte[] getParameter(byte keyPair, short param) {
- return getParam(getIndex(keyPair, param));
- }
- }
-
- /**
- *
- */
- public static class ECDH extends Response {
- private byte pubkey;
- private byte privkey;
- private byte export;
- private short transformation;
- private byte type;
-
- public ECDH(ResponseAPDU response, String description, long time, byte pubkey, byte privkey, byte export, short transformation, byte type) {
- super(response, description, time);
- this.pubkey = pubkey;
- this.privkey = privkey;
- this.export = export;
- this.transformation = transformation;
- this.type = type;
-
- parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0);
- }
-
- public short getTransformation() {
- return transformation;
- }
-
- public byte getType() {
- return type;
- }
-
- public boolean hasSecret() {
- return hasParam(0);
- }
-
- public byte[] getSecret() {
- return getParam(0);
- }
-
- public int secretLength() {
- return getParamLength(0);
- }
- }
-
- /**
- *
- */
- public static class ECDSA extends Response {
- private byte keyPair;
- private byte sigType;
- private byte export;
- private byte[] raw;
-
- public ECDSA(ResponseAPDU response, String description, long time, byte keyPair, byte sigType, byte export, byte[] raw) {
- super(response, description, time);
- this.keyPair = keyPair;
- this.sigType = sigType;
- this.export = export;
- this.raw = raw;
-
- parse(1, (export == ECTesterApplet.EXPORT_TRUE) ? 1 : 0);
- }
-
- public boolean hasSignature() {
- return hasParam(0);
- }
-
- public byte[] getSignature() {
- return getParam(0);
- }
- }
-
- /**
- *
- */
- public static class Cleanup extends Response {
-
- public Cleanup(ResponseAPDU response, String description, long time) {
- super(response, description, time);
-
- parse(1, 0);
- }
- }
-
- /**
- *
- */
- public static class GetInfo extends Response {
- private short base;
- private short jcVersion;
- private short cleanupSupport;
- private short apduBufferLength;
- private short ramArrayLength;
- private short ramArray2Length;
- private short apduArrayLength;
-
- public GetInfo(ResponseAPDU response, String description, long time) {
- super(response, description, time);
-
- parse(1, 1);
- int offset = 2 + 2 + getParamLength(0);
- byte[] data = getData();
- base = ByteUtil.getShort(data, offset);
- offset += 2;
- jcVersion = ByteUtil.getShort(data, offset);
- offset += 2;
- cleanupSupport = ByteUtil.getShort(data, offset);
- offset += 2;
- apduBufferLength = ByteUtil.getShort(data, offset);
- offset += 2;
- ramArrayLength = ByteUtil.getShort(data, offset);
- offset += 2;
- ramArray2Length = ByteUtil.getShort(data, offset);
- offset += 2;
- apduArrayLength = ByteUtil.getShort(data, offset);
- }
-
- public String getVersion() {
- return new String(getParam(0));
- }
-
- public short getBase() {
- return base;
- }
-
- public float getJavaCardVersion() {
- byte major = (byte) (jcVersion >> 8);
- byte minor = (byte) (jcVersion & 0xff);
- int minorSize;
- if (minor == 0) {
- minorSize = 1;
- } else {
- minorSize = (int) Math.ceil(Math.log10(minor));
- }
- return (major + ((float) (minor) / (minorSize * 10)));
- }
-
- public boolean getCleanupSupport() {
- return cleanupSupport == 1;
- }
-
- public short getApduBufferLength() {
- return apduBufferLength;
- }
-
- public short getRamArrayLength() {
- return ramArrayLength;
- }
-
- public short getRamArray2Length() {
- return ramArray2Length;
- }
-
- public short getApduArrayLength() {
- return apduArrayLength;
- }
- }
-
- /**
- *
- */
- public static class SetDryRunMode extends Response {
-
- public SetDryRunMode(ResponseAPDU response, String description, long time) {
- super(response, description, time);
-
- parse(1, 0);
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java b/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
deleted file mode 100644
index d1eb2b1..0000000
--- a/src/cz/crcs/ectester/reader/test/CardCofactorSuite.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardCofactorSuite extends CardTestSuite {
- public CardCofactorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "cofactor", new String[]{"preset", "random"}, "The cofactor test suite tests whether the card correctly rejects points on the curve",
- "but not in the subgroup generated by the generator(so of small order, dividing the cofactor) during ECDH.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "cofactor");
- Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
- Test generate = setupKeypairs(curve, ExpectedValue.SUCCESS, ECTesterApplet.KEYPAIR_LOCAL);
-
- Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
-
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
- Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with cofactor pubkey.", setPub, ecdh);
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
- Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on non-generator subgroup.", "Card incorrectly accepted point on non-generator subgroup.");
- ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " cofactor key test.", objectEcdh, rawEcdh));
- }
- Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with public points on non-generator subgroup.", ecdhTests.toArray(new Test[0]));
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, ecdh, cleanup));
- } else {
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Cofactor test of " + curve.getId() + ".", prepare, ecdh));
- }
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java b/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
deleted file mode 100644
index babe732..0000000
--- a/src/cz/crcs/ectester/reader/test/CardCompositeSuite.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardCompositeSuite extends CardTestSuite {
-
- public CardCompositeSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "composite", new String[]{"preset", "random"}, "The composite suite runs ECDH over curves with composite order.",
- "Various types of compositeness is tested: smooth numbers, Carmichael pseudo-prime, prime square, product of two large primes.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_Key> keys = EC_Store.getInstance().getObjects(EC_Key.class, "composite");
- Map<EC_Curve, List<EC_Key>> mappedKeys = EC_Store.mapKeyToCurve(keys.values());
- for (Map.Entry<EC_Curve, List<EC_Key>> curveKeys : mappedKeys.entrySet()) {
- EC_Curve curve = curveKeys.getKey();
- List<Test> tests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
- tests.add(allocate);
- tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY));
-
- String name;
- if (cfg.testOptions.contains("preset")) {
- name = "preset semi-random private key";
- } else {
- name = "generated private key";
- }
- tests.add(setupKeypairs(curve, ExpectedValue.ANY, ECTesterApplet.KEYPAIR_LOCAL));
- for (EC_Key key : curveKeys.getValue()) {
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, key.flatten());
- Test ecdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a composite order curve.", "Card incorrectly does ECDH over a composite order curve, leaks bits of private key.");
- tests.add(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ", with " + name + ", " + key.getDesc(), ecdh));
- }
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Composite test of " + curve.getId() + ".", tests.toArray(new Test[0])));
- }
-
-
- Map<String, EC_Curve> results = EC_Store.getInstance().getObjects(EC_Curve.class, "composite");
- Map<String, List<EC_Curve>> groups = EC_Store.mapToPrefix(results.values());
- /* Test the whole curves with both keypairs generated on card(no small-order public points provided).
- */
- List<EC_Curve> wholeCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("whole")).findFirst().get().getValue();
- testGroup(wholeCurves, "Composite generator order", ExpectedValue.FAILURE, "Card rejected to do ECDH with composite order generator.", "Card did not reject to do ECDH with composite order generator.");
-
- /* Also test having a G of small order, so small R.
- */
- List<EC_Curve> smallRCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("small")).findFirst().get().getValue();
- testGroup(smallRCurves, "Small generator order", ExpectedValue.FAILURE, "Card correctly rejected to do ECDH over a small order generator.", "Card incorrectly does ECDH over a small order generator.");
-
- /* Test increasingly larger prime R, to determine where/if card behavior changes.
- */
- List<EC_Curve> varyingCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("varying")).findFirst().get().getValue();
- testGroup(varyingCurves, null, ExpectedValue.ANY, "", "");
-
- /* Also test having a G of large but composite order, R = p * q,
- */
- List<EC_Curve> pqCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pq")).findFirst().get().getValue();
- testGroup(pqCurves, null, ExpectedValue.ANY, "", "");
-
- /* Also test having G or large order being a Carmichael pseudoprime, R = p * q * r,
- */
- List<EC_Curve> ppCurves = groups.entrySet().stream().filter((e) -> e.getKey().equals("pp")).findFirst().get().getValue();
- testGroup(ppCurves, "Generator order = Carmichael pseudo-prime", ExpectedValue.ANY, "", "");
-
- /* Also test rg0 curves.
- */
- List<EC_Curve> rg0Curves = groups.entrySet().stream().filter((e) -> e.getKey().equals("rg0")).findFirst().get().getValue();
- testGroup(rg0Curves, null, ExpectedValue.ANY, "", "");
- }
-
- private void testGroup(List<EC_Curve> curves, String testName, ExpectedValue dhValue, String ok, String nok) throws Exception {
- for (EC_Curve curve : curves) {
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.ANY);
- Test generate = setupKeypairs(curve, ExpectedValue.ANY, ECTesterApplet.KEYPAIR_BOTH);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), dhValue, ok, nok);
- Test ecdsa = CommandTest.expect(new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), dhValue, ok, nok);
-
- String description;
- if (testName == null) {
- description = curve.getDesc() + " test of " + curve.getId() + ".";
- } else {
- description = testName + " test of " + curve.getId() + ".";
- }
-
- Test perform = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ecdh, ecdsa);
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, perform, cleanup));
- } else {
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, description, allocate, set, generate, perform));
- }
- }
-
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java b/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
deleted file mode 100644
index 9eed814..0000000
--- a/src/cz/crcs/ectester/reader/test/CardCompressionSuite.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.KeyPair;
-
-import java.security.spec.ECPoint;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardCompressionSuite extends CardTestSuite {
- public CardCompressionSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "compression", null, "The compression test suite tests cards support for compressed points in ECDH (as per ANSI X9.62).",
- "It also tests for handling of bogus input in ECDH by using the point at infinity and a hybrid point with the y coordinate corrupted.",
- "It also tests handling of compressed point in ECDH, where the x coordinate is invalid and therefore",
- "a quadratic non-residue will be computed and (square root-ed) during decompression.");
- }
-
- @Override
- protected void runTests() throws Exception {
- //iterate over default curve sizes
- // for Fp
- // - allocate, set custom curve, generate keypairs, -> export generated.
- // - test ecdh with local and remote simply(no compression)
- // - test local privkey, remote pubkey (compressed)
- // - test local privkey, remote pubkey (hybrid)
- // - test local privkey, remote pubkey (hybrid with wrong y)
- // - test local privkey, remote pubkey (point at infinity)
- if (cfg.primeField) {
- runCompression(KeyPair.ALG_EC_FP);
- }
- // for F2m
- // - allocate, set custom curve, generate keypairs, -> export generated.
- // - test ecdh with local and remote simply(no compression)
- // - test local privkey, remote pubkey (compressed)
- // - test local privkey, remote pubkey (hybrid)
- // - test local privkey, remote pubkey (hybrid with wrong y)
- // - test local privkey, remote pubkey (point at infinity)
- if (cfg.binaryField) {
- runCompression(KeyPair.ALG_EC_F2M);
- }
-
- // Now, do ECDH over SECG curves and give the implementation a compressed key that is not a quadratic residue in
- // decompression.
- runNonResidue();
- }
-
- private void runCompression(byte field) throws Exception {
- short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES;
- short domain = field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
-
- for (short keyLength : keySizes) {
- String spec = keyLength + "b " + CardUtil.getKeyTypeString(field);
- byte curveId = EC_Consts.getCurve(keyLength, field);
-
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), Result.ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for compression test on " + spec + ".", allocateFirst));
- continue;
- }
-
- List<Test> compressionTests = new LinkedList<>();
- compressionTests.add(allocateFirst);
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curveId, domain, null), Result.ExpectedValue.SUCCESS));
- Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), Result.ExpectedValue.SUCCESS));
- compressionTests.add(setCustom);
- compressionTests.add(genCustom);
-
- Response.Export key = new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W).send();
- byte[] pubkey = key.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PUBLIC);
- EC_Curve secgCurve = EC_Store.getInstance().getObject(EC_Curve.class, "secg", CardUtil.getCurveName(curveId));
- ECPoint pub;
- try {
- pub = ECUtil.fromX962(pubkey, secgCurve.toCurve());
- } catch (IllegalArgumentException iae) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "", compressionTests.toArray(new Test[0])));
- continue;
- }
-
- List<Test> kaTests = new LinkedList<>();
- for (byte kaType : EC_Consts.KA_TYPES) {
- List<Test> thisTests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), Result.ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), Result.ExpectedValue.SUCCESS));
-
- thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement setup and basic test.", allocate, ka));
- if (ka.ok()) {
- // tests of the good stuff
- Test kaCompressed = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), Result.ExpectedValue.SUCCESS);
- Test kaHybrid = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS_HYBRID, kaType), Result.ExpectedValue.SUCCESS);
- thisTests.add(CompoundTest.any(Result.ExpectedValue.SUCCESS, "Tests of compressed and hybrid form.", kaCompressed, kaHybrid));
-
- // tests the bad stuff here
- byte[] pubHybrid = ECUtil.toX962Hybrid(pub, keyLength);
- pubHybrid[pubHybrid.length - 1] ^= 1;
- byte[] pubHybridEncoded = ByteUtil.prependLength(pubHybrid);
- Test kaBadHybrid = CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubHybridEncoded), Result.ExpectedValue.FAILURE);
-
- byte[] pubInfinityEncoded = {0x01, 0x00};
- Test kaBadInfinity = CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType, pubInfinityEncoded), Result.ExpectedValue.FAILURE);
- thisTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests of corrupted hybrid form and infinity.", kaBadHybrid, kaBadInfinity));
- }
- kaTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyAgreement tests of " + CardUtil.getKATypeString(kaType) + ".", thisTests.toArray(new Test[0])));
- }
- }
- compressionTests.addAll(kaTests);
- if (cfg.cleanup) {
- compressionTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY));
- }
-
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Compression test of " + spec + ".", compressionTests.toArray(new Test[0])));
- }
- }
-
- private void runNonResidue() {
- Map<String, EC_Key.Public> otherKeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "misc");
- List<EC_Key.Public> compressionKeys = EC_Store.mapToPrefix(otherKeys.values()).get("compression");
-
- for (EC_Key.Public key : compressionKeys) {
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, key.getCurve());
- List<Test> tests = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for non-residue test on " + curve.getBits() + "b " + curve.getId() + ".", allocate));
- continue;
- }
- tests.add(allocate);
- tests.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS));
- tests.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS));
- byte[] pointData = ECUtil.toX962Compressed(key.getParam(EC_Consts.PARAMETER_W));
- byte[] pointDataEncoded = ByteUtil.prependLength(pointData);
- tests.add(CommandTest.expect(new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pointDataEncoded), Result.ExpectedValue.FAILURE));
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Non-residue test of " + curve.getId() + ".", tests.toArray(new Test[0])));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java b/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
deleted file mode 100644
index 8814c37..0000000
--- a/src/cz/crcs/ectester/reader/test/CardDefaultSuite.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import javacard.security.KeyPair;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Random;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-import static cz.crcs.ectester.common.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardDefaultSuite extends CardTestSuite {
-
- public CardDefaultSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "default", null, "The default test suite tests basic support and performance of ECDH and ECDSA.");
- }
-
- @Override
- protected void runTests() throws Exception {
- if (cfg.primeField) {
- runDefault(KeyPair.ALG_EC_FP);
- }
- if (cfg.binaryField) {
- runDefault(KeyPair.ALG_EC_F2M);
- }
- }
-
- private void runDefault(byte field) throws Exception {
- short[] keySizes = field == KeyPair.ALG_EC_FP ? EC_Consts.FP_SIZES : EC_Consts.F2M_SIZES;
- short domain = field == KeyPair.ALG_EC_FP ? EC_Consts.PARAMETERS_DOMAIN_FP : EC_Consts.PARAMETERS_DOMAIN_F2M;
- for (short keyLength : keySizes) {
-
- List<Test> supportTests = new LinkedList<>();
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + keyLength + "b " + CardUtil.getKeyTypeString(field) + ".", allocateFirst));
- continue;
- }
- supportTests.add(allocateFirst);
-
- Test genDefault = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- Test allocateSecond = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, field), ExpectedValue.SUCCESS));
- Test setCustom = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.getCurve(keyLength, field), domain, null), ExpectedValue.SUCCESS));
- Test genCustom = runTest(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- supportTests.add(genDefault);
- supportTests.add(allocateSecond);
- supportTests.add(setCustom);
- supportTests.add(genCustom);
-
- List<Test> kaTests = new LinkedList<>();
- for (byte kaType : EC_Consts.KA_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Command ecdh = new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType);
- Test ka = runTest(CommandTest.expect(ecdh, ExpectedValue.SUCCESS));
- Test kaCompressed = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_COMPRESS, kaType), ExpectedValue.SUCCESS));
-
- String kaDesc = "Test of the " + CardUtil.getKATypeString(kaType) + " KeyAgreement.";
- Function<Test[], Result> kaCallback = (tests) -> {
- if (tests[1].ok() || tests[2].ok()) {
- return new Result(Value.SUCCESS, "Some ECDH is supported.");
- } else {
- return new Result(Value.FAILURE, "ECDH failed.");
- }
- };
-
- Test compound;
- if (ka.ok()) {
- Test perfTest = runTest(PerformanceTest.repeat(this.card, ecdh, 10));
- compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed, perfTest));
- } else {
- compound = runTest(CompoundTest.function(kaCallback, kaDesc, allocate, ka, kaCompressed));
- }
-
- kaTests.add(compound);
- } else {
- runTest(allocate);
- kaTests.add(allocate);
- }
- }
- Test kaTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "KeyAgreement tests.", kaTests.toArray(new Test[0])));
- supportTests.add(kaTest);
-
- List<Test> signTests = new LinkedList<>();
- for (byte sigType : EC_Consts.SIG_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateSignature(this.card, sigType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Command ecdsa = new Command.ECDSA(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_FALSE, null);
- Test expect = runTest(CommandTest.expect(ecdsa, ExpectedValue.SUCCESS));
-
- String signDesc = "Test of the " + CardUtil.getSigTypeString(sigType) + " signature.";
-
- Random rand = new Random();
- byte[] sigData = new byte[64];
- rand.nextBytes(sigData);
-
- Test compound;
- if (expect.ok()) {
- Command ecdsaSign = new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, ECTesterApplet.EXPORT_TRUE, sigData);
- PerformanceTest signTest = runTest(PerformanceTest.repeat(this.card, "Sign", ecdsaSign, 10));
- byte[] signature = signTest.getResponses()[0].getParam(0);
- Command ecdsaVerify = new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_LOCAL, sigType, sigData, signature);
- PerformanceTest verifyTest = runTest(PerformanceTest.repeat(this.card, "Verify", ecdsaVerify, 10));
- compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect, signTest, verifyTest));
- } else {
- compound = runTest(CompoundTest.all(ExpectedValue.SUCCESS, signDesc, allocate, expect));
- }
- signTests.add(compound);
- } else {
- signTests.add(allocate);
- }
- }
- Test signTest = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Signature tests.", signTests.toArray(new Test[0])));
- supportTests.add(signTest);
- ExpectedValue[] testExpects = {ExpectedValue.SUCCESS, ExpectedValue.ANY, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS, ExpectedValue.SUCCESS};
- List<ExpectedValue> expects = Stream.of(testExpects).collect(Collectors.toList());
- if (cfg.cleanup) {
- supportTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY));
- expects.add(ExpectedValue.ANY);
- }
-
- doTest(CompoundTest.mask(expects.toArray(new ExpectedValue[0]), "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(field) + " support.", supportTests.toArray(new Test[0])));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java b/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
deleted file mode 100644
index f2e73b6..0000000
--- a/src/cz/crcs/ectester/reader/test/CardDegenerateSuite.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardDegenerateSuite extends CardTestSuite {
-
- public CardDegenerateSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "degenerate", null, "The degenerate suite tests whether the card rejects points outside of the curve during ECDH.",
- "The tested points lie on a part of the plane for which some Edwards, Hessian and Huff form addition formulas degenerate into exponentiation in the base finite field.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "degenerate");
- Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
-
- Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
-
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
- Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with degenerate pubkey.", setPub, ecdh);
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
- Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on degenerate curve.", "Card incorrectly accepted point on degenerate curve.");
- ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " degenerate key test.", objectEcdh, rawEcdh));
- //TODO: actually get the result of ECDH here, as well as export privkey and compare to exponentiation in Fp^*.
- }
- Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with degenerate public points.", ecdhTests.toArray(new Test[0]));
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh, cleanup));
- } else {
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Degenerate curve test of " + curve.getId() + ".", prepare, ecdh));
- }
-
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java b/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
deleted file mode 100644
index 9257b3d..0000000
--- a/src/cz/crcs/ectester/reader/test/CardEdgeCasesSuite.java
+++ /dev/null
@@ -1,336 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_KAResult;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.ec.EC_Params;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.test.TestCallback;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.CryptoException;
-import javacard.security.KeyPair;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardEdgeCasesSuite extends CardTestSuite {
- public CardEdgeCasesSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "edge-cases", null, "The edge-cases test suite tests various inputs to ECDH which may cause an implementation to achieve a certain edge-case state during it.",
- "Some of the data is from the google/Wycheproof project. Tests include CVE-2017-10176 and CVE-2017-8932.",
- "Also tests values of the private key and public key that would trigger the OpenSSL modular multiplication bug on the P-256 curve.",
- "Various edge private key values are also tested.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "wycheproof");
- Map<String, List<EC_KAResult>> groups = EC_Store.mapToPrefix(results.values());
- for (Map.Entry<String, List<EC_KAResult>> e : groups.entrySet()) {
- String description = null;
- switch (e.getKey()) {
- case "addsub":
- description = "Tests for addition-subtraction chains.";
- break;
- case "cve_2017_10176":
- description = "Tests for CVE-2017-10176.";
- break;
- case "cve_2017_8932":
- description = "Tests for CVE-2017-8932.";
- break;
- }
-
- List<Test> groupTests = new LinkedList<>();
- Map<EC_Curve, List<EC_KAResult>> curveList = EC_Store.mapResultToCurve(e.getValue());
- for (Map.Entry<EC_Curve, List<EC_KAResult>> c : curveList.entrySet()) {
- EC_Curve curve = c.getKey();
-
- List<Test> curveTests = new LinkedList<>();
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test prepareCurve = CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Prepare curve", allocate, set);
-
- List<EC_KAResult> values = c.getValue();
- for (EC_KAResult value : values) {
- String id = value.getId();
- String privkeyId = value.getOneKey();
- String pubkeyId = value.getOtherKey();
-
- EC_Key.Private privkey = EC_Store.getInstance().getObject(EC_Key.Private.class, privkeyId);
- EC_Key.Public pubkey = EC_Store.getInstance().getObject(EC_Key.Public.class, pubkeyId);
-
- Test setPrivkey = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, privkey.getParams(), privkey.flatten()), Result.ExpectedValue.SUCCESS);
- Test setPubkey = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pubkey.getParams(), pubkey.flatten()), Result.ExpectedValue.SUCCESS);
- Test ecdhPreTest = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.SUCCESS);
- Test ecdh = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, value.getJavaCardKA()), new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- Response.ECDH dh = (Response.ECDH) testable.getResponse();
- if (dh.getSW(0) == CryptoException.NO_SUCH_ALGORITHM) {
- return new Result(Result.Value.SUCCESS, "ECDH algorithm unsupported.");
- }
- if (!dh.successful())
- return new Result(Result.Value.FAILURE, "ECDH was unsuccessful.");
- if (!dh.hasSecret())
- return new Result(Result.Value.FAILURE, "ECDH response did not contain the derived secret.");
- if (!ByteUtil.compareBytes(dh.getSecret(), 0, value.getData(0), 0, dh.secretLength())) {
- int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, value.getData(0), 0, dh.secretLength());
- System.err.println(ByteUtil.bytesToHex(dh.getSecret()));
- System.err.println(ByteUtil.bytesToHex(value.getData(0)));
- return new Result(Result.Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + firstDiff + ".");
- }
- return new Result(Result.Value.SUCCESS);
- }
- });
-
- Test prepare = CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Prepare", setPrivkey, setPubkey);
- Test ka = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do", ecdhPreTest, ecdh);
-
- Test one = CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Test " + id + ".", prepare, ka);
- curveTests.add(one);
- }
-
- if (cfg.cleanup) {
- curveTests.add(CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY));
- }
-
- Test curveTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests", curveTests.toArray(new Test[0]));
- groupTests.add(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Tests on " + curve.getId() + ".", prepareCurve, curveTest));
- }
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, description, groupTests.toArray(new Test[0])));
- }
-
- {
- EC_KAResult openssl_bug = EC_Store.getInstance().getObject(EC_KAResult.class, "misc", "openssl-bug");
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, openssl_bug.getCurve());
- EC_Key.Private skey = EC_Store.getInstance().getObject(EC_Key.Private.class, openssl_bug.getOtherKey());
- EC_Key.Public pkey = EC_Store.getInstance().getObject(EC_Key.Public.class, openssl_bug.getOneKey());
- Test key = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test setPrivate = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, skey.flatten(EC_Consts.PARAMETER_S)), Result.ExpectedValue.SUCCESS);
- Test setPublic = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, pkey.flatten(EC_Consts.PARAMETER_W)), Result.ExpectedValue.SUCCESS);
- Test ecdh = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, openssl_bug.getJavaCardKA()), new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- Response.ECDH dh = (Response.ECDH) testable.getResponse();
- if (!dh.successful())
- return new Result(Result.Value.FAILURE, "ECDH was unsuccessful.");
- if (!dh.hasSecret())
- return new Result(Result.Value.FAILURE, "ECDH response did not contain the derived secret.");
- if (ByteUtil.compareBytes(dh.getSecret(), 0, openssl_bug.getData(0), 0, dh.secretLength())) {
- return new Result(Result.Value.FAILURE, "OpenSSL bug is present, derived secret matches example.");
- }
- return new Result(Result.Value.SUCCESS);
- }
- });
-
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Test OpenSSL modular reduction bug.", key, set, setPrivate, setPublic, ecdh));
- }
-
- Map<String, EC_Curve> curveMap = EC_Store.getInstance().getObjects(EC_Curve.class, "secg");
- List<EC_Curve> curves = curveMap.entrySet().stream().filter((e) -> e.getKey().endsWith("r1") && e.getValue().getField() == KeyPair.ALG_EC_FP).map(Map.Entry::getValue).collect(Collectors.toList());
- curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor128p2"));
- curves.add(EC_Store.getInstance().getObject(EC_Curve.class, "cofactor/cofactor160p4"));
- Random rand = new Random();
- for (EC_Curve curve : curves) {
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + curve.getId() + ".", key));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
- CommandTest export = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), Result.ExpectedValue.SUCCESS);
- Test setup = runTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate, export));
-
- /*
- byte[] pParam = curve.getParam(EC_Consts.PARAMETER_FP)[0];
- BigInteger p = new BigInteger(1, pParam);
- byte[] wParam = ((Response.Export) export.getResponse()).getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
- byte[] xValue = new byte[(wParam.length - 1) / 2];
- byte[] yValue = new byte[(wParam.length - 1) / 2];
- System.arraycopy(wParam, 1, xValue, 0, xValue.length);
- System.arraycopy(wParam, (wParam.length / 2) + 1, yValue, 0, yValue.length);
- BigInteger y = new BigInteger(1, yValue);
- BigInteger negY = p.subtract(y);
- byte[] newY = ECUtil.toByteArray(negY, curve.getBits());
-
- EC_Params negYParams = new EC_Params(EC_Consts.PARAMETER_W, new byte[][]{xValue, newY});
- Test negYTest = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, negYParams.getParams(), negYParams.flatten()), "ECDH with pubkey negated.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
- */
-
- Test zeroS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ZERO), "ECDH with S = 0.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
- Test oneS = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, EC_Consts.TRANSFORMATION_ONE), "ECDH with S = 1.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
-
- byte[] rParam = curve.getParam(EC_Consts.PARAMETER_R)[0];
- BigInteger R = new BigInteger(1, rParam);
- BigInteger smaller = new BigInteger(curve.getBits(), rand).mod(R);
- BigInteger diff = R.divide(BigInteger.valueOf(10));
- BigInteger randDiff = new BigInteger(diff.bitLength(), rand).mod(diff);
- BigInteger larger = R.add(randDiff);
-
- BigInteger full = BigInteger.valueOf(1).shiftLeft(R.bitLength() - 1).subtract(BigInteger.ONE);
-
- BigInteger alternate = full;
- for (int i = 0; i < R.bitLength(); i += 2) {
- alternate = alternate.clearBit(i);
- }
-
- BigInteger alternateOther = alternate.xor(full);
-
- EC_Params alternateParams = makeParams(alternate);
- Test alternateS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateParams.getParams(), alternateParams.flatten()), "ECDH with S = 101010101...01010.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
-
- EC_Params alternateOtherParams = makeParams(alternateOther);
- Test alternateOtherS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, alternateOtherParams.getParams(), alternateOtherParams.flatten()), "ECDH with S = 010101010...10101.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
-
- EC_Params fullParams = makeParams(full);
- Test fullS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, fullParams.getParams(), fullParams.flatten()), "ECDH with S = 111111111...11111 (but < r).", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
-
- EC_Params smallerParams = makeParams(smaller);
- Test smallerS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, smallerParams.getParams(), smallerParams.flatten()), "ECDH with S < r.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
-
- EC_Params exactParams = makeParams(R);
- Test exactS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, exactParams.getParams(), exactParams.flatten()), "ECDH with S = r.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
-
- EC_Params largerParams = makeParams(larger);
- Test largerS = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, largerParams.getParams(), largerParams.flatten()), "ECDH with S > r.", Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
-
- BigInteger rm1 = R.subtract(BigInteger.ONE);
- BigInteger rp1 = R.add(BigInteger.ONE);
-
- EC_Params rm1Params = makeParams(rm1);
- Test rm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, rm1Params.getParams(), rm1Params.flatten()), "ECDH with S = r - 1.", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
-
- EC_Params rp1Params = makeParams(rp1);
- Test rp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, rp1Params.getParams(), rp1Params.flatten()), "ECDH with S = r + 1.", Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
-
- byte[] k = curve.getParam(EC_Consts.PARAMETER_K)[0];
- BigInteger K = new BigInteger(1, k);
- BigInteger kr = K.multiply(R);
- BigInteger krm1 = kr.subtract(BigInteger.ONE);
- BigInteger krp1 = kr.add(BigInteger.ONE);
-
- Result.ExpectedValue kExpected = K.equals(BigInteger.ONE) ? Result.ExpectedValue.SUCCESS : Result.ExpectedValue.FAILURE;
-
- EC_Params krParams = makeParams(kr);
- Test krS /*ONE!*/ = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krParams.getParams(), krParams.flatten()), "ECDH with S = k * r.", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
-
- EC_Params krm1Params = makeParams(krm1);
- Test krm1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krm1Params.getParams(), krm1Params.flatten()), "ECDH with S = (k * r) - 1.", kExpected, kExpected);
-
- EC_Params krp1Params = makeParams(krp1);
- Test krp1S = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, krp1Params.getParams(), krp1Params.flatten()), "ECDH with S = (k * r) + 1.", Result.ExpectedValue.ANY, Result.ExpectedValue.ANY);
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S, cleanup));
- } else {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Tests with edge-case private key values over " + curve.getId() + ".", setup, zeroS, oneS, alternateS, alternateOtherS, fullS, smallerS, exactS, largerS, rm1S, rp1S, krS, krm1S, krp1S));
- }
- }
-
- EC_Curve secp160r1 = EC_Store.getInstance().getObject(EC_Curve.class, "secg/secp160r1");
- byte[] pData = secp160r1.getParam(EC_Consts.PARAMETER_FP)[0];
- BigInteger p = new BigInteger(1, pData);
- byte[] rData = secp160r1.getParam(EC_Consts.PARAMETER_R)[0];
- BigInteger r = new BigInteger(1, rData);
-
- BigInteger range = r.subtract(p);
- BigInteger deviation = range.divide(BigInteger.valueOf(5));
- BigDecimal dev = new BigDecimal(deviation);
- BigDecimal smallDev = new BigDecimal(10000);
- int n = 10;
- BigInteger[] rs = new BigInteger[n];
- BigInteger[] ps = new BigInteger[n];
- BigInteger[] zeros = new BigInteger[n];
- for (int i = 0; i < n; ++i) {
- double sample;
- do {
- sample = rand.nextGaussian();
- } while (sample >= -1 && sample <= 1);
- BigInteger where = dev.multiply(new BigDecimal(sample)).toBigInteger();
- rs[i] = where.add(r);
- ps[i] = where.add(p);
- zeros[i] = smallDev.multiply(new BigDecimal(sample)).toBigInteger().abs();
- }
- Arrays.sort(rs);
- Arrays.sort(ps);
- Arrays.sort(zeros);
-
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, secp160r1.getBits(), KeyPair.ALG_EC_FP), Result.ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.FAILURE, "No support for " + secp160r1.getBits() + "b secp160r1.", key));
- return;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, secp160r1.getParams(), secp160r1.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
- Test setup = CompoundTest.all(Result.ExpectedValue.SUCCESS, "KeyPair setup.", key, set, generate);
-
- Test[] zeroTests = new Test[n];
- int i = 0;
- for (BigInteger nearZero : zeros) {
- EC_Params params = makeParams(nearZero);
- zeroTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearZero.toString(16), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
- }
- Test zeroTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near zero.", zeroTests);
-
- Test[] pTests = new Test[n];
- i = 0;
- for (BigInteger nearP : ps) {
- EC_Params params = makeParams(nearP);
- pTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearP.toString(16) + (nearP.compareTo(p) > 0 ? " (>p)" : " (<=p)"), Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
- }
- Test pTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near p.", pTests);
-
- Test[] rTests = new Test[n];
- i = 0;
- for (BigInteger nearR : rs) {
- EC_Params params = makeParams(nearR);
- if (nearR.compareTo(r) >= 0) {
- rTests[i++] = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (>=r)", Result.ExpectedValue.FAILURE, Result.ExpectedValue.FAILURE);
- } else {
- rTests[i++] = ecdhTestBoth(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, params.getParams(), params.flatten()), nearR.toString(16) + " (<r)", Result.ExpectedValue.SUCCESS, Result.ExpectedValue.SUCCESS);
- }
- }
- Test rTest = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Near r.", rTests);
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "Test private key values near zero, near p and near/larger than the order.", setup, zeroTest, pTest, rTest));
- }
-
- private Test ecdhTestBoth(Command setPriv, String desc, Result.ExpectedValue setExpect, Result.ExpectedValue ecdhExpect) {
- Test set = CommandTest.expect(setPriv, setExpect);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ecdhExpect);
-
- return CompoundTest.all(Result.ExpectedValue.SUCCESS, desc, set, ecdh);
- }
-
- private Test ecdhTest(Command setPriv, String desc, Result.ExpectedValue setExpect, Result.ExpectedValue ecdhExpect) {
- Test set = CommandTest.expect(setPriv, setExpect);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ecdhExpect);
-
- return CompoundTest.any(Result.ExpectedValue.SUCCESS, desc, set, ecdh);
- }
-
- private EC_Params makeParams(BigInteger s) {
- return makeParams(ECUtil.toByteArray(s, s.bitLength()));
- }
-
- private EC_Params makeParams(byte[] s) {
- return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{s});
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java b/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
deleted file mode 100644
index 5df379e..0000000
--- a/src/cz/crcs/ectester/reader/test/CardInvalidSuite.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardInvalidSuite extends CardTestSuite {
-
- public CardInvalidSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "invalid", null, "The invalid curve suite tests whether the card rejects points outside of the curve during ECDH.");
- }
-
- @Override
- protected void runTests() throws Exception {
- /* Set original curves (secg/nist/brainpool). Generate local.
- * Try ECDH with invalid public keys of increasing order.
- */
- Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "invalid");
- Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), ExpectedValue.SUCCESS);
-
- Test prepare = CompoundTest.all(ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
-
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE);
- Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with invalid pubkey.", setPub, ecdh);
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
- Test rawEcdh = CommandTest.expect(ecdhCommand, ExpectedValue.FAILURE, "Card correctly rejected point on invalid curve.", "Card incorrectly accepted point on invalid curve.");
- ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " invalid key test.", objectEcdh, rawEcdh));
- }
- Test ecdh = CompoundTest.all(ExpectedValue.SUCCESS, "Perform ECDH with invalid public points.", ecdhTests.toArray(new Test[0]));
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh, cleanup));
- } else {
- doTest(CompoundTest.greedyAllTry(ExpectedValue.SUCCESS, "Invalid curve test of " + curve.getId() + ".", prepare, ecdh));
- }
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java b/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
deleted file mode 100644
index dd49708..0000000
--- a/src/cz/crcs/ectester/reader/test/CardMiscSuite.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardMiscSuite extends CardTestSuite {
-
- public CardMiscSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "miscellaneous", new String[]{"preset", "random"}, "Some miscellaneous tests, tries ECDH and ECDSA over supersingular curves, anomalous curves,",
- "Barreto-Naehrig curves with small embedding degree and CM discriminant, MNT curves,",
- "some Montgomery curves transformed to short Weierstrass form and Curve25519 transformed to short Weierstrass form.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_Curve> anCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "anomalous");
- Map<String, EC_Curve> ssCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "supersingular");
- Map<String, EC_Curve> bnCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "Barreto-Naehrig");
- Map<String, EC_Curve> mntCurves = EC_Store.getInstance().getObjects(EC_Curve.class, "MNT");
- List<EC_Curve> mCurves = new ArrayList<>();
- mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-221"));
- mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-383"));
- mCurves.add(EC_Store.getInstance().getObject(EC_Curve.class, "other", "M-511"));
- EC_Curve curve25519 = EC_Store.getInstance().getObject(EC_Curve.class, "other", "Curve25519");
-
- testCurves(anCurves.values(), "anomalous", Result.ExpectedValue.FAILURE);
- testCurves(ssCurves.values(), "supersingular", Result.ExpectedValue.FAILURE);
- testCurves(bnCurves.values(), "Barreto-Naehrig", Result.ExpectedValue.SUCCESS);
- testCurves(mntCurves.values(), "MNT", Result.ExpectedValue.SUCCESS);
- testCurves(mCurves, "Montgomery", Result.ExpectedValue.SUCCESS);
- testCurve(curve25519, "Montgomery", Result.ExpectedValue.SUCCESS);
- }
-
- private void testCurve(EC_Curve curve, String catName, Result.ExpectedValue expected) {
- Test allocateFirst = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocateFirst.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst));
- return;
- }
-
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = setupKeypairs(curve, Result.ExpectedValue.ANY, ECTesterApplet.KEYPAIR_BOTH);
- Test ka = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), expected);
- Test sig = CommandTest.expect(new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_FALSE, null), expected);
- Test perform = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH and ECDSA.", ka, sig);
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform, cleanup));
- } else {
- doTest(CompoundTest.greedyAll(Result.ExpectedValue.SUCCESS, "Tests over " + curve.getBits() + "b " + catName + " curve: " + curve.getId() + ".", allocateFirst, set, generate, perform));
- }
- }
-
- private void testCurves(Collection<EC_Curve> curves, String catName, Result.ExpectedValue expected) {
- for (EC_Curve curve : curves) {
- testCurve(curve, catName, expected);
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java b/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
deleted file mode 100644
index 0e4ca8e..0000000
--- a/src/cz/crcs/ectester/reader/test/CardSignatureSuite.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.ec.EC_SigResult;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardSignatureSuite extends CardTestSuite {
- public CardSignatureSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "signature", null, "The signature test suite tests verifying various malformed and well-formed but invalid ECDSA signatures.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_SigResult> results = EC_Store.getInstance().getObjects(EC_SigResult.class, "wrong");
- Map<String, List<EC_SigResult>> groups = EC_Store.mapToPrefix(results.values());
-
- List<EC_SigResult> nok = groups.entrySet().stream().filter((e) -> e.getKey().equals("nok")).findFirst().get().getValue();
-
- byte[] data = "Some stuff that is not the actual data".getBytes();
- for (EC_SigResult sig : nok) {
- ecdsaTest(sig, Result.ExpectedValue.FAILURE, data);
- }
-
- List<EC_SigResult> ok = groups.entrySet().stream().filter((e) -> e.getKey().equals("ok")).findFirst().get().getValue();
- for (EC_SigResult sig : ok) {
- ecdsaTest(sig, Result.ExpectedValue.SUCCESS, null);
- }
- }
-
- private void ecdsaTest(EC_SigResult sig, Result.ExpectedValue expected, byte[] defaultData) {
- EC_Key.Public pubkey = EC_Store.getInstance().getObject(EC_Key.Public.class, sig.getVerifyKey());
-
- byte[] data = sig.getSigData();
- if (data == null) {
- data = defaultData;
- }
-
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, sig.getCurve());
- Test allocate = CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_LOCAL, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS);
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test setVerifyKey = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, pubkey.getParams(), pubkey.flatten()), Result.ExpectedValue.SUCCESS);
- Test ecdsaVerify = CommandTest.expect(new Command.ECDSA_verify(this.card, ECTesterApplet.KEYPAIR_LOCAL, sig.getJavaCardSig(), data, sig.getData(0)), expected);
-
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "ECDSA test of " + sig.getId() + ".", allocate, set, setVerifyKey, ecdsaVerify, cleanup));
- } else {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "ECDSA test of " + sig.getId() + ".", allocate, set, setVerifyKey, ecdsaVerify));
- }
-
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestSuite.java b/src/cz/crcs/ectester/reader/test/CardTestSuite.java
deleted file mode 100644
index fc60ae5..0000000
--- a/src/cz/crcs/ectester/reader/test/CardTestSuite.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Params;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.test.TestSuite;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.Arrays;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public abstract class CardTestSuite extends TestSuite {
- ECTesterReader.Config cfg;
- CardMngr card;
- String[] options;
-
- CardTestSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager, String name, String[] options, String... description) {
- super(writer, name, description);
- this.card = cardManager;
- this.cfg = cfg;
- this.options = options;
- }
-
- public CardMngr getCard() {
- return card;
- }
-
- public ECTesterReader.Config getCfg() {
- return cfg;
- }
-
- public String[] getOptions() {
- if (options != null) {
- return options.clone();
- } else {
- return options;
- }
- }
-
- public Test setupKeypairs(EC_Curve curve, Result.ExpectedValue expected, byte keyPair) {
- if ((Arrays.asList(options).contains("preset") && cfg.testOptions.contains("preset")) || (Arrays.asList(options).contains("random") && cfg.testOptions.contains("random"))) {
- Test setLocal = null;
- if ((keyPair & ECTesterApplet.KEYPAIR_LOCAL) != 0) {
- EC_Params priv;
- if (cfg.testOptions.contains("preset")) {
- priv = ECUtil.fixedRandomKey(curve);
- } else {
- priv = ECUtil.fullRandomKey(curve);
- }
- setLocal = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, priv.getParams(), priv.flatten()), expected);
- }
- Test setRemote = null;
- if ((keyPair & ECTesterApplet.KEYPAIR_REMOTE) != 0) {
- EC_Params pub;
- if (cfg.testOptions.contains("preset")) {
- pub = ECUtil.fixedRandomPoint(curve);
- } else {
- pub = ECUtil.fullRandomPoint(curve);
- }
- if (pub == null) {
- setRemote = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_REMOTE), expected);
- } else {
- setRemote = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), expected);
- }
- }
-
- if (keyPair == ECTesterApplet.KEYPAIR_LOCAL) {
- return setLocal;
- } else if (keyPair == ECTesterApplet.KEYPAIR_REMOTE) {
- return setRemote;
- } else {
- String desc;
- if (cfg.testOptions.contains("preset")) {
- desc = "Set semi-random parameters.";
- } else {
- desc = "Set fully-random parameters.";
- }
- return CompoundTest.all(expected, desc, setLocal, setRemote);
- }
- } else {
- return CommandTest.expect(new Command.Generate(this.card, keyPair), expected);
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java b/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
deleted file mode 100644
index d143852..0000000
--- a/src/cz/crcs/ectester/reader/test/CardTestVectorSuite.java
+++ /dev/null
@@ -1,235 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.*;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.test.TestCallback;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-import javacard.security.KeyPair;
-
-import javax.crypto.KeyAgreement;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.*;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPrivateKeySpec;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.function.BiFunction;
-import java.util.stream.Collectors;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-import static cz.crcs.ectester.common.test.Result.Value;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardTestVectorSuite extends CardTestSuite {
-
- public CardTestVectorSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "test-vectors", null, "The test-vectors suite contains a collection of test vectors which test basic ECDH correctness.");
- }
-
- @Override
- protected void runTests() throws Exception {
- /* Set original curves (secg/nist/brainpool). Set keypairs from test vectors.
- * Do ECDH both ways, export and verify that the result is correct.
- */
- Map<String, EC_KAResult> results = EC_Store.getInstance().getObjects(EC_KAResult.class, "test");
- for (EC_KAResult result : results.values()) {
- EC_Curve curve = EC_Store.getInstance().getObject(EC_Curve.class, result.getCurve());
- EC_Params onekey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOneKey());
- if (onekey == null) {
- onekey = EC_Store.getInstance().getObject(EC_Key.Private.class, result.getOneKey());
- }
- EC_Params otherkey = EC_Store.getInstance().getObject(EC_Keypair.class, result.getOtherKey());
- if (otherkey == null) {
- otherkey = EC_Store.getInstance().getObject(EC_Key.Public.class, result.getOtherKey());
- }
- if (onekey == null || otherkey == null) {
- throw new IOException("Test vector keys couldn't be located.");
- }
- List<Test> testVector = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
-
- testVector.add(allocate);
- testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.CURVE_external, EC_Consts.PARAMETER_S, onekey.flatten(EC_Consts.PARAMETER_S)), ExpectedValue.SUCCESS));
- testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, EC_Consts.PARAMETER_W, otherkey.flatten(EC_Consts.PARAMETER_W)), ExpectedValue.SUCCESS));
- testVector.add(CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, result.getJavaCardKA()), new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- Response.ECDH dh = (Response.ECDH) testable.getResponse();
- if (!dh.successful())
- return new Result(Value.FAILURE, "ECDH was unsuccessful.");
- if (!dh.hasSecret())
- return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
- if (!ByteUtil.compareBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength())) {
- int firstDiff = ByteUtil.diffBytes(dh.getSecret(), 0, result.getData(0), 0, dh.secretLength());
- return new Result(Value.FAILURE, "ECDH derived secret does not match the test-vector, first difference was at byte " + firstDiff + ".");
- }
- return new Result(Value.SUCCESS);
- }
- }));
- if (cfg.cleanup) {
- testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY));
- }
- doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Test vector " + result.getId() + ".", testVector.toArray(new Test[0])));
- }
-
- KeyAgreement ka;
- Signature sig;
- KeyFactory kf;
- MessageDigest md;
- try {
- ka = KeyAgreement.getInstance("ECDH", "BC");
- sig = Signature.getInstance("ECDSAwithSHA1", "BC");
- kf = KeyFactory.getInstance("ECDH", "BC");
- md = MessageDigest.getInstance("SHA1", "BC");
- } catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
- return;
- }
-
- List<EC_Curve> testCurves = new ArrayList<>();
- testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "secg").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList()));
- testCurves.addAll(EC_Store.getInstance().getObjects(EC_Curve.class, "brainpool").values().stream().filter((curve) -> curve.getField() == KeyPair.ALG_EC_FP).collect(Collectors.toList()));
- for (EC_Curve curve : testCurves) {
- List<Test> testVector = new LinkedList<>();
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()) + ".", allocate));
- continue;
- }
- testVector.add(allocate);
- testVector.add(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.SUCCESS));
- testVector.add(CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.SUCCESS));
- CommandTest exportLocal = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.KEY_PUBLIC, EC_Consts.PARAMETER_W), ExpectedValue.ANY);
- CommandTest exportRemote = CommandTest.expect(new Command.Export(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.KEY_PRIVATE, EC_Consts.PARAMETER_S), ExpectedValue.ANY);
- testVector.add(exportLocal);
- testVector.add(exportRemote);
- BiFunction<Response.Export, Response.Export, Key[]> getKeys = (localData, remoteData) -> {
- byte[] pkey = localData.getParameter(ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.PARAMETER_W);
- byte[] skey = remoteData.getParameter(ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.PARAMETER_S);
- ECParameterSpec spec = curve.toSpec();
- ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger(1, skey), spec);
- ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(ECUtil.fromX962(pkey, curve.toCurve()), spec);
- PrivateKey privKey;
- PublicKey pubKey;
- try {
- privKey = kf.generatePrivate(privKeySpec);
- pubKey = kf.generatePublic(pubKeySpec);
- } catch (InvalidKeySpecException ex) {
- return null;
- }
- return new Key[]{privKey, pubKey};
- };
- TestCallback<CommandTestable> kaCallback = new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- Response.ECDH ecdhData = (Response.ECDH) testable.getResponse();
- if (!ecdhData.successful())
- return new Result(Value.FAILURE, "ECDH was unsuccessful.");
- if (!ecdhData.hasSecret()) {
- return new Result(Value.FAILURE, "ECDH response did not contain the derived secret.");
- }
- byte[] secret = ecdhData.getSecret();
- Response.Export localData = (Response.Export) exportLocal.getResponse();
- Response.Export remoteData = (Response.Export) exportRemote.getResponse();
- Key[] keys = getKeys.apply(localData, remoteData);
- if (keys == null) {
- return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable.");
- }
- PrivateKey privKey = (PrivateKey) keys[0];
- PublicKey pubKey = (PublicKey) keys[1];
- try {
- ka.init(privKey);
- ka.doPhase(pubKey, true);
- byte[] derived = ka.generateSecret();
- int fieldSize = (curve.getBits() + 7) / 8;
- if (derived.length < fieldSize) {
- byte[] padded = new byte[fieldSize];
- System.arraycopy(derived, 0, padded, fieldSize - derived.length, derived.length);
- derived = padded;
- }
- if (ecdhData.getType() == EC_Consts.KeyAgreement_ALG_EC_SVDP_DH || ecdhData.getType() == EC_Consts.KeyAgreement_ALG_EC_SVDP_DHC) {
- derived = md.digest(derived);
- }
- if (secret.length != derived.length) {
- if (secret.length < derived.length) {
- return new Result(Value.FAILURE, String.format("Derived secret was shorter than expected: %d vs %d (expected).", secret.length, derived.length));
- } else {
- return new Result(Value.FAILURE, String.format("Derived secret was longer than expected: %d vs %d (expected).", secret.length, derived.length));
- }
- }
- int diff = ByteUtil.diffBytes(derived, 0, secret, 0, secret.length);
- if (diff == secret.length) {
- return new Result(Value.SUCCESS, "Derived secret matched expected value.");
- } else {
- return new Result(Value.FAILURE, "Derived secret does not match expected value, first difference was at byte " + diff + ".");
- }
- } catch (InvalidKeyException ex) {
- return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage());
- }
- }
- };
- Test ecdhTest = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), kaCallback);
- Test ecdhRawTest = CommandTest.function(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_TRUE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH_PLAIN), kaCallback);
- byte[] data = new byte[32];
- TestCallback<CommandTestable> sigCallback = new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- Response.ECDSA ecdsaData = (Response.ECDSA) testable.getResponse();
- if (!ecdsaData.successful())
- return new Result(Value.FAILURE, "ECDSA was unsuccessful.");
- if (!ecdsaData.hasSignature()) {
- return new Result(Value.FAILURE, "ECDSA response did not contain the signature.");
- }
- byte[] signature = ecdsaData.getSignature();
- Response.Export localData = (Response.Export) exportLocal.getResponse();
- Response.Export remoteData = (Response.Export) exportRemote.getResponse();
- Key[] keys = getKeys.apply(localData, remoteData);
- if (keys == null) {
- return new Result(Value.SUCCESS, "Result could not be verified. keyData unavailable.");
- }
- PublicKey pubKey = (PublicKey) keys[1];
- try {
- sig.initVerify(pubKey);
- sig.update(data);
- if (sig.verify(signature)) {
- return new Result(Value.SUCCESS, "Signature verified.");
- } else {
- return new Result(Value.FAILURE, "Signature failed to verify.");
- }
- } catch (InvalidKeyException | SignatureException ex) {
- return new Result(Value.SUCCESS, "Result could not be verified. " + ex.getMessage());
- }
- }
- };
- Test ecdsaTest = CommandTest.function(new Command.ECDSA_sign(this.card, ECTesterApplet.KEYPAIR_LOCAL, EC_Consts.Signature_ALG_ECDSA_SHA, ECTesterApplet.EXPORT_TRUE, data), sigCallback);
- testVector.add(CompoundTest.all(ExpectedValue.SUCCESS, "Test.", ecdhTest, ecdhRawTest, ecdsaTest));
- if (cfg.cleanup) {
- testVector.add(CommandTest.expect(new Command.Cleanup(this.card), ExpectedValue.ANY));
- }
- doTest(CompoundTest.greedyAll(ExpectedValue.SUCCESS, "Validation test on " + curve.getId() + ".", testVector.toArray(new Test[0])));
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java b/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
deleted file mode 100644
index a6bca6c..0000000
--- a/src/cz/crcs/ectester/reader/test/CardTwistSuite.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Key;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardTwistSuite extends CardTestSuite {
- public CardTwistSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "twist", null, "The twist test suite tests whether the card correctly rejects points on the quadratic twist of the curve during ECDH.");
- }
-
- @Override
- protected void runTests() throws Exception {
- Map<String, EC_Key.Public> pubkeys = EC_Store.getInstance().getObjects(EC_Key.Public.class, "twist");
- Map<EC_Curve, List<EC_Key.Public>> curveList = EC_Store.mapKeyToCurve(pubkeys.values());
- for (Map.Entry<EC_Curve, List<EC_Key.Public>> e : curveList.entrySet()) {
- EC_Curve curve = e.getKey();
- List<EC_Key.Public> keys = e.getValue();
-
- Test allocate = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), Result.ExpectedValue.SUCCESS));
- if (!allocate.ok()) {
- doTest(CompoundTest.all(Result.ExpectedValue.SUCCESS, "No support for " + curve.getId() + ".", allocate));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), Result.ExpectedValue.SUCCESS);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_LOCAL), Result.ExpectedValue.SUCCESS);
-
- Test prepare = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Prepare and generate keypair on " + curve.getId() + ".", allocate, set, generate);
-
- List<Test> ecdhTests = new LinkedList<>();
- for (EC_Key.Public pub : keys) {
- Test setPub = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_REMOTE, EC_Consts.CURVE_external, pub.getParams(), pub.flatten()), Result.ExpectedValue.FAILURE);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist.");
- Test objectEcdh = CompoundTest.any(Result.ExpectedValue.SUCCESS, CardUtil.getKATypeString(EC_Consts.KeyAgreement_ALG_EC_SVDP_DH) + " test with twist pubkey.", setPub, ecdh);
- Command ecdhCommand = new Command.ECDH_direct(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH, pub.flatten());
- Test rawEcdh = CommandTest.expect(ecdhCommand, Result.ExpectedValue.FAILURE, "Card correctly rejected point on twist.", "Card incorrectly accepted point on twist.");
- ecdhTests.add(CompoundTest.all(Result.ExpectedValue.SUCCESS, pub.getId() + " twist key test.", objectEcdh, rawEcdh));
- }
- Test ecdh = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Perform ECDH with public points on twist.", ecdhTests.toArray(new Test[0]));
-
- Test tests = CompoundTest.all(Result.ExpectedValue.SUCCESS, "Do tests.", ecdh);
- if (cfg.cleanup) {
- Test cleanup = CommandTest.expect(new Command.Cleanup(this.card), Result.ExpectedValue.ANY);
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests, cleanup));
- } else {
- doTest(CompoundTest.greedyAllTry(Result.ExpectedValue.SUCCESS, "Twist test of " + curve.getId() + ".", prepare, tests));
- }
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java b/src/cz/crcs/ectester/reader/test/CardWrongSuite.java
deleted file mode 100644
index 13a3f8b..0000000
--- a/src/cz/crcs/ectester/reader/test/CardWrongSuite.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.applet.EC_Consts;
-import cz.crcs.ectester.common.ec.EC_Curve;
-import cz.crcs.ectester.common.ec.EC_Params;
-import cz.crcs.ectester.common.output.TestWriter;
-import cz.crcs.ectester.common.test.CompoundTest;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.Test;
-import cz.crcs.ectester.common.util.ByteUtil;
-import cz.crcs.ectester.common.util.CardUtil;
-import cz.crcs.ectester.common.util.ECUtil;
-import cz.crcs.ectester.data.EC_Store;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.ECTesterReader;
-import cz.crcs.ectester.reader.command.Command;
-import javacard.security.KeyPair;
-
-import java.math.BigInteger;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-import static cz.crcs.ectester.common.test.Result.ExpectedValue;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CardWrongSuite extends CardTestSuite {
-
- public CardWrongSuite(TestWriter writer, ECTesterReader.Config cfg, CardMngr cardManager) {
- super(writer, cfg, cardManager, "wrong", new String[]{"preset", "random"}, "The wrong curve suite tests whether the card rejects domain parameters which are not curves.");
- }
-
- @Override
- protected void runTests() throws Exception {
- /* Just do the default run on the wrong curves.
- * These should generally fail, the curves aren't curves.
- */
- Map<String, EC_Curve> curves = EC_Store.getInstance().getObjects(EC_Curve.class, "wrong");
- for (Map.Entry<String, EC_Curve> e : curves.entrySet()) {
- EC_Curve curve = e.getValue();
- List<Test> tests = new LinkedList<>();
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, curve.getBits(), curve.getField()), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), key));
- continue;
- }
- tests.add(key);
- Test set = runTest(CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, curve.getParams(), curve.flatten()), ExpectedValue.FAILURE));
- Test generate = runTest(setupKeypairs(curve, ExpectedValue.SUCCESS, ECTesterApplet.KEYPAIR_BOTH));
- Test setup = runTest(CompoundTest.any(ExpectedValue.SUCCESS, "Set wrong curve and generate keypairs.", set, generate));
- tests.add(setup);
-
- for (byte kaType : EC_Consts.KA_TYPES) {
- Test allocate = runTest(CommandTest.expect(new Command.AllocateKeyAgreement(this.card, kaType), ExpectedValue.SUCCESS));
- if (allocate.ok()) {
- Test ka = runTest(CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, kaType), ExpectedValue.FAILURE));
- Test kaTest = runTest(CompoundTest.all(ExpectedValue.SUCCESS, "Allocate and perform KA.", allocate, ka));
- tests.add(kaTest);
- }
- }
- doTest(CompoundTest.function((tsts) -> {
- for (int i = 0; i < tsts.length; ++i) {
- if (i != 1 && !tsts[i].ok()) {
- return new Result(Result.Value.FAILURE, "Some tests did not have the expected result.");
- }
- }
- return new Result(Result.Value.SUCCESS, "All tests had the expected result.");
- }, "Wrong curve test of " + curve.getBits() + "b " + CardUtil.getKeyTypeString(curve.getField()), tests.toArray(new Test[0])));
- }
- /*
- * Do some interesting tests with corrupting the custom curves.
- * For prime field:
- * - p = 0
- * - p = 1
- * - p is a square of a prime
- * - p is a composite q * s with q, s primes
- * - TODO: p divides discriminant
- */
- Random r = new Random();
- for (short keyLength : EC_Consts.FP_SIZES) {
- byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_FP);
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_FP), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_FP.", key));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_FP, null), ExpectedValue.SUCCESS);
- Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
-
- Test prime0 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.TRANSFORMATION_ZERO), "Set p = 0.", "ECDH with p = 0.");
- Test prime1 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_FP, EC_Consts.TRANSFORMATION_ONE), "Set p = 1.", "ECDH with p = 1.");
-
- short keyHalf = (short) (keyLength / 2);
- BigInteger prime = new BigInteger(keyHalf, 50, r);
- BigInteger primePow = prime.pow(2);
- byte[] primePowBytes = ECUtil.toByteArray(primePow, keyLength);
- EC_Params primePowData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{primePowBytes});
- Test primePower = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, primePowData.getParams(), primePowData.flatten()), "Set p = square of a prime.", "ECDH with p = q^2.");
-
- BigInteger q = new BigInteger(keyHalf, r);
- BigInteger s = new BigInteger(keyHalf, r);
- BigInteger compositeValue = q.multiply(s);
- byte[] compositeBytes = ECUtil.toByteArray(compositeValue, keyLength);
- EC_Params compositeData = new EC_Params(EC_Consts.PARAMETER_FP, new byte[][]{compositeBytes});
- Test composite = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, compositeData.getParams(), compositeData.flatten()), "Set p = product of two primes.", "ECDH with p = q * s.");
-
- Test wrongPrime = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted prime parameter.", prime0, prime1, primePower, composite);
-
- Test resetSetup = CompoundTest.all(ExpectedValue.SUCCESS, "Reset keypair.", set.clone());
-
- Test randomG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, (short) (EC_Consts.TRANSFORMATION_FULLRANDOM | EC_Consts.TRANSFORMATION_04_MASK)), "Set G = random non-point/point-like.", "ECDH with non-point G.");
- Test fullRandomG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_FULLRANDOM), "Set G = random data.", "ECDH with G = random data.");
- Test zeroG = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_G, EC_Consts.TRANSFORMATION_INFINITY), "Set G = inifnity.", "ECDH with G = infinity.");
- Test wrongG = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted G parameter.", randomG, fullRandomG, zeroG);
-
- byte[] originalR = new byte[((keyLength + 7) / 8) + 1];
- short origRlen = EC_Consts.getCurveParameter(curve, EC_Consts.PARAMETER_R, originalR, (short) 0);
- if (origRlen != originalR.length) {
- byte[] copyR = new byte[origRlen];
- System.arraycopy(originalR, 0, copyR, 0, origRlen);
- originalR = copyR;
- }
- BigInteger originalBigR = new BigInteger(1, originalR);
-
- Test zeroR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ZERO), "Set R = 0.", "ECDH with R = 0.");
- Test oneR = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, EC_Consts.PARAMETER_R, EC_Consts.TRANSFORMATION_ONE), "Set R = 1.", "ECDH with R = 1.");
-
- BigInteger prevPrimeR;
- do {
- prevPrimeR = BigInteger.probablePrime(originalBigR.bitLength() - 1, r);
- } while (prevPrimeR.compareTo(originalBigR) >= 0);
- byte[] prevRBytes = ECUtil.toByteArray(prevPrimeR, keyLength);
- EC_Params prevRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{prevRBytes});
- Test prevprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, prevRData.getParams(), prevRData.flatten()), "Set R = some prime (but [r]G != infinity) smaller than original R.", "ECDH with wrong R, prevprime.");
-
- BigInteger nextPrimeR = originalBigR.nextProbablePrime();
- byte[] nextRBytes = ECUtil.toByteArray(nextPrimeR, keyLength);
- EC_Params nextRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nextRBytes});
- Test nextprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nextRData.getParams(), nextRData.flatten()), "Set R = some prime (but [r]G != infinity) larger than original R.", "ECDH with wrong R, nextprime.");
-
- byte[] nonprimeRBytes = nextRBytes.clone();
- nonprimeRBytes[nonprimeRBytes.length - 1] ^= 1;
- EC_Params nonprimeWrongRData = new EC_Params(EC_Consts.PARAMETER_R, new byte[][]{nonprimeRBytes});
- Test nonprimeWrongR = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, nonprimeWrongRData.getParams(), nonprimeWrongRData.flatten()), "Set R = some composite (but [r]G != infinity).", "ECDH with wrong R, composite.");
-
- Test wrongR = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted R parameter.", zeroR, oneR, prevprimeWrongR, nextprimeWrongR, nonprimeWrongR);
-
- byte[] kRaw = new byte[]{(byte) 0xff};
- EC_Params kData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kRaw});
- Test bigK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kData.getParams(), kData.flatten()), "", "");
-
- byte[] kZero = new byte[]{(byte) 0};
- EC_Params kZeroData = new EC_Params(EC_Consts.PARAMETER_K, new byte[][]{kZero});
- Test zeroK = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, kZeroData.getParams(), kZeroData.flatten()), "", "");
-
- Test wrongK = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted K parameter.", bigK, zeroK);
-
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_FP), setup, wrongPrime, resetSetup, wrongG, resetSetup.clone(), wrongR, resetSetup.clone(), wrongK, resetSetup.clone()));
- }
-
- /*
- * For binary field:
- * - e1, e2 or e3 is larger than m.
- * - e1 = e2 = e3 = 0
- */
- for (short keyLength : EC_Consts.F2M_SIZES) {
- byte curve = EC_Consts.getCurve(keyLength, KeyPair.ALG_EC_F2M);
- Test key = runTest(CommandTest.expect(new Command.Allocate(this.card, ECTesterApplet.KEYPAIR_BOTH, keyLength, KeyPair.ALG_EC_F2M), ExpectedValue.SUCCESS));
- if (!key.ok()) {
- doTest(CompoundTest.all(ExpectedValue.FAILURE, "No support for " + keyLength + "b ALG_EC_F2M.", key));
- continue;
- }
- Test set = CommandTest.expect(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, curve, EC_Consts.PARAMETERS_DOMAIN_F2M, null), ExpectedValue.SUCCESS);
- Test setup = CompoundTest.all(ExpectedValue.SUCCESS, "KeyPair setup.", key, set);
-
- Test coeff0 = ecdhTest(new Command.Transform(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.KEY_BOTH, EC_Consts.PARAMETER_F2M, EC_Consts.TRANSFORMATION_ZERO), "Set e1 = e2 = e3 = 0.", "ECDH with wrong field polynomial: x^" + keyLength);
-
- short e1 = (short) (2 * keyLength);
- short e2 = (short) (3 * keyLength);
- short e3 = (short) (4 * keyLength);
- byte[][] coeffBytes = new byte[][]{
- ByteUtil.shortToBytes(keyLength),
- ByteUtil.shortToBytes(e1),
- ByteUtil.shortToBytes(e2),
- ByteUtil.shortToBytes(e3)};
- EC_Params coeffParams = new EC_Params(EC_Consts.PARAMETER_F2M, coeffBytes);
- Test coeffLarger = ecdhTest(new Command.Set(this.card, ECTesterApplet.KEYPAIR_BOTH, EC_Consts.CURVE_external, coeffParams.getParams(), coeffParams.flatten()), "Set e1=" + e1 + ", e2=" + e2 + ", e3=" + e3, "ECDH with wrong field poly, powers larger than " + keyLength);
-
- Test wrong = CompoundTest.all(ExpectedValue.SUCCESS, "Tests with corrupted field polynomial parameter.", coeff0, coeffLarger);
- doTest(CompoundTest.all(ExpectedValue.SUCCESS, "Tests of " + keyLength + "b " + CardUtil.getKeyTypeString(KeyPair.ALG_EC_F2M), setup, wrong));
- }
-
- /*
- * TODO: tests for both Fp and F2m:
- * - generator not on curve,
- * - generator not on proper subgroup of curve(as specified by order/cofactor),
- * - wrong order,
- * - wrong cofactor.
- */
- }
-
- private Test ecdhTest(Command setupCmd, String prepareDesc, String fullDesc) {
- Test setup = CommandTest.expect(setupCmd, ExpectedValue.FAILURE);
- Test generate = CommandTest.expect(new Command.Generate(this.card, ECTesterApplet.KEYPAIR_BOTH), ExpectedValue.FAILURE);
- Test preparePhase = CompoundTest.any(ExpectedValue.SUCCESS, prepareDesc, setup, generate);
- Test allocateECDH = CommandTest.expect(new Command.AllocateKeyAgreement(this.card, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ExpectedValue.SUCCESS);
- Test ecdh = CommandTest.expect(new Command.ECDH(this.card, ECTesterApplet.KEYPAIR_LOCAL, ECTesterApplet.KEYPAIR_REMOTE, ECTesterApplet.EXPORT_FALSE, EC_Consts.TRANSFORMATION_NONE, EC_Consts.KeyAgreement_ALG_EC_SVDP_DH), ExpectedValue.FAILURE);
-
-
- return CompoundTest.function((tests) -> {
- if (preparePhase.ok() | !allocateECDH.ok() | ecdh.ok()) {
- return new Result(Result.Value.SUCCESS, "All tests had the expected result.");
- } else {
- return new Result(Result.Value.FAILURE, "Some tests did not have the expected result.");
- }
- }, (tests) -> {
- preparePhase.run();
- if (preparePhase.ok()) {
- return;
- }
- allocateECDH.run();
- if (!allocateECDH.ok()) {
- return;
- }
- ecdh.run();
- }, fullDesc, preparePhase, allocateECDH, ecdh);
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTest.java b/src/cz/crcs/ectester/reader/test/CommandTest.java
deleted file mode 100644
index b05d3e4..0000000
--- a/src/cz/crcs/ectester/reader/test/CommandTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.SimpleTest;
-import cz.crcs.ectester.common.test.TestCallback;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-
-import java.util.Arrays;
-
-/**
- * A simple test that runs one Command to get and evaluate one Response
- * to get a Result and compare it with the expected one.
- *
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CommandTest extends SimpleTest<CommandTestable> {
- private CommandTest(CommandTestable command, TestCallback<CommandTestable> callback) {
- super(command, callback);
- }
-
- public static CommandTest function(CommandTestable command, TestCallback<CommandTestable> callback) {
- return new CommandTest(command, callback);
- }
-
- public static CommandTest function(Command command, TestCallback<CommandTestable> callback) {
- return function(new CommandTestable(command), callback);
- }
-
- public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected, String ok, String nok) {
- return new CommandTest(command, new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable commandTestable) {
- Result.Value resultValue = Result.Value.fromExpected(expected, commandTestable.ok(), commandTestable.error());
- return new Result(resultValue, commandTestable.error() ? commandTestable.errorCause() : (resultValue.ok() ? ok : nok));
- }
- });
- }
-
- public static CommandTest expect(Command command, Result.ExpectedValue expectedValue, String ok, String nok) {
- return expect(new CommandTestable(command), expectedValue, ok, nok);
- }
-
- public static CommandTest expect(CommandTestable command, Result.ExpectedValue expected) {
- return expect(command, expected, null, null);
- }
-
- public static CommandTest expect(Command command, Result.ExpectedValue expectedValue) {
- return expect(command, expectedValue, null, null);
- }
-
- public static CommandTest expectSW(CommandTestable command, short... expectedSWS) {
- return new CommandTest(command, new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable commandTestable) {
- if (Arrays.equals(commandTestable.getResponse().getSWs(), expectedSWS)) {
- return new Result(Result.Value.SUCCESS);
- } else {
- return new Result(Result.Value.FAILURE);
- }
- }
- });
- }
-
- public static CommandTest expectSW(Command command, short... expectedSWS) {
- return expectSW(new CommandTestable(command), expectedSWS);
- }
-
- public Command getCommand() {
- return testable.getCommand();
- }
-
- public Response getResponse() {
- return testable.getResponse();
- }
-
- @Override
- public String getDescription() {
- if (hasRun) {
- return testable.getResponse().getDescription();
- } else {
- return testable.getCommand().getDescription();
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/CommandTestable.java b/src/cz/crcs/ectester/reader/test/CommandTestable.java
deleted file mode 100644
index f670534..0000000
--- a/src/cz/crcs/ectester/reader/test/CommandTestable.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.common.test.BaseTestable;
-import cz.crcs.ectester.common.test.TestException;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-
-import javax.smartcardio.CardException;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class CommandTestable extends BaseTestable {
- private Command command;
- private Response response;
-
- public CommandTestable(Command command) {
- this.command = command;
- }
-
- public Command getCommand() {
- return command;
- }
-
- public Response getResponse() {
- return response;
- }
-
- @Override
- public void run() {
- try {
- response = command.send();
- } catch (CardException e) {
- throw new TestException(e);
- }
-
- hasRun = true;
- if (response.error()) {
- error = true;
- } else if (response.successful()) {
- ok = true;
- }
- }
-}
diff --git a/src/cz/crcs/ectester/reader/test/PerformanceTest.java b/src/cz/crcs/ectester/reader/test/PerformanceTest.java
deleted file mode 100644
index f9cba46..0000000
--- a/src/cz/crcs/ectester/reader/test/PerformanceTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package cz.crcs.ectester.reader.test;
-
-import cz.crcs.ectester.applet.ECTesterApplet;
-import cz.crcs.ectester.common.test.Result;
-import cz.crcs.ectester.common.test.SimpleTest;
-import cz.crcs.ectester.common.test.TestCallback;
-import cz.crcs.ectester.common.test.TestException;
-import cz.crcs.ectester.reader.CardMngr;
-import cz.crcs.ectester.reader.command.Command;
-import cz.crcs.ectester.reader.response.Response;
-
-import javax.smartcardio.CardException;
-import java.util.Arrays;
-
-/**
- * @author Jan Jancar johny@neuromancer.sk
- */
-public class PerformanceTest extends SimpleTest<CommandTestable> {
- private CardMngr cardManager;
- private long[] times;
- private long[] reducedTimes;
- private Response[] responses;
- private long mean;
- private long median;
- private long mode;
- private int count;
- private String desc;
-
- private PerformanceTest(CardMngr cardManager, CommandTestable testable, int count, String desc) {
- super(testable, new TestCallback<CommandTestable>() {
- @Override
- public Result apply(CommandTestable testable) {
- return new Result(Result.Value.SUCCESS);
- }
- });
- this.cardManager = cardManager;
- this.count = count;
- this.desc = desc;
- }
-
- public static PerformanceTest repeat(CardMngr cardManager, Command cmd, int count) {
- return new PerformanceTest(cardManager, new CommandTestable(cmd), count, null);
- }
-
- public static PerformanceTest repeat(CardMngr cardManager, String desc, Command cmd, int count) {
- return new PerformanceTest(cardManager, new CommandTestable(cmd), count, desc);
- }
-
- @Override
- public String getDescription() {
- String rest = String.format("Mean = %d ns, Median = %d ns, Mode = %d ns", mean, median, mode);
- return (desc == null ? rest : desc + " (" + rest + ")");
- }
-
- @Override
- protected void runSelf() {
- long baseTime;
- try {
- new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_DRY_RUN).send();
- testable.run();
- baseTime = testable.getResponse().getDuration();
- testable.reset();
- testable.run();
- baseTime += testable.getResponse().getDuration();
- testable.reset();
- baseTime /= 2;
- new Command.SetDryRunMode(cardManager, ECTesterApplet.MODE_NORMAL).send();
- } catch (CardException ce) {
- throw new TestException(ce);
- }
-
- times = new long[count];
- reducedTimes = new long[count];
- responses = new Response[count];
- for (int i = 0; i < count; ++i) {
- testable.run();
- responses[i] = testable.getResponse();
- times[i] = responses[i].getDuration();
- reducedTimes[i] = times[i] - baseTime;
- testable.reset();
- }
-
- mean = Arrays.stream(reducedTimes).sum() / count;
-
- long[] sorted = reducedTimes.clone();
- Arrays.sort(sorted);
- if (count % 2 == 0) {
- median = (sorted[(count / 2) - 1] + sorted[count / 2]) / 2;
- } else {
- median = sorted[count / 2];
- }
-
- long max_occurences = 0;
- int i = 0;
- while (i < count) {
- long current_value = sorted[i];
- long current_occurences = 0;
- while (i < count && sorted[i] == current_value) {
- i++;
- current_occurences++;
- }
- if (current_occurences > max_occurences) {
- max_occurences = current_occurences;
- mode = current_value;
- }
- }
- result = callback.apply(testable);
- }
-
- public long getCount() {
- return count;
- }
-
- public Command getCommand() {
- return testable.getCommand();
- }
-
- public Response[] getResponses() {
- return responses;
- }
-
- public long[] getTimes() {
- return times;
- }
-
- public long[] getReducedTimes() {
- return reducedTimes;
- }
-
- public long getMean() {
- return mean;
- }
-
- public long getMedian() {
- return median;
- }
-
- public long getMode() {
- return mode;
- }
-}