diff options
Diffstat (limited to 'src')
8 files changed, 1094 insertions, 32 deletions
diff --git a/src/main/java/org/uic/barcode/Encoder.java b/src/main/java/org/uic/barcode/Encoder.java index 9afddce..b01ca14 100644 --- a/src/main/java/org/uic/barcode/Encoder.java +++ b/src/main/java/org/uic/barcode/Encoder.java @@ -27,6 +27,7 @@ import org.uic.barcode.staticFrame.ticketLayoutBarcode.TicketLayout; import org.uic.barcode.ticket.EncodingFormatException;
import org.uic.barcode.ticket.UicRailTicketCoder;
import org.uic.barcode.ticket.api.spec.IUicRailTicket;
+import org.uic.barcode.utils.ECKeyEncoder;
/**
@@ -278,6 +279,30 @@ public class Encoder { }
}
+ /**
+ * Sets the level 2 algorithm Is.
+ *
+ * @param level2SigningAlg the level 2 signing algorithm (OID)
+ * @param level2KeyAlg the level 2 key algorithm (OID)
+ * @param publicKey the public key of the level 2 signature
+ * @param publicKeyEncodingFormat "X509", for elliptic curve keys only: "X962_UNCOMPRESSED", "X962_COMPRESSED" constants defined in class ECKeyEncoder.
+ **/
+ public void setLevel2Algs(String level2SigningAlg, String level2KeyAlg, PublicKey publicKey, String publicKeyEncodingFormat) {
+ if (dynamicFrame != null) {
+ if (dynamicFrame.getLevel2Data() == null) {
+ dynamicFrame.setLevel2Data(new SimpleLevel2Data());
+ }
+ if (dynamicFrame.getLevel2Data().getLevel1Data() == null) {
+ dynamicFrame.getLevel2Data().setLevel1Data(new SimpleLevel1Data());
+ }
+ dynamicFrame.getLevel2Data().getLevel1Data().setLevel2SigningAlg(level2SigningAlg);
+ dynamicFrame.getLevel2Data().getLevel1Data().setLevel2KeyAlg(level2KeyAlg);
+ if (publicKey != null) {
+ dynamicFrame.getLevel2Data().getLevel1Data().setLevel2publicKey(ECKeyEncoder.getEncoded(publicKey, publicKeyEncodingFormat));
+ }
+ }
+ }
+
public void setDynamicData(IUicDynamicContent content) throws EncodingFormatException {
if (dynamicFrame != null) {
if (dynamicFrame.getLevel2Data() == null) {
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java index ae1b4e2..15f169b 100644 --- a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java +++ b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java @@ -8,8 +8,6 @@ import java.security.Provider; import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import org.uic.barcode.dynamicContent.api.DynamicContentCoder;
@@ -20,6 +18,7 @@ import org.uic.barcode.dynamicFrame.v1.DynamicFrameCoderV1; import org.uic.barcode.dynamicFrame.v2.DynamicFrameCoderV2;
import org.uic.barcode.ticket.EncodingFormatException;
import org.uic.barcode.utils.AlgorithmNameResolver;
+import org.uic.barcode.utils.ECKeyEncoder;
import org.uic.barcode.utils.SecurityUtils;
@@ -180,15 +179,12 @@ public class SimpleDynamicFrame implements IDynamicFrame { }
KeyFactory keyFactory = KeyFactory.getInstance(keyAlgName,provider);
if (keyFactory != null) {
- X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
- key = keyFactory.generatePublic(keySpec);
+ key = ECKeyEncoder.fromEncoded(keyBytes,level2KeyAlg, provider);
} else {
return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED;
}
- } catch (InvalidKeySpecException e1) {
- return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED;
- } catch (NoSuchAlgorithmException e1) {
+ } catch (Exception e1) {
return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED;
}
diff --git a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java new file mode 100644 index 0000000..e1662a7 --- /dev/null +++ b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java @@ -0,0 +1,321 @@ +package org.uic.barcode.utils;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ECKeyEncoder.
+ */
+public class ECKeyEncoder {
+
+
+ /** The Constant X962_UNCOMPRESSED_POINT_INDICATOR. */
+ private static final byte X962_UNCOMPRESSED_POINT_INDICATOR = 0x04;
+
+ /** The Constant X962_ODD. */
+ private static final byte X962_ODD = 0x02;
+
+ /** The Constant X962_EVEN. */
+ private static final byte X962_EVEN = 0x03;
+
+ /** The Constant ENCODING_X509. */
+ public static final String ENCODING_X509 = "X509";
+
+ /** The Constant ENCODING_X962_UNCOMPESSED. */
+ public static final String ENCODING_X962_UNCOMPESSED = "X962_UNCOMPRESSED";
+
+ /** The Constant ENCODING_X962_COMPRESSED. */
+ public static final String ENCODING_X962_COMPRESSED = "X962_COMPRESSED";
+
+
+ /**
+ * From encoded.
+ *
+ * @param keyBytes the encoded key
+ * @param oid the algorithm OID of the key algorithm
+ * @param provider the provider of the security implementation
+ * @return the public key
+ */
+ public static PublicKey fromEncoded (byte[] keyBytes, String oid, Provider provider) {
+
+ PublicKey key = null;
+
+
+ String keyAlgName = null;
+ try {
+ keyAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, oid,provider);
+ } catch (Exception e1) {
+ throw new IllegalArgumentException("algorithm unknown in: " + provider.getName());
+ }
+
+ if (keyAlgName == null || keyAlgName.length() == 0) {
+ throw new IllegalArgumentException("algorithm unknown in: " + provider.getName());
+ }
+
+ //try standard X.509 encoding first
+
+ try {
+
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+
+ if (keyAlgName != null && keyAlgName.length() > 0) {
+
+ KeyFactory keyFactory = KeyFactory.getInstance(keyAlgName,provider);
+
+ key = keyFactory.generatePublic(keySpec);
+
+ }
+
+ } catch (Exception e) {
+
+ //try next option
+
+ }
+
+ if (key != null) return key;
+
+
+ //maybe a compressed X9.62 eliptic key
+ if (keyBytes[0] == X962_ODD || keyBytes[0] == X962_EVEN) {
+
+
+ try {
+
+ //we need to know the curve!
+ String curveName = EllipticCurveNames.getInstance().getName(oid);
+
+ AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider);
+ parameters.init(new ECGenParameterSpec(curveName));
+ ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
+
+ //reconstruct the uncompressed version with the curve
+ byte[] uncompressed = decompressPubkey(keyBytes, ecParameters);
+
+ //decode the uncompressed key
+ return fromUncompressedPoint(uncompressed, ecParameters, provider);
+
+ } catch (Exception e) {
+ key = null;
+ // failed
+ }
+
+
+ }
+
+ //try X962 uncompressed
+ if (keyBytes[0] == X962_UNCOMPRESSED_POINT_INDICATOR) {
+
+ try {
+ //we need to know the curve!
+ String curveName = EllipticCurveNames.getInstance().getName(oid);
+
+ //get the curve parameters
+ AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider);
+ parameters.init(new ECGenParameterSpec(curveName));
+ ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
+
+ //decode the uncompressed key
+ return fromUncompressedPoint(keyBytes, ecParameters, provider);
+
+ } catch(Exception e) {
+ //failed
+ }
+ }
+
+
+ throw new IllegalArgumentException("public key format unknown");
+ }
+
+
+
+ /**
+ * Gets the encoded.
+ *
+ * @param key the public key
+ * @param encoding the encoding ("X509","X962_UNCOMPRESSED","X962_COMPRESSED")
+ * @param provider
+ * @return the encoded key
+ */
+ public static byte[] getEncoded(PublicKey key, String encoding){
+
+ if (encoding.equals(ENCODING_X509)) {
+ return key.getEncoded();
+ } else if (encoding.equals(ENCODING_X962_UNCOMPESSED)) {
+
+ if (key instanceof ECPublicKey) {
+
+ return toUncompressedPoint((ECPublicKey) key);
+
+ }
+
+ } else if (encoding.equals(ENCODING_X962_COMPRESSED)) {
+
+ if (key instanceof ECPublicKey) {
+
+ ECPoint point = ((ECPublicKey) key).getW();
+
+ int fieldSize = (((ECPublicKey)key).getParams().getCurve().getField().getFieldSize() + 7) / 8;
+ int keySizeBytes = fieldSize + 1;
+ final byte[] compressed = new byte[keySizeBytes];
+
+
+
+ byte[] x = toUnsignedBytes(point.getAffineX());
+
+ BigInteger y = point.getAffineY();
+
+
+ //compression indicator
+ if (y.testBit(0)) {
+ compressed[0] = 0x03;
+ } else {
+ compressed[0] = 0x02;
+ }
+ System.arraycopy(x, 0, compressed, 1 + fieldSize - x.length, x.length);
+
+ return compressed;
+ }
+ }
+
+ throw new IllegalArgumentException("unknown encoding");
+
+
+ }
+
+
+ /**
+ * From uncompressed point.
+ *
+ * @param encoded the public key in uncompressed encoding
+ * @param params the elliptic curve parameters
+ * @return the EC public key
+ * @throws Exception the exception
+ */
+ private static ECPublicKey fromUncompressedPoint(
+ final byte[] encoded, final ECParameterSpec params, Provider provider)
+ throws Exception {
+
+ int offset = 0;
+ if (encoded[offset++] != X962_UNCOMPRESSED_POINT_INDICATOR) {
+ throw new IllegalArgumentException("Invalid uncompressedPoint encoding, no uncompressed point indicator");
+ }
+
+ int keySizeBytes = (params.getOrder().bitLength() + Byte.SIZE - 1)
+ / Byte.SIZE;
+
+ if (encoded.length != 1 + 2 * keySizeBytes) {
+ throw new IllegalArgumentException("Invalid uncompressedPoint encoding, not the correct size");
+ }
+
+ final BigInteger x = new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + keySizeBytes));
+ offset += keySizeBytes;
+ final BigInteger y = new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + keySizeBytes));
+ final ECPoint w = new ECPoint(x, y);
+ final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(w, params);
+ final KeyFactory keyFactory = KeyFactory.getInstance("EC",provider);
+ return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec);
+ }
+
+
+ /**
+ * To uncompressed point.
+ *
+ * @param publicKey the public key
+ * @return the encoded public key
+ */
+ private static byte[] toUncompressedPoint(final ECPublicKey publicKey) {
+
+ final byte[] xCoordBytes = toUnsignedBytes(publicKey.getW().getAffineX());
+ final byte[] yCoordBytes = toUnsignedBytes(publicKey.getW().getAffineY());
+
+ int fieldSize = (publicKey.getParams().getCurve().getField().getFieldSize() + 7) / 8;
+ int keySizeBytes = 2 * fieldSize + 1;
+ final byte[] uncompressedPoint = new byte[keySizeBytes];
+
+ System.arraycopy(xCoordBytes, 0, uncompressedPoint, 1 + fieldSize - xCoordBytes.length, xCoordBytes.length);
+ System.arraycopy(yCoordBytes, 0, uncompressedPoint, 1 + 2 * fieldSize - yCoordBytes.length, yCoordBytes.length);
+ uncompressedPoint[0] = 0x04;
+
+ return uncompressedPoint;
+ }
+
+
+
+ /**
+ * Decompress public key.
+ *
+ * @param compressedKey the compressed public key
+ * @param ecParameters the elliptic curve parameters
+ * @return uncompressed encoded public key
+ */
+ private static byte[] decompressPubkey(byte[] compressedKey, ECParameterSpec ecParameters ) {
+
+ EllipticCurve curve = ecParameters.getCurve();
+
+ // Check array length and type indicator byte
+ if (compressedKey[0] != 2 && compressedKey[0] != 3) {
+ throw new IllegalArgumentException();
+ }
+
+ final byte[] xCoordBytes = Arrays.copyOfRange(compressedKey, 1, compressedKey.length);
+ final BigInteger xCoord = new BigInteger(1, xCoordBytes); // Range [0, 2^256)
+
+ ECFieldFp ecf = (ECFieldFp) curve.getField();
+ BigInteger modulus = ecf.getP();
+ BigInteger pow = modulus.add(BigInteger.ONE).shiftRight(2);
+
+
+ BigInteger temp = xCoord.pow(2).add(curve.getA());
+ temp = temp.multiply(xCoord);
+ temp = temp.add(curve.getB());
+ temp = temp.modPow(pow, modulus);
+ boolean tempIsOdd = temp.testBit(0);
+ boolean yShouldBeOdd = compressedKey[0] == 3;
+ if (tempIsOdd != yShouldBeOdd) {
+ temp = temp.negate().mod(modulus);
+ }
+ final BigInteger yCoord = temp;
+
+ final byte[] yCoordBytes = toUnsignedBytes(yCoord);
+
+ int fieldSize = (curve.getField().getFieldSize() + 7) / 8;
+ byte[] result = new byte[2 * fieldSize + 1];
+ System.arraycopy(compressedKey, 0,result, 1 + fieldSize - compressedKey.length, compressedKey.length);
+ System.arraycopy(yCoordBytes, 0,result, 1 + 2 * fieldSize - yCoordBytes.length, yCoordBytes.length);
+ // set uncompressed key indicator
+ result[0] = 0x04;
+
+ return result;
+ }
+
+ /**
+ * To unsigned bytes.
+ *
+ * @param i the i
+ * @return the unsigned bytes of the integer
+ */
+ private static byte[] toUnsignedBytes(BigInteger i) {
+ byte[] b = i.abs().toByteArray();
+ //remove top sign bit
+ if (b[0] == 0) {
+ b = Arrays.copyOfRange(b, 1, b.length);
+ }
+ return b;
+ }
+
+
+}
diff --git a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java new file mode 100644 index 0000000..1bff0c0 --- /dev/null +++ b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java @@ -0,0 +1,114 @@ +package org.uic.barcode.utils;
+
+import java.util.HashMap;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ElipticCurves.
+ */
+public class EllipticCurveNames {
+
+
+ /** The oit to name. */
+ public HashMap<String, String> oitToName = new HashMap<String,String>();
+
+ /** The me. */
+ private static EllipticCurveNames me = null;
+
+
+ /**
+ * Gets the single instance of ElipticCurves.
+ *
+ * @return single instance of ElipticCurves
+ */
+ public static EllipticCurveNames getInstance() {
+
+ if (me == null) {
+ me = new EllipticCurveNames();
+ me.oitToName.put("1.2.840.10045.3.0.4", "c2pnb176w1");
+ me.oitToName.put("1.2.840.10045.3.0.1", "c2pnb163v1");
+ me.oitToName.put("1.2.840.10045.3.0.2", "c2pnb163v2");
+ me.oitToName.put("1.2.840.10045.3.0.3", "c2pnb163v3");
+ me.oitToName.put("1.2.840.10045.3.0.10","c2pnb208w1");
+ me.oitToName.put("1.2.840.10045.3.0.7", "c2tnb191v3");
+ me.oitToName.put("1.2.840.10045.3.0.6", "c2tnb191v2");
+ me.oitToName.put("1.2.840.10045.3.0.5", "c2tnb191v1");
+ me.oitToName.put("1.2.840.10045.3.0.13","c2tnb239v3");
+ me.oitToName.put("1.2.840.10045.3.0.12","c2tnb239v2");
+ me.oitToName.put("1.2.840.10045.3.0.11","c2tnb239v1");
+ me.oitToName.put("1.2.840.10045.3.0.16","c2pnb272w1");
+ me.oitToName.put("1.2.840.10045.3.0.17","c2pnb304w1");
+ me.oitToName.put("1.2.840.10045.3.0.19","c2pnb368w1");
+ me.oitToName.put("1.2.840.10045.3.0.18","c2tnb359v1");
+ me.oitToName.put("1.2.840.10045.3.0.20","c2tnb431r1");
+ me.oitToName.put("1.2.840.10045.3.0.8", "c2onb191v4");
+ me.oitToName.put("1.2.840.10045.3.0.9", "c2onb191v5");
+ me.oitToName.put("1.2.840.10045.3.0.14","c2onb239v4");
+ me.oitToName.put("1.2.840.10045.3.0.15","c2onb239v5");
+ me.oitToName.put("1.2.840.10045.3.1.1", "secp192r1");
+ //me.oitToName.put("1.2.840.10045.3.1.1", "prime192v1");
+ me.oitToName.put("1.2.840.10045.3.1.2", "prime192v2");
+ me.oitToName.put("1.2.840.10045.3.1.3", "prime192v3");
+ me.oitToName.put("1.2.840.10045.3.1.4", "prime239v1");
+ me.oitToName.put("1.2.840.10045.3.1.5", "prime239v2");
+ me.oitToName.put("1.2.840.10045.3.1.6", "prime239v3");
+ me.oitToName.put("1.2.840.10045.3.1.7", "secp256r1");
+ //me.oitToName.put("1.2.840.10045.3.1.7", "prime256v1");
+
+ me.oitToName.put("1.3.132.0.1", "sect163k1");
+ me.oitToName.put("1.3.132.0.2", "sect163r1");
+ me.oitToName.put("1.3.132.0.3", "sect239k1");
+ me.oitToName.put("1.3.132.0.4", "sect113r1");
+ me.oitToName.put("1.3.132.0.5", "sect113r2");
+ me.oitToName.put("1.3.132.0.6", "secp112r1");
+ me.oitToName.put("1.3.132.0.7", "secp112r2");
+ me.oitToName.put("1.3.132.0.8", "secp160r1");
+ me.oitToName.put("1.3.132.0.9", "secp160k1");
+ me.oitToName.put("1.3.132.0.10", "secp256k1");
+ me.oitToName.put("1.3.132.0.15", "sect163r2");
+ me.oitToName.put("1.3.132.0.16", "sect283k1");
+ me.oitToName.put("1.3.132.0.17", "sect283r1");
+ me.oitToName.put("1.3.132.0.22", "sect131r1");
+ me.oitToName.put("1.3.132.0.23", "sect131r2");
+ me.oitToName.put("1.3.132.0.24", "sect193r1");
+ me.oitToName.put("1.3.132.0.25", "sect193r2");
+ me.oitToName.put("1.3.132.0.26", "sect233k1");
+ me.oitToName.put("1.3.132.0.27", "sect233r1");
+ me.oitToName.put("1.3.132.0.28", "secp128r1");
+ me.oitToName.put("1.3.132.0.29", "secp128r2");
+ me.oitToName.put("1.3.132.0.30", "secp160r2");
+ me.oitToName.put("1.3.132.0.31", "secp192k1");
+ me.oitToName.put("1.3.132.0.32", "secp224k1");
+ me.oitToName.put("1.3.132.0.33", "secp224r1");
+ me.oitToName.put("1.3.132.0.34", "secp384r1");
+ me.oitToName.put("1.3.132.0.35", "secp521r1");
+ me.oitToName.put("1.3.132.0.36", "sect409k1");
+ me.oitToName.put("1.3.132.0.37", "sect409r1");
+ me.oitToName.put("1.3.132.0.38", "sect571k1");
+ me.oitToName.put("1.3.132.0.39", "sect571r1");
+
+ }
+ return me;
+ }
+
+
+ /**
+ * Adds the oid to name mapping.
+ *
+ * @param oid the oid
+ * @param name the name
+ */
+ public void addOidToNameMapping(String oid, String name) {
+ oitToName.put(oid, name);
+ }
+
+ /**
+ * Gets the name.
+ *
+ * @param oid the oid
+ * @return the name
+ */
+ public String getName(String oid) {
+ return oitToName.get(oid);
+ }
+}
diff --git a/src/main/java/org/uic/barcode/utils/SecurityUtils.java b/src/main/java/org/uic/barcode/utils/SecurityUtils.java index fc6a135..5fdbda7 100644 --- a/src/main/java/org/uic/barcode/utils/SecurityUtils.java +++ b/src/main/java/org/uic/barcode/utils/SecurityUtils.java @@ -24,37 +24,16 @@ public class SecurityUtils { * @return the provider
*/
public static Provider findPublicKeyProvider(String keyAlgorithmOid, byte[] keyBytes) {
-
-
- X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
-
- String name;
- try {
- name = AlgorithmNameResolver.getAlgorithmName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, keyAlgorithmOid, null);
- } catch (Exception e2) {
- return null;
- }
-
- KeyFactory keyFactory = null;
-
+
Provider[] provs = Security.getProviders();
for (Provider provider : provs) {
try {
- keyFactory = KeyFactory.getInstance(name,provider);
- } catch (NoSuchAlgorithmException e1) {
+ PublicKey key = ECKeyEncoder.fromEncoded(keyBytes, keyAlgorithmOid, provider);
+ if (key != null) return provider;
+ } catch (Exception e1) {
//try next
}
- if (keyFactory != null) {
- try {
- keyFactory.generatePublic(keySpec);
- return provider;
- } catch (Exception e) {
- provider = null;
- //try next
- }
- }
}
-
return null;
}
diff --git a/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java b/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java new file mode 100644 index 0000000..3a3f7d2 --- /dev/null +++ b/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java @@ -0,0 +1,168 @@ +package org.uic.barcode.test;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.Before;
+import org.junit.Test;
+import org.uic.barcode.Decoder;
+import org.uic.barcode.Encoder;
+import org.uic.barcode.dynamicFrame.Constants;
+import org.uic.barcode.dynamicFrame.api.IData;
+import org.uic.barcode.logger.LoggerFactory;
+import org.uic.barcode.test.utils.Level2TestDataFactory;
+import org.uic.barcode.test.utils.SimpleUICTestTicket;
+import org.uic.barcode.ticket.EncodingFormatException;
+import org.uic.barcode.ticket.api.spec.IUicRailTicket;
+import org.uic.barcode.utils.ECKeyEncoder;
+import org.uic.barcode.utils.SecurityUtils;
+
+public class DynamicFrameDoubleSignatureCompressedCurveTest {
+
+ public String signatureAlgorithmOID = null;
+ public String elipticCurve = null;
+ public String keyPairAlgorithmOID = null;
+
+ public KeyPair keyPairLevel1 = null;
+ public KeyPair keyPairLevel2 = null;
+
+ public IUicRailTicket testFCBticket = null;
+
+ public Provider provider = null;
+
+
+ @Before public void initialize() {
+
+ LoggerFactory.setActivateConsoleLog(true);
+
+ signatureAlgorithmOID = Constants.ECDSA_SHA256;
+ keyPairAlgorithmOID = Constants.KG_EC_256;
+ elipticCurve = "secp256r1";
+
+ testFCBticket = SimpleUICTestTicket.getUicTestTicket();
+
+ provider = new BouncyCastleProvider();
+ Security.addProvider(new BouncyCastleProvider());
+
+ try {
+ keyPairLevel1 = generateECKeys(keyPairAlgorithmOID, elipticCurve);
+ keyPairLevel2 = generateECKeys(keyPairAlgorithmOID, elipticCurve);
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ assert(keyPairLevel1 != null);
+
+ assert(keyPairLevel2 != null);
+
+ }
+
+
+
+ @Test public void testDynamicHeaderBarcodeDecoding() {
+
+ IUicRailTicket ticket = testFCBticket;
+
+ Encoder enc = null;
+
+ try {
+ enc = new Encoder(ticket, null, Encoder.UIC_BARCODE_TYPE_DOSIPAS, 1, 13);
+ } catch (IOException | EncodingFormatException e1) {
+ assert(false);
+ }
+
+ assert(enc != null);
+
+ try {
+ enc.setLevel1Algs(signatureAlgorithmOID, keyPairAlgorithmOID);
+ enc.setLevel2Algs(signatureAlgorithmOID, keyPairAlgorithmOID,keyPairLevel2.getPublic(), ECKeyEncoder.ENCODING_X962_COMPRESSED);
+ enc.signLevel1("1080", keyPairLevel1.getPrivate(), signatureAlgorithmOID, "1");
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ assert(enc != null);
+
+
+ IData level2Data = Level2TestDataFactory.getLevel2SimpleTestData();
+ try {
+ enc.setLevel2Data(level2Data);
+ enc.signLevel2(keyPairLevel2.getPrivate());
+ } catch (Exception e) {
+ assert(false);
+ }
+
+
+ byte[] encoded = null;
+ try {
+ encoded = enc.encode();
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ assert(encoded != null);
+
+ Decoder dec = null;
+ try {
+ dec = new Decoder(encoded);
+ } catch (IOException e) {
+ assert(false);
+ } catch (EncodingFormatException e) {
+ assert(false);
+ } catch (DataFormatException e) {
+ assert(false);
+ }
+ assert(dec != null);
+
+ int signatureCheck = 0;
+ try {
+ signatureCheck = dec.validateLevel1(keyPairLevel1.getPublic(), null);
+ } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException | IllegalArgumentException
+ | UnsupportedOperationException | IOException | EncodingFormatException e) {
+ assert(false);
+ }
+ assert(signatureCheck == Constants.LEVEL1_VALIDATION_OK);
+
+ signatureCheck = 0;
+ try {
+ signatureCheck = dec.validateLevel2();
+ } catch (Exception e) {
+ assert(false);
+ }
+ assert(signatureCheck == Constants.LEVEL2_VALIDATION_OK);
+
+ IData level2DataDec = dec.getLevel2Data();
+
+ assert(level2Data.getFormat().equals(level2DataDec.getFormat()));
+ assert(Arrays.equals(level2Data.getData(),level2DataDec.getData()));
+
+ SimpleUICTestTicket.compare(ticket, dec.getUicTicket());
+
+ }
+
+
+ public KeyPair generateECKeys(String keyAlgorithmOid, String curve) throws Exception{
+
+ //ECNamedCurveGenParameterSpec namedParamSpec = new ECNamedCurveGenParameterSpec(elipticCurve);
+
+ ECGenParameterSpec namedParamSpec = new ECGenParameterSpec(elipticCurve);
+ KeyPairGenerator ecKPGen = KeyPairGenerator.getInstance("EC", "BC");
+ ecKPGen.initialize(namedParamSpec, new SecureRandom());
+ KeyPair keyPair = ecKPGen.generateKeyPair();
+ KeyPair kp = new KeyPair(SecurityUtils.convert(keyPair.getPublic(), provider),SecurityUtils.convert(keyPair.getPrivate(), provider));
+ return kp;
+ }
+
+
+}
diff --git a/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java new file mode 100644 index 0000000..df8807e --- /dev/null +++ b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java @@ -0,0 +1,227 @@ +package org.uic.barcode.test;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.encoders.Hex;
+import org.junit.Before;
+import org.junit.Test;
+import org.uic.barcode.utils.AlgorithmNameResolver;
+import org.uic.barcode.utils.ECKeyEncoder;
+
+public class ECKeyEncoderTest {
+
+ public static Provider provider = null;
+
+ @Before public void initialize() {
+
+ provider = new BouncyCastleProvider();
+ Security.addProvider(provider);
+ }
+
+ @Test public void testEncodeCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getCompressed(key,name);
+ String compressedHexBC = Hex.toHexString(compressedBC);
+
+ byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_COMPRESSED);
+ String compressedHex = Hex.toHexString(publicKeyBytes);
+
+ if (!compressedHexBC.equals(compressedHex)) {
+ assert(compressedHexBC.equals(compressedHex));
+ }
+
+ assert(Arrays.equals(compressedBC, publicKeyBytes));
+
+ assert(compressedHexBC.equals(compressedHex));
+ }
+ }
+
+ @Test public void testDecodeCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getCompressed(key,name);
+ //String compressedHex = Hex.toHexString(compressedBC);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+ @Test public void testEncodeUnCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ byte[] uncompressedBC = getUnCompressed(key,name);
+ //String uncompressedHex = Hex.toHexString(uncompressedBC);
+
+ byte[] publicKeyUnComp = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_UNCOMPESSED);
+
+ assert(Arrays.equals(uncompressedBC, publicKeyUnComp));
+
+ }
+ }
+
+ @Test public void testDecodeUnCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getUnCompressed(key,name);
+ //String compressedHex = Hex.toHexString(compressedBC);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+ @Test public void testEncodeX509() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ byte[] publicKeyBcX509 = key.getEncoded();
+
+ byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X509);
+ assert(Arrays.equals(publicKeyBcX509, publicKeyBytes));
+
+ }
+ }
+
+ @Test public void testDecodeX509() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp256k1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = key.getEncoded();
+ //String compressedHex = Hex.toHexString(compressedBC);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+
+
+
+ private ECPublicKey createECPublicKey(String name) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
+ ECKeyPairGenerator gen = new ECKeyPairGenerator();
+ SecureRandom secureRandom = new SecureRandom();
+ X9ECParameters secnamecurves = SECNamedCurves.getByName(name);
+ ECDomainParameters ecParams = new ECDomainParameters(secnamecurves.getCurve(), secnamecurves.getG(),
+ secnamecurves.getN(), secnamecurves.getH());
+ ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecParams, secureRandom);
+ gen.init(keyGenParam);
+
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
+ ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1");
+ kpg.initialize(ecGenParameterSpec);
+ ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
+ return key;
+ }
+
+ private byte[] getCompressed(ECPublicKey key, String name) {
+
+ byte[] x = key.getW().getAffineX().toByteArray();
+ byte[] y = key.getW().getAffineY().toByteArray();
+
+ // assumes that x and y are (unsigned) big endian encoded
+ BigInteger xbi = new BigInteger(1, x);
+ BigInteger ybi = new BigInteger(1, y);
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ ECCurve curve = x9.getCurve();
+ ECPoint point = curve.createPoint(xbi, ybi);
+
+ return point.getEncoded(true);
+ }
+
+ private byte[] getUnCompressed(ECPublicKey key, String name) {
+
+ byte[] x = key.getW().getAffineX().toByteArray();
+ byte[] y = key.getW().getAffineY().toByteArray();
+
+ // assumes that x and y are (unsigned) big endian encoded
+ BigInteger xbi = new BigInteger(1, x);
+ BigInteger ybi = new BigInteger(1, y);
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ ECCurve curve = x9.getCurve();
+ ECPoint point = curve.createPoint(xbi, ybi);
+
+ return point.getEncoded(false);
+
+ }
+
+ private void compareKeys(ECPublicKey key1, ECPublicKey key2) {
+
+ assert(key1.getW().getAffineX().equals(key2.getW().getAffineX()) );
+ assert(key1.getW().getAffineY().equals(key2.getW().getAffineY()) );
+
+ }
+
+}
diff --git a/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java new file mode 100644 index 0000000..d70e38e --- /dev/null +++ b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java @@ -0,0 +1,232 @@ +package org.uic.barcode.test;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.encoders.Hex;
+import org.junit.Before;
+import org.junit.Test;
+import org.uic.barcode.utils.AlgorithmNameResolver;
+import org.uic.barcode.utils.ECKeyEncoder;
+
+public class ECKeyEncoderTest521 {
+
+ public static Provider provider = null;
+
+ @Before public void initialize() {
+
+ provider = new BouncyCastleProvider();
+ Security.addProvider(provider);
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+ }
+
+ @Test public void testEncodeCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getCompressed(key,name);
+ String compressedHexBC = Hex.toHexString(compressedBC);
+
+ byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_COMPRESSED);
+ String compressedHex = Hex.toHexString(publicKeyBytes);
+
+ if (!compressedHexBC.equals(compressedHex)) {
+ assert(compressedHexBC.equals(compressedHex));
+ }
+
+ assert(Arrays.equals(compressedBC, publicKeyBytes));
+
+ assert(compressedHexBC.equals(compressedHex));
+ }
+ }
+
+ @Test public void testDecodeCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getCompressed(key,name);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+ @Test public void testEncodeUnCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ byte[] uncompressedBC = getUnCompressed(key,name);
+ //String uncompressedHex = Hex.toHexString(uncompressedBC);
+
+ byte[] publicKeyUnComp = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_UNCOMPESSED);
+
+ if (!Arrays.equals(uncompressedBC, publicKeyUnComp)) {
+ assert(Arrays.equals(uncompressedBC, publicKeyUnComp));
+ }
+
+ assert(Arrays.equals(uncompressedBC, publicKeyUnComp));
+
+ }
+ }
+
+ @Test public void testDecodeUnCompressed() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = getUnCompressed(key,name);
+ //String compressedHex = Hex.toHexString(compressedBC);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+ @Test public void testEncodeX509() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ byte[] publicKeyBcX509 = key.getEncoded();
+
+ byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X509);
+ assert(Arrays.equals(publicKeyBcX509, publicKeyBytes));
+
+ }
+ }
+
+ @Test public void testDecodeX509() throws Exception {
+
+ for (int i = 0; i < 10; i++) {
+
+ String name = "secp521r1";
+
+ AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC");
+
+ ECPublicKey key = createECPublicKey(name);
+
+ // some additional encoding tricks
+ byte[] compressedBC = key.getEncoded();
+ //String compressedHex = Hex.toHexString(compressedBC);
+
+ PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider);
+
+ compareKeys((ECPublicKey) publicKey, key);
+
+ }
+ }
+
+
+
+
+ private ECPublicKey createECPublicKey(String name) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
+ ECKeyPairGenerator gen = new ECKeyPairGenerator();
+ SecureRandom secureRandom = new SecureRandom();
+ X9ECParameters secnamecurves = SECNamedCurves.getByName(name);
+ ECDomainParameters ecParams = new ECDomainParameters(secnamecurves.getCurve(), secnamecurves.getG(),
+ secnamecurves.getN(), secnamecurves.getH());
+ ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecParams, secureRandom);
+ gen.init(keyGenParam);
+
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
+ ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp521r1");
+ kpg.initialize(ecGenParameterSpec);
+ ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic();
+ return key;
+ }
+
+ private byte[] getCompressed(ECPublicKey key, String name) {
+
+ byte[] x = key.getW().getAffineX().toByteArray();
+ byte[] y = key.getW().getAffineY().toByteArray();
+
+ // assumes that x and y are (unsigned) big endian encoded
+ BigInteger xbi = new BigInteger(1, x);
+ BigInteger ybi = new BigInteger(1, y);
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ ECCurve curve = x9.getCurve();
+ ECPoint point = curve.createPoint(xbi, ybi);
+
+ return point.getEncoded(true);
+ }
+
+ private byte[] getUnCompressed(ECPublicKey key, String name) {
+
+ byte[] x = key.getW().getAffineX().toByteArray();
+ byte[] y = key.getW().getAffineY().toByteArray();
+
+ // assumes that x and y are (unsigned) big endian encoded
+ BigInteger xbi = new BigInteger(1, x);
+ BigInteger ybi = new BigInteger(1, y);
+ X9ECParameters x9 = ECNamedCurveTable.getByName(name);
+ ECCurve curve = x9.getCurve();
+ ECPoint point = curve.createPoint(xbi, ybi);
+
+ return point.getEncoded(false);
+
+ }
+
+ private void compareKeys(ECPublicKey key1, ECPublicKey key2) {
+
+ assert(key1.getW().getAffineX().equals(key2.getW().getAffineX()) );
+ assert(key1.getW().getAffineY().equals(key2.getW().getAffineY()) );
+
+ }
+
+}
|