summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCGantert345 <57003061+CGantert345@users.noreply.github.com>2021-12-16 16:13:13 +0100
committerCGantert345 <57003061+CGantert345@users.noreply.github.com>2021-12-16 16:13:13 +0100
commitbdb54c653eda54b003e50460928cfd8bbc80bc44 (patch)
tree1ccaa3af3fb8fcf2319fac438585eb0219c52905
parentapi layer for dynamic content (diff)
downloadUIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar.gz
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar.bz2
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar.lz
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar.xz
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.tar.zst
UIC-barcode-bdb54c653eda54b003e50460928cfd8bbc80bc44.zip
-rw-r--r--src/main/java/org/uic/barcode/Decoder.java12
-rw-r--r--src/main/java/org/uic/barcode/Encoder.java18
-rw-r--r--src/main/java/org/uic/barcode/dynamicContent/api/DynamicContentCoder.java4
-rw-r--r--src/main/java/org/uic/barcode/dynamicContent/fdc1/TimeStamp.java7
-rw-r--r--src/main/java/org/uic/barcode/dynamicFrame/DynamicFrame.java94
-rw-r--r--src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java230
-rw-r--r--src/test/java/org/uic/barcode/test/TimeStampTest.java36
-rw-r--r--src/test/java/org/uic/barcode/test/utils/DynamicTestContent.java38
8 files changed, 436 insertions, 3 deletions
diff --git a/src/main/java/org/uic/barcode/Decoder.java b/src/main/java/org/uic/barcode/Decoder.java
index 9f102d3..4c8b044 100644
--- a/src/main/java/org/uic/barcode/Decoder.java
+++ b/src/main/java/org/uic/barcode/Decoder.java
@@ -8,6 +8,7 @@ import java.security.PublicKey;
import java.security.SignatureException;
import java.util.zip.DataFormatException;
+import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
import org.uic.barcode.dynamicFrame.Constants;
import org.uic.barcode.dynamicFrame.DataType;
import org.uic.barcode.dynamicFrame.DynamicFrame;
@@ -238,6 +239,17 @@ public class Decoder {
}
/**
+ * Gets the dynamic content.
+ *
+ * @return the dynamic header
+ */
+ public IUicDynamicContent getDynamicContent() {
+ if (dynamicFrame == null) return null;
+
+ return dynamicFrame.getDynamicContent();
+ }
+
+ /**
* Sets the dynamic header.
*
* @param dynamicHeader the new dynamic header
diff --git a/src/main/java/org/uic/barcode/Encoder.java b/src/main/java/org/uic/barcode/Encoder.java
index f0f8d14..3b30e8a 100644
--- a/src/main/java/org/uic/barcode/Encoder.java
+++ b/src/main/java/org/uic/barcode/Encoder.java
@@ -6,6 +6,7 @@ import java.security.Provider;
import java.security.PublicKey;
import org.uic.barcode.asn1.datatypesimpl.OctetString;
+import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
import org.uic.barcode.dynamicContent.fdc1.UicDynamicContentDataFDC1;
import org.uic.barcode.dynamicFrame.Constants;
import org.uic.barcode.dynamicFrame.DataType;
@@ -178,6 +179,15 @@ public class Encoder {
}
}
+ public void setDynamicData(IUicDynamicContent content) throws EncodingFormatException {
+ if (dynamicFrame != null) {
+ if (dynamicFrame.getLevel2SignedData() == null) {
+ dynamicFrame.setLevel2SignedData(new Level2DataType());
+ }
+ dynamicFrame.addDynamicContent(content);
+ }
+ }
+
public void setLevel2Data(DataType level2data) {
if (dynamicFrame != null) {
if (dynamicFrame.getLevel2SignedData() == null) {
@@ -203,6 +213,14 @@ public class Encoder {
return null;
}
+
+ public IUicDynamicContent getDynamicContent() {
+ if (dynamicFrame != null && dynamicFrame.getLevel2SignedData() != null) {
+ return dynamicFrame.getDynamicContent();
+ }
+ return null;
+ }
+
public UicDynamicContentDataFDC1 getDynamicContentDataUIC1() {
if (dynamicFrame != null && dynamicFrame.getLevel2SignedData() != null) {
return dynamicFrame.getDynamicDataFDC1();
diff --git a/src/main/java/org/uic/barcode/dynamicContent/api/DynamicContentCoder.java b/src/main/java/org/uic/barcode/dynamicContent/api/DynamicContentCoder.java
index d8bf3b4..34406e0 100644
--- a/src/main/java/org/uic/barcode/dynamicContent/api/DynamicContentCoder.java
+++ b/src/main/java/org/uic/barcode/dynamicContent/api/DynamicContentCoder.java
@@ -26,9 +26,11 @@ import org.uic.barcode.ticket.api.utils.UicEncoderUtils;
public class DynamicContentCoder {
+ public static String dynamicContentDataFDC1 = "FDC1";
+
public static byte[] encode(IUicDynamicContent content, String format) throws EncodingFormatException {
- if (format != null && !format.equals("FDC1")) {
+ if (format != null && !format.equals(dynamicContentDataFDC1)) {
throw new EncodingFormatException("Format of dynamic content not supported!");
}
diff --git a/src/main/java/org/uic/barcode/dynamicContent/fdc1/TimeStamp.java b/src/main/java/org/uic/barcode/dynamicContent/fdc1/TimeStamp.java
index ecbb226..a1b9581 100644
--- a/src/main/java/org/uic/barcode/dynamicContent/fdc1/TimeStamp.java
+++ b/src/main/java/org/uic/barcode/dynamicContent/fdc1/TimeStamp.java
@@ -91,8 +91,11 @@ public class TimeStamp {
this.secondOfDay = time;
}
+
+
+
/**
- * Gets the time.
+ * Gets the current date and time in UTC
*
* @return the date and time of content creation in UTC
*/
@@ -136,4 +139,6 @@ public class TimeStamp {
}
+
+
}
diff --git a/src/main/java/org/uic/barcode/dynamicFrame/DynamicFrame.java b/src/main/java/org/uic/barcode/dynamicFrame/DynamicFrame.java
index c74215d..eb26729 100644
--- a/src/main/java/org/uic/barcode/dynamicFrame/DynamicFrame.java
+++ b/src/main/java/org/uic/barcode/dynamicFrame/DynamicFrame.java
@@ -18,10 +18,14 @@ import org.uic.barcode.asn1.datatypes.RestrictedString;
import org.uic.barcode.asn1.datatypes.Sequence;
import org.uic.barcode.asn1.datatypesimpl.OctetString;
import org.uic.barcode.asn1.uper.UperEncoder;
+import org.uic.barcode.dynamicContent.api.DynamicContentCoder;
+import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
import org.uic.barcode.dynamicContent.fdc1.UicDynamicContentDataFDC1;
+import org.uic.barcode.ticket.EncodingFormatException;
import org.uic.barcode.utils.AlgorithmNameResolver;
+// TODO: Auto-generated Javadoc
/**
* The DynamicHeader for bar codes
*
@@ -30,6 +34,9 @@ import org.uic.barcode.utils.AlgorithmNameResolver;
@Sequence
public class DynamicFrame extends Object{
+ /**
+ * Instantiates a new dynamic frame.
+ */
public DynamicFrame() {}
/** The format. */
@@ -37,12 +44,13 @@ public class DynamicFrame extends Object{
@RestrictedString(CharacterRestriction.IA5String)
public String format;
+ /** The level 2 signed data. */
/*level 2 data*/
@FieldOrder(order = 1)
Level2DataType level2SignedData;
- /** The signature of level 2 data*/
+ /** The signature of level 2 data. */
@FieldOrder(order = 2)
@Asn1Optional public OctetString level2Signature;
@@ -64,18 +72,38 @@ public class DynamicFrame extends Object{
this.format = format;
}
+ /**
+ * Gets the level 2 signed data.
+ *
+ * @return the level 2 signed data
+ */
public Level2DataType getLevel2SignedData() {
return level2SignedData;
}
+ /**
+ * Sets the level 2 signed data.
+ *
+ * @param level2SignedData the new level 2 signed data
+ */
public void setLevel2SignedData(Level2DataType level2SignedData) {
this.level2SignedData = level2SignedData;
}
+ /**
+ * Gets the level 2 signature.
+ *
+ * @return the level 2 signature
+ */
public OctetString getLevel2Signature() {
return level2Signature;
}
+ /**
+ * Sets the level 2 signature.
+ *
+ * @param level2Signature the new level 2 signature
+ */
public void setLevel2Signature(OctetString level2Signature) {
this.level2Signature = level2Signature;
}
@@ -108,6 +136,7 @@ public class DynamicFrame extends Object{
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
+ * @return the int
*/
public int validateLevel2() {
@@ -120,6 +149,8 @@ public class DynamicFrame extends Object{
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
+ * @param prov the prov
+ * @return the int
*/
public int validateLevel2(Provider prov) {
@@ -213,6 +244,9 @@ public class DynamicFrame extends Object{
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
+ * @param key the key
+ * @param prov the prov
+ * @return the int
*/
public int validateLevel1(PublicKey key, Provider prov) {
@@ -282,6 +316,8 @@ public class DynamicFrame extends Object{
*
* Note: an appropriate security provider (e.g. BC) must be registered before
*
+ * @param key the key
+ * @return the int
*/
public int validateLevel1(PublicKey key) {
@@ -289,6 +325,12 @@ public class DynamicFrame extends Object{
}
+ /**
+ * Sign level 2 data without a specific security provider.
+ *
+ * @param key the key
+ * @throws Exception the exception
+ */
public void signLevel2(PrivateKey key) throws Exception {
//find the algorithm name for the signature OID
@@ -302,6 +344,13 @@ public class DynamicFrame extends Object{
}
+ /**
+ * Sign level 2 data.
+ *
+ * @param key the key
+ * @param prov the security Provider
+ * @throws Exception the exception
+ */
public void signLevel2(PrivateKey key, Provider prov) throws Exception {
//find the algorithm name for the signature OID
@@ -315,10 +364,53 @@ public class DynamicFrame extends Object{
}
+ /**
+ * Adds the dynamic content and encodes it. (API level)
+ *
+ * @param content the dynamic content
+ * @throws EncodingFormatException the encoding format exception
+ */
+ public void addDynamicContent(IUicDynamicContent content) throws EncodingFormatException {
+
+
+ this.getLevel2SignedData().setLevel2Data(new DataType());
+
+ this.getLevel2SignedData().getLevel2Data().setFormat(DynamicContentCoder.dynamicContentDataFDC1);
+
+ this.getLevel2SignedData().getLevel2Data().setByteData(DynamicContentCoder.encode(content, DynamicContentCoder.dynamicContentDataFDC1));
+
+ }
+
+ /**
+ * Adds the level 2 dynamic data. (ASN level)
+ *
+ * @param dynamicData the dynamic data
+ */
public void addLevel2DynamicData(UicDynamicContentDataFDC1 dynamicData) {
this.getLevel2SignedData().setLevel2Data( dynamicData.getDataType());
}
+ /**
+ * Gets the dynamic content.
+ *
+ * @return the dynamic content
+ */
+ public IUicDynamicContent getDynamicContent() {
+
+ if (this.getLevel2SignedData() == null ||
+ this.getLevel2SignedData().getLevel2Data() == null){
+ return null;
+ }
+
+ return DynamicContentCoder.decode(this.getLevel2SignedData().getLevel2Data().getByteData());
+
+ }
+
+ /**
+ * Gets the dynamic data FDC 1.
+ *
+ * @return the dynamic data FDC 1
+ */
public UicDynamicContentDataFDC1 getDynamicDataFDC1() {
if (this.getLevel2SignedData() == null ||
diff --git a/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java b/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java
new file mode 100644
index 0000000..5a70841
--- /dev/null
+++ b/src/test/java/org/uic/barcode/test/DynamicFrameDynamicContentApiTest.java
@@ -0,0 +1,230 @@
+package org.uic.barcode.test;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.zip.DataFormatException;
+
+import org.bouncycastle.jce.ECNamedCurveTable;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.junit.Before;
+import org.junit.Test;
+import org.uic.barcode.Decoder;
+import org.uic.barcode.Encoder;
+import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
+import org.uic.barcode.dynamicFrame.Constants;
+import org.uic.barcode.test.utils.DynamicTestContent;
+import org.uic.barcode.test.utils.SimpleUICTestTicket;
+import org.uic.barcode.ticket.EncodingFormatException;
+import org.uic.barcode.ticket.api.spec.IUicRailTicket;
+
+public class DynamicFrameDynamicContentApiTest {
+
+ public String signatureAlgorithmOID = null;
+ public String elipticCurve = null;
+ public String keyPairAlgorithmOID = null;
+
+ public KeyPair keyPairLevel1 = null;
+ public KeyPair keyPairLevel2 = null;
+
+ public byte[] passIdHash = "PassId".getBytes();
+ public byte[] phoneIdHash = "myPhone".getBytes();
+
+
+ public IUicRailTicket testFCBticket = null;
+
+
+ @Before public void initialize() {
+
+ signatureAlgorithmOID = Constants.ECDSA_SHA256;
+ keyPairAlgorithmOID = Constants.KG_EC_256;
+ elipticCurve = "secp256k1";
+
+ testFCBticket = SimpleUICTestTicket.getUicTestTicket();
+
+ 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 testDynamicContentEncoding() {
+
+ 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);
+
+ enc.setLevel2Algs(signatureAlgorithmOID, keyPairAlgorithmOID, keyPairLevel2.getPublic());
+
+ try {
+ enc.signLevel1("1080", keyPairLevel1.getPrivate(), signatureAlgorithmOID, "1");
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ try {
+ enc.setDynamicData(DynamicTestContent.createDynamicTestContent());
+ enc.signLevel2(keyPairLevel2.getPrivate());
+
+ } catch (Exception e) {
+ assert(false);
+ }
+
+
+ byte[] encoded = null;
+ try {
+ encoded = enc.encode();
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ assert(encoded != null);
+
+
+
+ }
+
+ @Test public void testDynamicContentDecoding() {
+
+ 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);
+
+ enc.setLevel2Algs(signatureAlgorithmOID, keyPairAlgorithmOID, keyPairLevel2.getPublic());
+
+ try {
+ enc.signLevel1("1080", keyPairLevel1.getPrivate(), signatureAlgorithmOID, "1");
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ try {
+ enc.setDynamicData(DynamicTestContent.createDynamicTestContent());
+ 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);
+
+ SimpleUICTestTicket.compare(ticket, dec.getUicTicket());
+
+ int level2check = 0;
+ try {
+ level2check = dec.validateLevel2();
+ } catch (Exception e) {
+ assert(false);
+ }
+
+ assert(level2check == Constants.LEVEL2_VALIDATION_OK);
+
+ IUicDynamicContent dynamicData = dec.getDynamicContent();
+
+ assert(dynamicData.getChallengeString().equals("CHALLENGE"));
+
+ assert(dynamicData.getAppId().equals("MyApp"));
+
+ assert(Arrays.equals(dynamicData.getPassIdHash(),passIdHash));
+
+ assert(Arrays.equals(dynamicData.getPhoneIdHash(),phoneIdHash));
+
+ assert(dynamicData.getGeoCoordinate().getLatitude() == 123456L);
+ assert(dynamicData.getGeoCoordinate().getLongitude() == 23456L);
+
+ Date timeStamp = dynamicData.getTimeStamp();
+ ZonedDateTime retrievedTimeStamp = timeStamp.toInstant().atZone(ZoneId.of("UTC"));
+ ZonedDateTime originalTimeStamp = ZonedDateTime.now(ZoneId.of("UTC"));
+ long diff = ChronoUnit.SECONDS.between(originalTimeStamp, retrievedTimeStamp);
+
+ assert(diff > -50 && diff < 50);
+ }
+
+ public KeyPair generateECDSAKeys(String keyAlgorithmName, String paramName) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException{
+ ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(paramName);
+ KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithmName, "BC");
+ g.initialize(ecSpec, new SecureRandom());
+ return g.generateKeyPair();
+ }
+
+ public KeyPair generateECKeys(String keyAlgorithmOid, String curve) throws Exception{
+
+ String keyAlgorithmName = "ECDSA";
+ ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(curve);
+ KeyPairGenerator g = KeyPairGenerator.getInstance(keyAlgorithmName, "BC");
+ g.initialize(ecSpec, new SecureRandom());
+ return g.generateKeyPair();
+ }
+
+
+}
diff --git a/src/test/java/org/uic/barcode/test/TimeStampTest.java b/src/test/java/org/uic/barcode/test/TimeStampTest.java
new file mode 100644
index 0000000..b2e3ab1
--- /dev/null
+++ b/src/test/java/org/uic/barcode/test/TimeStampTest.java
@@ -0,0 +1,36 @@
+package org.uic.barcode.test;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.junit.Test;
+import org.uic.barcode.dynamicContent.fdc1.TimeStamp;
+
+public class TimeStampTest {
+
+
+
+ @Test public void testDateConversion() {
+
+
+ TimeStamp ts = new TimeStamp();
+
+ ts.setDay(10L);
+ ts.setTime(6000L);
+
+ Date date = ts.getTimeAsDate();
+
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ cal.setTime(date);
+ long seconds = cal.get(Calendar.SECOND);
+ seconds = seconds + cal.get(Calendar.MINUTE) * 60;
+ seconds = seconds + cal.get(Calendar.HOUR_OF_DAY) * 60 * 60;
+
+ assert(seconds == 6000L);
+
+
+ }
+
+
+}
diff --git a/src/test/java/org/uic/barcode/test/utils/DynamicTestContent.java b/src/test/java/org/uic/barcode/test/utils/DynamicTestContent.java
new file mode 100644
index 0000000..a39b270
--- /dev/null
+++ b/src/test/java/org/uic/barcode/test/utils/DynamicTestContent.java
@@ -0,0 +1,38 @@
+package org.uic.barcode.test.utils;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+import org.uic.barcode.dynamicContent.api.IUicDynamicContent;
+import org.uic.barcode.dynamicContent.api.SimpleUicDynamicContent;
+import org.uic.barcode.ticket.api.impl.SimpleGeoCoordinate;
+import org.uic.barcode.ticket.api.spec.IGeoCoordinate;
+
+public class DynamicTestContent {
+
+ public static byte[] passIdHash = "PassId".getBytes();
+ public static byte[] phoneIdHash = "myPhone".getBytes();
+
+
+ public static IUicDynamicContent createDynamicTestContent() {
+
+ IUicDynamicContent dc = new SimpleUicDynamicContent();
+ dc.setChallengeString("CHALLENGE");
+ dc.setAppId("MyApp");
+ dc.setPhoneIdHash(phoneIdHash);
+ dc.setPassIdHash(passIdHash);
+
+ ZonedDateTime timeStamp = ZonedDateTime.now(ZoneId.of("UTC"));
+
+ dc.setTimeStamp(Date.from(timeStamp.toInstant()));
+
+ IGeoCoordinate geo = new SimpleGeoCoordinate();
+ geo.setLatitude(123456L);
+ geo.setLongitude(23456L);
+ dc.setGeoCoordinate(geo);
+
+ return dc;
+ }
+
+}