diff options
Diffstat (limited to 'src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java')
-rw-r--r-- | src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java | 371 |
1 files changed, 371 insertions, 0 deletions
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..b473c1e --- /dev/null +++ b/src/main/java/org/uic/barcode/ssbFrame/SsbFrame.java @@ -0,0 +1,371 @@ +package org.uic.barcode.ssbFrame; + +import java.io.ByteArrayOutputStream; +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.Security; +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 = new SsbHeader(); + + 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"); + } + + if (header == null) { + header = new SsbHeader(); + } + + int offset = 0; + + offset = offset + header.decodeContent(bytes,0); + + if (header.getTicketType().equals(SsbTicketType.UIC_1_IRT_RES_BOA)) { + + reservationData = new SsbReservation(); + offset = offset + reservationData.decodeContent(bytes,offset); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_2_NRT)) { + + nonReservationData = new SsbNonReservation(); + offset = offset + nonReservationData.decodeContent(bytes,offset); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_3_GRP)) { + + groupData = new SsbGroup(); + offset = offset + groupData.decodeContent(bytes, offset); + + } else if (header.getTicketType().equals(SsbTicketType.UIC_4_RPT)) { + + passData = new SsbPass(); + offset = offset + passData.decodeContent(bytes,offset); + + } else { + + nonUicData = new SsbNonUic(); + offset = offset + nonUicData.decodeContent(bytes,offset); + + } + + byte[] signatureBytes = new byte[56]; + + try { + //check for non-standard signature encoding + BigInteger[] bInts = SecurityUtils.decodeSignatureIntegerSequence(signatureBytes); + byte[] sig = SecurityUtils.encodeSignatureIntegerSequence(bInts[0],bInts[1]); + signaturePart1 = bInts[0].toByteArray(); + signaturePart2 = bInts[1].toByteArray(); + //decoding the entire signature was ok, so there was no split + } catch (Exception e) { + //the signature is correctly implemented, continue with recombination + signaturePart1 = new byte[28]; + signaturePart2 = new byte[28]; + + for (int i = 0 ; i < 28;i++) { + signaturePart1[i] = bytes[58 + i]; + signaturePart2[i] = bytes[58 + 28 + i]; + } + } + + + } + + + + + public byte[] encode() throws EncodingFormatException { + + byte[] bytes = new byte[114]; + + int offset = header.encodeContent(bytes,0); + + + + if (nonUicData != null) { + offset = nonUicData.encodeContent(bytes, offset); + } else if (nonReservationData != null) { + offset = nonReservationData.encodeContent(bytes, offset); + } else if (reservationData != null) { + offset = reservationData.encodeContent(bytes, offset); + } else if (groupData != null) { + offset = groupData.encodeContent(bytes, offset); + } else if (passData != null) { + offset = passData.encodeContent(bytes, offset); + } else { + throw new EncodingFormatException("Data Content for SSB missing"); + }; + + + if (signaturePart1.length > 28) { + throw new EncodingFormatException("Signature too large"); + } + if (signaturePart2.length > 28) { + throw new EncodingFormatException("Signature too large"); + } + + for (int i = 1 ; i < 29; i++) { + int sigInd = signaturePart1.length - i; + if (sigInd < signaturePart1.length && sigInd >= 0) { + bytes[58 + 28 - i] = signaturePart1[sigInd]; + } else { + bytes[58 + 28 - i] = '\0'; + } + sigInd = signaturePart2.length - i; + if (sigInd < signaturePart2.length && sigInd >= 0) { + bytes[58 + 28 + 28 - i] = signaturePart2[sigInd]; + } else { + bytes[58 + 28 + 28 - i] = '\0'; + } + } + + + return bytes; + + } + + public byte[] getDataForSignature() throws EncodingFormatException { + + byte[] bytes = new byte[58]; + + int offset = header.encodeContent(bytes,0); + + + if (nonUicData != null) { + offset = nonUicData.encodeContent(bytes, offset); + } else if (nonReservationData != null) { + offset = nonReservationData.encodeContent(bytes, offset); + } else if (reservationData != null) { + offset = reservationData.encodeContent(bytes, offset); + } else if (groupData != null) { + offset = groupData.encodeContent(bytes, offset); + } else if (passData != null) { + offset = passData.encodeContent(bytes, offset); + } 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; + this.nonReservationData = null; + this.reservationData = null; + this.groupData = null; + this.passData = null; + } + + public SsbNonReservation getNonReservationData() { + return nonReservationData; + } + + public void setNonReservationData(SsbNonReservation nonReservationData) { + this.nonReservationData = nonReservationData; + header.setTicketType(SsbTicketType.UIC_2_NRT); + this.reservationData = null; + this.nonUicData = null; + this.groupData = null; + this.passData = null; + } + + public SsbReservation getReservationData() { + return reservationData; + } + + public void setReservationData(SsbReservation reservationData) { + header.setTicketType(SsbTicketType.UIC_1_IRT_RES_BOA); + this.nonReservationData = null; + this.nonUicData = null; + this.groupData = null; + this.passData = null; + this.reservationData = reservationData; + } + + public SsbGroup getGroupData() { + return groupData; + } + + public void setGroupData(SsbGroup groupData) { + this.groupData = groupData; + header.setTicketType(SsbTicketType.UIC_3_GRP); + this.nonReservationData = null; + this.nonUicData = null; + this.reservationData = null; + this.passData = null; + + } + + public SsbPass getPassData() { + return passData; + } + + public void setPassData(SsbPass passData) { + this.passData = passData; + header.setTicketType(SsbTicketType.UIC_4_RPT); + this.nonReservationData = null; + this.nonUicData = null; + this.groupData = null; + this.reservationData = null; + } + + public void signLevel1(PrivateKey key, Provider prov, String keyId, String algorithmOid) throws Exception { + + + this.header.setKeyId(Integer.parseInt(keyId)); + + 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; + + if (prov != null) { + Service service = prov.getService("Signature",signingAlg); + if (service != null) { + algo = service.getAlgorithm(); + } + } else { + Provider[] provs = Security.getProviders(); + for (Provider p : provs) { + if (algo == null) { + Service service = p.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); + } + + +} |