package org.uic.barcode; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.Provider; 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.api.DynamicFrameCoder; import org.uic.barcode.dynamicFrame.api.IData; import org.uic.barcode.dynamicFrame.api.IDynamicFrame; import org.uic.barcode.dynamicFrame.api.ILevel1Data; import org.uic.barcode.dynamicFrame.api.ILevel2Data; import org.uic.barcode.ssbFrame.SsbFrame; import org.uic.barcode.staticFrame.StaticFrame; import org.uic.barcode.staticFrame.UFLEXDataRecord; import org.uic.barcode.staticFrame.UTLAYDataRecord; 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.SecurityUtils; /** * The Class Decoder. * * signature validation and decoding of UIC bar codes * */ public class Decoder { /** The dynamic frame. */ private IDynamicFrame dynamicFrame = null; /** The static frame. */ private StaticFrame staticFrame = null; /** The ssb frame. */ private SsbFrame ssbFrame = null; /** The uic ticket coder. */ private UicRailTicketCoder uicTicketCoder = null; /** The uic ticket. */ private IUicRailTicket uicTicket = null; /** The layout. */ private TicketLayout layout = null; /** The data. */ byte[] data = null; private Provider defaultProvider = null; public Provider getDefaultProvider() { return defaultProvider; } public void setDefaultProvider(Provider defaultProvider) { this.defaultProvider = defaultProvider; } /** * Instantiates a new decoder. * * @param data the data * @throws IOException Signals that an I/O exception has occurred. * @throws EncodingFormatException the encoding format exception * @throws DataFormatException the data format exception */ public Decoder (byte[] data) throws IOException, EncodingFormatException, DataFormatException { this.data = data; if (defaultProvider == null) { defaultProvider = SecurityUtils.getDefaultProvider(); } decode(data); } /** * Validate level 1. * * @param key the public key * @param signingAlg the signing algorithm OID * @return the return code indicating errors * @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 operation exception * @throws IOException Signals that an I/O exception has occurred. * @throws EncodingFormatException the encoding format exception * @deprecated */ public int validateLevel1(PublicKey key) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException { return validateLevel1(key,null, defaultProvider); } /** * Validate level 1. * * @param key the public key * @param signingAlg the signing algorithm OID * @return the return code indicating errors * @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 operation exception * @throws IOException Signals that an I/O exception has occurred. * @throws EncodingFormatException the encoding format exception * @deprecated */ public int validateLevel1(PublicKey key, String signingAlg) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException { return validateLevel1(key, signingAlg, defaultProvider); } /** * Validate level 1. * * @param key the public key * @param signingAlg the signing algorithm OID * @param security provider in case a dedicated provider must be used (otherwise null) * @return the return code indicating errors * @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 operation exception * @throws IOException Signals that an I/O exception has occurred. * @throws EncodingFormatException the encoding format exception */ public int validateLevel1(PublicKey key, String signingAlg, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IllegalArgumentException, UnsupportedOperationException, IOException, EncodingFormatException { if (!isStaticHeader(data) && dynamicFrame != null) { return dynamicFrame.validateLevel1(key, provider) ; } else if (isSsbFrame(data) && ssbFrame != null) { if (ssbFrame.verifyByAlgorithmOid(key,signingAlg, provider)) { return Constants.LEVEL1_VALIDATION_OK; } else { return Constants.LEVEL1_VALIDATION_FRAUD; } } else if (staticFrame != null) { // guess the signature algorithm based on the signature size if (staticFrame.verifyByAlgorithmOid(key,signingAlg, provider)) { return Constants.LEVEL1_VALIDATION_OK; } else { return Constants.LEVEL1_VALIDATION_FRAUD; } } return Constants.LEVEL1_VALIDATION_NO_SIGNATURE; } /** * Validate level 2. * * @return the return code indicating errors * @throws EncodingFormatException * @deprecated */ public int validateLevel2() throws EncodingFormatException { return validateLevel2(defaultProvider); } /* * Validate level 2. * @param prov - provider of the java security implementation in case a dedicated provider must be used * @return the return code indicating errors */ public int validateLevel2(Provider prov) throws EncodingFormatException { if (!isStaticHeader(data) && dynamicFrame != null) { return dynamicFrame.validateLevel2(prov) ; } else { return Constants.LEVEL2_VALIDATION_NO_SIGNATURE; } } /** * Decode. * * @param data the byte array raw data * @throws IOException Signals that an I/O exception has occurred. * @throws EncodingFormatException the encoding format exception * @throws DataFormatException the data format exception */ public void decode(byte[] data) throws IOException, EncodingFormatException, DataFormatException { if (!isStaticHeader(data)) { try { decodeDynamicFrame(data); } catch (Exception e) { dynamicFrame = null; if (isSsbFrame(data)) { decodeSsbFrame(data); } else { throw e; } } catch (AssertionError e) { dynamicFrame = null; if (isSsbFrame(data)) { decodeSsbFrame(data); } else { throw new EncodingFormatException(e.getMessage()); } } } else if (isStaticHeader(data)){ try { decodeStaticFrame(data); } catch (Exception e) { staticFrame = null; throw e; } } } private void decodeDynamicFrame(byte[] data) throws EncodingFormatException, IOException { dynamicFrame = DynamicFrameCoder.decode(data); ILevel2Data level2 = dynamicFrame.getLevel2Data(); ILevel1Data level1 = level2.getLevel1Data(); for (IData level1Content : level1.getData()) { uicTicketCoder = new UicRailTicketCoder(); if (level1Content.getFormat().equals("FCB1")) { uicTicket = uicTicketCoder.decodeFromAsn(level1Content.getData(), 1); } else if (level1Content.getFormat().equals("FCB2")) { uicTicket = uicTicketCoder.decodeFromAsn(level1Content.getData(), 2); } else if (level1Content.getFormat().equals("FCB3")) { uicTicket = uicTicketCoder.decodeFromAsn(level1Content.getData(), 3); } } } private void decodeStaticFrame(byte[] data) throws EncodingFormatException, DataFormatException, IOException { staticFrame = new StaticFrame(); staticFrame.decode(data); UFLEXDataRecord flex = staticFrame.getuFlex(); if (flex != null) { uicTicket = flex.getTicket(); } UTLAYDataRecord tlay = staticFrame.getuTlay(); if (tlay != null) { layout = tlay.getLayout(); } } private void decodeSsbFrame(byte[] data) throws EncodingFormatException, DataFormatException, IOException { ssbFrame = new SsbFrame(); ssbFrame.decode(data); } /** * Checks if is static header. * * @param data the data * @return true, if is static header */ private boolean isStaticHeader(byte[] data) { byte[] start = "#UT".getBytes(); if (start[0] != data[0] || start[1]!= start[1] || start[2] != data[2]) return false; return true; } /** * Checks if is ssb frame. * * @param data the data * @return true, if is static header */ private boolean isSsbFrame(byte[] data) { if (data.length == 114) { return true; } return false; } /** * Gets the uic ticket. * * @return the uic ticket */ public IUicRailTicket getUicTicket() { return uicTicket; } /** * Gets the layout. * * @return the layout */ public TicketLayout getLayout() { return layout; } /** * Gets the dynamic header. * * @return the dynamic header */ public IDynamicFrame getDynamicFrame() { return dynamicFrame; } /** * 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 */ public void setDynamicHeader(IDynamicFrame dynamicHeader) { this.dynamicFrame = dynamicHeader; } /** * Gets the static frame. * * @return the static frame */ public StaticFrame getStaticFrame() { return staticFrame; } /** * Sets the static frame. * * @param staticFrame the new static frame */ public void setStaticFrame(StaticFrame staticFrame) { this.staticFrame = staticFrame; } public IData getLevel2Data() { if (!isStaticHeader(data) && dynamicFrame != null && dynamicFrame.getLevel2Data() != null) { return dynamicFrame.getLevel2Data().getLevel2Data(); } return null; } public byte[] getEncodedLevel1Data() throws IOException, EncodingFormatException { if (!isStaticHeader(data) && dynamicFrame != null) { return dynamicFrame.getLevel1DataBin(); } else if (staticFrame != null) { return staticFrame.getDataForSignature(); } else { throw new EncodingFormatException("Unknown Header"); } } public byte[] getLevel1Signature() throws IOException, EncodingFormatException { if (!isStaticHeader(data)) { return dynamicFrame.getLevel2Data().getLevel1Signature(); } else if (staticFrame != null) { return staticFrame.getDataForSignature(); } else { throw new EncodingFormatException("Unknown Header"); } } public String getLevel1KeyId() throws EncodingFormatException { if (dynamicFrame != null && dynamicFrame.getLevel2Data() != null && dynamicFrame.getLevel2Data().getLevel1Data() != null) { return dynamicFrame.getLevel2Data().getLevel1Data().getKeyId().toString(); } else if (staticFrame != null) { return staticFrame.getSignatureKey(); } else { throw new EncodingFormatException("Unknown Header"); } } public SsbFrame getSsbFrame() { return ssbFrame; } public void setSsbFrame(SsbFrame ssbFrame) { this.ssbFrame = ssbFrame; } }