summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/uic/barcode/Decoder.java
blob: 1e0a02d19bfcd42da92ff9bf36c6f82d141db1f5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                               
                               



                                          
                                                              
                                               
                                                           



                                                       
                                          


                                                    
                                                                     


                                                       
                                            











                                                      
                                                   



                                                


                                          











                                                          
                                                 
         








                                                                   









                                                                                                        




                                                                              















                                                                                     
                       
            
                                                                                                                                                                                                                           
                                                                  














                                                                                     
                       
            
                                                                                                                                                                                                                                              
                                                                         

          















                                                                                                                                                                                                                                                                 
                                                                     
                                                                            









                                                                                       
                                                                                     





                                                                                          
                                                                 

          



                                                     
                                            
                       
            
                                                                     
                                                        
          





                                                                                                                
                                                                                  
                                                                     
                                                                   




                                                                         











                                                                                                           







                                                              
                                  






                                                                                           
                          
                                         
                                                  




                                                         
                          











                                                                                                   
                         






                                                                                                      


                          


















                                                                                                                       
 






                                                                                                                    













                                                                                                     





                                                  
                                          





                                     















                                               
         




                                      
                                                 



                                     










                                                         



                                                       
                                                                    




















                                                              
                                       
                                                                                                             
                                                                             



                             
                                                                                           
                                                                     






                                                                             
         









                                                                                         
         












                                                                                                   









                                                     

         
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;
	}
	
	
	
}