⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 derdecoder.java

📁 JAVA的加密库之一
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/* $Id: DerDecoder.java,v 1.8 2001/05/26 07:58:43 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.ArrayList;
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 Distinguished
 * Encoding Rules.<p>
 *
 * @version $Revision: 1.8 $
 * @author  Raif S. Naffah
 */
public class DerDecoder 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 DerDecoder() {
   		super();
	}

    /**
     * Private constructor for internal use.
     *
     * @param ba a byte array to become the underlying stream of the decoder.
	 */
	private DerDecoder(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.PRINTABLE_STRING
				|| xValue == Tag.IA5_STRING
				|| xValue == Tag.T61_STRING)
			return (tValue == Tag.PRINTABLE_STRING
					|| 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);
	}

	/**
	 * Use to parse UTCTime.<p>
	 *
	 * UTCTime formats are:
	 * <pre>
	 *		yymmddhhmmZ
	 *		yymmddhhmmssZ
	 *		yymmddhhmm+hhmm
	 *		yymmddhhmm-hhmm
	 *		yymmddhhmmss+hhmm
	 *		yymmddhhmmss-hhmm
	 * </pre>
	 */
	private static final Date toDate(byte[] buffer) throws DerFormatException {
		int limit = buffer.length;
		if (limit != 11 && limit != 13 && limit != 15 && limit != 17)
			throw new DerFormatException(Tag.UTC_TIME);
		if (limit == 11 && buffer[10] != 'Z')
			throw new DerFormatException(Tag.UTC_TIME);
		if (limit == 13 && buffer[12] != 'Z')
			throw new DerFormatException(Tag.UTC_TIME);
		if (limit == 15 && (buffer[10] != '+' || buffer[10] != '-'))
			throw new DerFormatException(Tag.UTC_TIME);
		if (limit == 17 && (buffer[12] != '+' || buffer[12] != '-'))
			throw new DerFormatException(Tag.UTC_TIME);
		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');
		YY += YY <= 50 ? 2000 : 1900; // fails for 2051 and later
		Date result = null;
		Calendar cal = null;
		int ss = 0;
		switch (limit) {
		case 11:
			cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
			cal.set(YY, MM, DD, hh, mm);
			result = cal.getTime();
			break;
		case 13:
			cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
			ss = (buffer[10]-'0')*10 + (buffer[11]-'0');
			cal.set(YY, MM, DD, hh, mm, ss);
			result = cal.getTime();
			break;
		case 15:
			cal = Calendar.getInstance();
			cal.set(YY, MM, DD, hh, mm);
			hh = (buffer[11]-'0')*10 + (buffer[12]-'0');
			mm = (buffer[13]-'0')*10 + (buffer[14]-'0');
			mm += hh * 60;
			if (buffer[10] == '+')
				cal.add(Calendar.MINUTE, mm);
			else
				cal.add(Calendar.MINUTE, - mm);
			result = cal.getTime();
			break;
		case 17:
			cal = Calendar.getInstance();
			ss = (buffer[10]-'0')*10 + (buffer[11]-'0');
			cal.set(YY, MM, DD, hh, mm, ss);
			hh = (buffer[13]-'0')*10 + (buffer[14]-'0');
			mm = (buffer[15]-'0')*10 + (buffer[16]-'0');
			mm += hh * 60;
			if (buffer[12] == '+')
				cal.add(Calendar.MINUTE, mm);
			else
				cal.add(Calendar.MINUTE, - mm);
			result = cal.getTime();
		}

		return result;
	}

	/**
	 * Use to parse GeneralizedTime.<p>
	 *
	 * GeneralizedTime use 4-digit for the year and an arbitrary number/precision
	 * for the seconds. Its formats are:
	 * <pre>
	 *		yyyymmddhhmmZ
	 *		yyyymmddhhmmssZ
	 *		yyyymmddhhmmss.ss..sZ
	 *		yyyymmddhhmm+hhmm
	 *		yyyymmddhhmm-hhmm
	 *		yyyymmddhhmmss+hhmm
	 *		yyyymmddhhmmss-hhmm
	 *		yyyymmddhhmmss.ss..s+hhmm
	 *		yyyymmddhhmmss.ss..s-hhmm
	 * </pre>
	 *
	 * Please note that while GeneralizedTime allows for an arbitrary precision
	 * for the fraction of a second field (digits after the decimal point) this
	 * implementation, relying on the Java <tt>java.util.Date</tt> and
	 * <tt>java.util.Calendar</tt> classes, only caters for time precision up to
	 * the millisecond --first 3 digits after the decimal point if/when
	 * encountered. If a loss of precision is detected, a warning message is
	 * generated in the trace/debug stream, but no exception is thrown.
	 *
	 * @param buffer the raw bytes from a DER stream to be interpreted as a
	 * GeneralizedTime value.
	 * @return a <tt>java.util.Date</tt> instance emboddying this value.
	 */
	private static final Date toFullDate(byte[] buffer) throws DerFormatException {
		int limit = buffer.length;
		if (limit < 13)
			throw new DerFormatException(Tag.GENERALIZED_TIME);
		int YY = (buffer[ 0]-'0')*1000 + (buffer[ 1]-'0')*100
				 + (buffer[ 2]-'0')*10   + (buffer[ 3]-'0');
		int MM = (buffer[ 4]-'0')*10   + (buffer[ 5]-'0') - 1;
		int DD = (buffer[ 6]-'0')*10   + (buffer[ 7]-'0');
		int hh = (buffer[ 8]-'0')*10   + (buffer[ 9]-'0');
		int mm = (buffer[10]-'0')*10   + (buffer[11]-'0');
		Date result = null;
		Calendar cal = null;
		int ss = 0;
		int ms = 0;
		int precision = 0;
		int b = 0;
		boolean millis = false;
		if (buffer[limit-1] == 'Z') {
			for (int i = 12; i < limit-1; ) {
				b = buffer[i++] & 0xFF;
				if (b == '.')
					millis = true;
				else if (!millis)
					ss = ss * 10 + (b - '0');
				else if (precision++ < 3)
					ms = ms * 10 + (b - '0');
			}

			cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
			cal.set(YY, MM, DD, hh, mm, ss);
			cal.set(Calendar.MILLISECOND, ms);
		} else {
			int i = 12;
			while (buffer[i] != '+' && buffer[i] != '-' && i < limit) {
				b = buffer[i++] & 0xFF;
				if (b == '.')
					millis = true;
				else if (!millis)
					ss = ss * 10 + (b - '0');
				else if (precision++ < 3)
					ms = ms * 10 + (b - '0');
			}

			if (i == limit)
				throw new DerFormatException(Tag.GENERALIZED_TIME);

			cal = Calendar.getInstance();
			cal.set(YY, MM, DD, hh, mm, ss);
			cal.set(Calendar.MILLISECOND, ms);
			boolean toSubtract = (buffer[i++] == '-');
			if ((limit - i) != 4)
				throw new DerFormatException(Tag.GENERALIZED_TIME);

			hh = (buffer[i++]-'0')*10 + (buffer[i++]-'0');
			mm = (buffer[i++]-'0')*10 + (buffer[i++]-'0');
			mm += hh * 60;
			if (toSubtract)
				mm *= -1;

			cal.add(Calendar.MINUTE, mm);
		}

		result = cal.getTime();
		return result;
	}

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

⌨️ 快捷键说明

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