From fc6a4042f7fca1828f0b8e267cfd660e6fe1d40a Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Tue, 22 Nov 2022 14:04:27 +0100 Subject: support for SSB barcodes SSB frame implenmentation including decoding, encoding, signing and verification --- .../java/org/uic/barcode/ssbFrame/SsbFrame.java | 282 +++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java (limited to 'src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java') diff --git a/src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java b/src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java new file mode 100644 index 0000000..b496b17 --- /dev/null +++ b/src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java @@ -0,0 +1,282 @@ +package org.uic.barcode.ssbFrame; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.Provider.Service; +import java.util.Arrays; + + +import org.uic.barcode.ticket.EncodingFormatException; +import org.uic.barcode.utils.AlgorithmNameResolver; +import org.uic.barcode.utils.SecurityUtils; + +public class SsbFrame { + + private SsbHeader header = null; + + private byte[] signaturePart1 = null; + + private byte[] signaturePart2 = null; + + private SsbNonUic nonUicData = null; + + private SsbNonReservation nonReservationData = null; + + private SsbReservation reservationData = null; + + private SsbGroup groupData = null; + + private SsbPass passData = null; + + public void decode(byte[] bytes) throws EncodingFormatException { + + if (bytes.length != 114) { + throw new EncodingFormatException("Data size does not fit to SSB"); + } + + header = new SsbHeader(); + header.decode(bytes); + + if (header.getTicketType().equals(SsbTicketType.UIC_1_IRT_RES_BOA)) { + + reservationData = new SsbReservation(); + reservationData.decode(bytes); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_2_NRT)) { + + nonReservationData = new SsbNonReservation(); + nonReservationData.decode(bytes); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_3_GRP)) { + + groupData = new SsbGroup(); + groupData.decode(bytes); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_4_RPT)) { + + passData = new SsbPass(); + passData.decode(bytes); + + } else { + + nonUicData = new SsbNonUic(); + nonUicData.decode(bytes); + + } + + signaturePart1 = new byte[28]; + signaturePart2 = new byte[28]; + + for (int i = 0 ; i < 28;i++) { + signaturePart1[i] = bytes[59 + i]; + signaturePart2[i] = bytes[59 + 28 + i]; + } + + } + + public byte[] encode() throws EncodingFormatException { + + byte[] bytes = new byte[114]; + + header.encode(bytes); + + if (nonUicData != null) { + nonUicData.encode(bytes); + } else if (nonReservationData != null) { + nonReservationData.encode(bytes); + } else if (reservationData != null) { + reservationData.encode(bytes); + } else if (groupData != null) { + groupData.encode(bytes); + } else if (passData != null) { + passData.encode(bytes); + } else { + throw new EncodingFormatException("Data Content for SSB missing"); + }; + + for (int i = 0 ; i < 28;i++) { + bytes[59 + i] = signaturePart1[i]; + bytes[59 + 28 + i] = signaturePart2[i]; + } + + return bytes; + + } + + public byte[] getDataForSignature() throws EncodingFormatException { + + byte[] bytes = new byte[58]; + + header.encode(bytes); + + if (nonUicData != null) { + nonUicData.encode(bytes); + } else if (nonReservationData != null) { + nonReservationData.encode(bytes); + } else if (reservationData != null) { + reservationData.encode(bytes); + } else if (groupData != null) { + groupData.encode(bytes); + } else if (passData != null) { + passData.encode(bytes); + } else { + throw new EncodingFormatException("Data Content for SSB missing"); + }; + + return bytes; + + } + + public SsbHeader getHeader() { + return header; + } + + public void setHeader(SsbHeader header) { + this.header = header; + } + + public byte[] getSignaturePart1() { + return signaturePart1; + } + + public void setSignaturePart1(byte[] signaturePart1) { + this.signaturePart1 = signaturePart1; + } + + public byte[] getSignaturePart2() { + return signaturePart2; + } + + public void setSignaturePart2(byte[] signaturePart2) { + this.signaturePart2 = signaturePart2; + } + + public SsbNonUic getNonUicData() { + return nonUicData; + } + + public void setNonUicData(SsbNonUic nonUicData) { + this.nonUicData = nonUicData; + } + + public SsbNonReservation getNonReservationData() { + return nonReservationData; + } + + public void setNonReservationData(SsbNonReservation nonReservationData) { + this.nonReservationData = nonReservationData; + } + + public SsbReservation getReservationData() { + return reservationData; + } + + public void setReservationData(SsbReservation reservationData) { + this.reservationData = reservationData; + } + + public SsbGroup getGroupData() { + return groupData; + } + + public void setGroupData(SsbGroup groupData) { + this.groupData = groupData; + } + + public SsbPass getPassData() { + return passData; + } + + public void setPassData(SsbPass passData) { + this.passData = passData; + } + + public void signLevel1(PrivateKey key, Provider prov, String algorithmOid) throws Exception { + + + byte[] data = getDataForSignature(); + + if (prov == null) { + //check for a provider supporting the key + prov = SecurityUtils.findPrivateKeyProvider(key); + } + + //find the algorithm name for the signature OID + String algo = AlgorithmNameResolver.getSignatureAlgorithmName(algorithmOid, prov); + Signature sig = null; + + if (prov != null) { + sig = Signature.getInstance(algo, prov); + } else { + sig = Signature.getInstance(algo); + } + sig.initSign(key); + + sig.update(data); + + byte[] signature = sig.sign(); + + BigInteger[] bInts = SecurityUtils.decodeSignatureIntegerSequence(signature); + + signaturePart1 = toUnsignedBytes(bInts[0]); + + signaturePart2 = toUnsignedBytes(bInts[1]); + + + } + + 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; + } + + /** + * Verify the signature + * + * Note: an appropriate security provider (e.g. BC) must be registered before + * + * @param key the key + * @param singningAlg the Object ID of the signing algorithm + * @param a dedicated security provider to validate the signature + * @return true, if successful + * @throws InvalidKeyException the invalid key exception + * @throws NoSuchAlgorithmException the no such algorithm exception + * @throws SignatureException the signature exception + * @throws IllegalArgumentException the illegal argument exception + * @throws UnsupportedOperationException the unsupported operating exception + * @throws EncodingFormatException + * @throws IOException + */ + public boolean verifyByAlgorithmOid(PublicKey key, String signingAlg, Provider prov) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException { + //find the algorithm name for the signature OID + String algo = null; + Service service = prov.getService("Signature",signingAlg); + if (service != null) { + algo = service.getAlgorithm(); + } + if (algo == null) { + throw new NoSuchAlgorithmException("No service for algorithm found: " + signingAlg); + } + Signature sig = Signature.getInstance(algo); + sig.initVerify(key); + sig.update(getDataForSignature()); + + BigInteger r = new BigInteger(1,signaturePart1); + BigInteger s = new BigInteger(1,signaturePart2); + + byte[] signature = SecurityUtils.encodeSignatureIntegerSequence(r,s); + + return sig.verify(signature); + } +} -- cgit v1.2.3