xerdecoder.java

来自「JAVA的加密库之一」· Java 代码 · 共 769 行 · 第 1/2 页

JAVA
769
字号
/* $Id: XerDecoder.java,v 1.1.1.1 2001/02/24 04:59:00 raif Exp $
 *
 * Copyright (C) 1997-2001 The Cryptix Foundation Limited. All rights reserved.
 *
 * Use, modification, copying and distribution of this software is subject to
 * the terms and conditions of the Cryptix General Licence. You should have
 * received a copy of the Cryptix General Licence along with this library; if
 * not, you can download a copy from http://www.cryptix.org/
 */
package cryptix.asn1.encoding;

import cryptix.asn1.io.*;
import cryptix.asn1.lang.*;

import org.apache.log4j.Category;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.InputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.TimeZone;

/**
 * A class to decode ASN.1 specifications according to the XML Encoding Rules.<p>
 *
 * @version $Revision: 1.1.1.1 $
 * @author  Raif S. Naffah
 */
public class XerDecoder extends ASNReader {

	// Constants and vars
	// ........................................................................

	static Category cat = Category.getInstance(DerDecoder.class.getName());

    /**
     * The underlying input stream that supports mark() and reset().
     */
	BufferedInputStream in;

	// Constructor(s)
	// ........................................................................

    /**
     * Trivial constructor for use by the Factory.
     */
	public XerDecoder() {
   		super();
	}

    /**
     * Private constructor for internal use.
     *
     * @param ba a byte array to become the underlying stream of the decoder.
	 */
	private XerDecoder(byte[] ba) {
		this.in = new BufferedInputStream(new ByteArrayInputStream(ba), 10240);
	}

	// Class method(s)
	// ........................................................................

   /**
    * A class method to compare similarity between 2 Tag instances. The
    * comparison works on the Tag's class and value fields.
    *
    * @param tClass the tag's actual (read) class field.
    * @param tValue the tag's actual (read) value field.
    * @param xClass the expected tag's class field.
    * @param xValue the expected tag's value field.
    */
	private static final boolean
	eval(int tClass, int xClass, int tValue, int xValue) {
		cat.info("Comparing ["+tClass+", "+tValue+"] to ["+xClass+", "+xValue+"]");

		if (tClass != xClass)
			return (false);

		if (tClass == Tag.APPLICATION || tClass == Tag.PRIVATE)
			return (tValue == xValue);

		if (tValue == xValue)
			return (true);

		if (xValue > 0x20) // compare unstructured values
			xValue -= 0x20;

		// equate PrintableString, IA5String and T61_STRING
		if (xValue == Tag.PrintableString
				|| xValue == Tag.IA5_STRING
				|| xValue == Tag.T61_STRING)
			return (tValue == Tag.PrintableString
					|| tValue == Tag.IA5_STRING
					|| tValue == Tag.T61_STRING);

		// equate SEQUENCE, SEQUENCE OF, SET and SET OF
		if (xValue == Tag.SEQUENCE
				|| xValue == Tag.SEQUENCE_OF
				|| xValue == Tag.SET
				|| xValue == Tag.SET_OF)
			return (tValue == Tag.SEQUENCE
					|| tValue == Tag.SEQUENCE_OF
					|| tValue == Tag.SET
					|| tValue == Tag.SET_OF);

		return (false);
	}

	private static final Date toDate(byte[] buffer) throws DerFormatException {
		Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
		int YY = (buffer[0]-'0')*10 + (buffer[1]-'0');
		int MM = (buffer[2]-'0')*10 + (buffer[3]-'0') - 1;
		int DD = (buffer[4]-'0')*10 + (buffer[5]-'0');
		int hh = (buffer[6]-'0')*10 + (buffer[7]-'0');
		int mm = (buffer[8]-'0')*10 + (buffer[9]-'0');
		int ss = 0;
		YY += YY <= 50 ? 2000 : 1900; // fails for 2051 and later
		if (buffer[10] != 'Z') {
			ss = (buffer[10]-'0')*10 + (buffer[11]-'0');
			if (buffer[12] != 'Z')
				throw new DerFormatException(Tag.UTC_TIME);
		}

		cal.set(YY, MM, DD, hh, mm, ss);
		return (cal.getTime());
	}

	private static final String toOID(byte[] buffer) {
		StringBuffer sb = new StringBuffer();
		int length = buffer.length;
		int i = 0;
		if (--length >= 0) { // first byte is special
			int b      = buffer[i++] & 0xFF;
			int first  = (b < 40 ? 0 : (b < 80 ? 1 : 2));
			int second = (b - first * 40);
			sb.append(first).append(".").append(second);
		}

		while (length > 0) { // handle the rest
			sb.append(".");
			int sid = 0; // subid
			int b;
			do {
				b = buffer[i++] & 0xFF;
				sid = sid << 7 | (b & 0x7F);
			} while (--length > 0 && (b & 0x80) == 0x80);

			sb.append(sid);
		}

		String result = sb.toString();
		return (result);
	}

	private static final Boolean toBoolean(byte[] buffer)
	throws DerInvalidLengthException  {
		int length = buffer.length;
		if (length != 1)
			throw new DerInvalidLengthException(Tag.BOOLEAN, length, 1);

		Boolean result = new Boolean(buffer[0] != 0x00);
		return (result);
	}

	private static final void toNull(byte[] buffer)
	throws DerInvalidLengthException {
		int length = buffer.length;
		if (length != 0)
			throw new DerInvalidLengthException(Tag.NULL, length, 0);
	}

	// ASN1InputStream abstract methods implementation
	// ........................................................................

	/**
	 * Initialises this instance to decode from the designated input stream.
	 *
	 * @param is the designated input stream to decode.
	 * @exception IllegalStateException if this instance is already initialised
	 * with an input stream. Caller should close the previous stream before
	 * invoking this method again on a new input stream.
	 */
	public void open(InputStream is) {
		if (in != null)
      		throw new IllegalStateException();

		this.in = is instanceof BufferedInputStream
      		? (BufferedInputStream) is
            : new BufferedInputStream(is, 10240);
	}

	/**
	 * Decodes an ANY from the input stream.
	 *
	 * @param obj the element to decode.
	 * @return the concrete object decoded from the underlying input stream.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public IType decodeAny(IType obj) throws IOException {
		cat.debug("==> decodeAny()");

		String name = obj.getName();
		Tag tag = null;
		try {
			tag = readTag();
		} catch (EOFException x) {
			throw new ASNElementNotFoundException("???");
		}

		int length = readLength();
		byte[] buffer = new byte[length];
		int actualLength = read(buffer);
		if (actualLength == -1)
			throw new EOFException();

		if (actualLength != length)
			throw new DerLengthMismatchException(actualLength, length);

		IType result = null;
		if (tag.getClazz() == Tag.UNIVERSAL)
			switch (tag.getValue()) {
			case Tag.BOOLEAN:
				result = new ASNBoolean(name, tag, toBoolean(buffer));
				break;
			case Tag.INTEGER:
				result = new ASNInteger(name, tag, new BigInteger(1, buffer));
				break;
			case Tag.BIT_STRING:
				result = new ASNBitString(name, tag, buffer);
				break;
			case Tag.OCTET_STRING:
				result = new ASNOctetString(name, tag, buffer);
				break;
			case Tag.NULL:
				toNull(buffer); // throws an exception if malformed
				result = new ASNNull(name, tag, new Object());
				break;
			case Tag.OBJECT_IDENTIFIER:
				result = new ASNObjectIdentifier(name, tag, toOID(buffer));
				break;
			case Tag.PrintableString:
				result = new ASNPrintableString(name, tag, new String(buffer, "US-ASCII"));
				break;
			case Tag.UTC_TIME:
				result = new ASNUTCTime(name, tag, toDate(buffer));
				break;
			}
		else
			result = new ASNAny(name, tag, buffer);

		cat.debug("<== decodeAny() --> "+result);
		return result;
	}

	/**
	 * Decodes an OBJECT IDENTIFIER from the input stream.
	 *
	 * @param obj the element to decode.
	 * @return a String representation of the OID decoded from the stream.
	 * @exception ASNTagMismatchException if the element in the stream has a
	 * different tag to the designated one.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public String decodeObjectIdentifier(IType obj) throws IOException {
		cat.debug("==> decodeObjectIdentifier()");

		Tag tag = obj.getTag();
		byte[] buffer = readRaw(tag, Tag.OBJECT_IDENTIFIER);
		String result = toOID(buffer);

		cat.debug("<== decodeObjectIdentifier() --> "+result);
		return result;
	}

	/**
	 * Decodes a NULL from the input stream.
	 *
	 * @param obj the element to decode.
	 * @exception ASNTagMismatchException if the element in the stream has a
	 * different tag to the designated one.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception DerInvalidLengthException if a mismatch between the expected
	 * and parsed size of the element's encoding is detected.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public void decodeNull(IType obj) throws IOException {
		cat.debug("==> decodeNull()");

		Tag tag = obj.getTag();
		byte[] buffer = readRaw(tag, Tag.NULL);
		toNull(buffer);

		cat.debug("<== decodeNull()");
	}

	/**
	 * Decodes a BOOLEAN from the input stream.
	 *
	 * @param obj the element to decode.
	 * @return the concrete value of this ASN.1 type.
	 * @exception ASNTagMismatchException if the element in the stream has a
	 * different tag to the designated one.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception DerInvalidLengthException if a mismatch between the expected
	 * and parsed size of the element's encoding is detected.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public Boolean decodeBoolean(IType obj) throws IOException {
		cat.debug("==> decodeBoolean("+tag+")");

		Tag tag = obj.getTag();
		byte[] buffer = readRaw(tag, Tag.BOOLEAN);
		Boolean result = toBoolean(buffer);

		cat.debug("<== decodeBoolean() --> "+result);
		return result;
	}

	/**
	 * Decodes an INTEGER from the input stream.
	 *
	 * @param obj the element to decode.
	 * @return the concrete value of this ASN.1 type.
	 * @exception ASNTagMismatchException if the element in the stream has a
	 * different tag to the designated one.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception DerInvalidLengthException if a mismatch between the expected
	 * and parsed size of the element's encoding is detected.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public BigInteger decodeInteger(IType obj) throws IOException {
		cat.debug("==> decodeInteger()");

		Tag tag = obj.getTag();
		byte[] buffer = readRaw(tag, Tag.INTEGER);
		BigInteger result = new BigInteger(1, buffer);

		cat.debug("<== decodeInteger() --> "+result);
		return result;
	}

	/**
	 * Decodes a PrintableString from the input stream.
	 *
	 * @param tagValue the value of a Tag constant to differentiate between
	 * the different types of strings.
	 * @param obj the element to decode.
	 * @return the concrete value of this ASN.1 type.
	 * @exception ASNTagMismatchException if the element in the stream has a
	 * different tag to the designated one.
	 * @exception DerObjectTooLargeException if the DER value of the length part
	 * exceeds 32-bit.
	 * @exception DerInvalidLengthException if a mismatch between the expected
	 * and parsed size of the element's encoding is detected.
	 * @exception EOFException if the end-of-stream was encountered while
	 * decoding the element.
	 * @exception IOException if any other I/O related exception has occured.
	 */
	public String decodeString(int tagValue, IType obj) throws IOException {
		cat.debug("==> decodeString()");

		Tag tag = obj.getTag();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?