mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-07-30 03:21:23 +00:00
226 lines
5.4 KiB
Java
226 lines
5.4 KiB
Java
package com.google.bitcoin.bouncycastle.asn1;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
|
|
import com.google.bitcoin.bouncycastle.util.Arrays;
|
|
|
|
/**
|
|
* Base class for an application specific object
|
|
*/
|
|
public class DERApplicationSpecific
|
|
extends ASN1Object
|
|
{
|
|
private final boolean isConstructed;
|
|
private final int tag;
|
|
private final byte[] octets;
|
|
|
|
DERApplicationSpecific(
|
|
boolean isConstructed,
|
|
int tag,
|
|
byte[] octets)
|
|
{
|
|
this.isConstructed = isConstructed;
|
|
this.tag = tag;
|
|
this.octets = octets;
|
|
}
|
|
|
|
public DERApplicationSpecific(
|
|
int tag,
|
|
byte[] octets)
|
|
{
|
|
this(false, tag, octets);
|
|
}
|
|
|
|
public DERApplicationSpecific(
|
|
int tag,
|
|
DEREncodable object)
|
|
throws IOException
|
|
{
|
|
this(true, tag, object);
|
|
}
|
|
|
|
public DERApplicationSpecific(
|
|
boolean explicit,
|
|
int tag,
|
|
DEREncodable object)
|
|
throws IOException
|
|
{
|
|
byte[] data = object.getDERObject().getDEREncoded();
|
|
|
|
this.isConstructed = explicit;
|
|
this.tag = tag;
|
|
|
|
if (explicit)
|
|
{
|
|
this.octets = data;
|
|
}
|
|
else
|
|
{
|
|
int lenBytes = getLengthOfLength(data);
|
|
byte[] tmp = new byte[data.length - lenBytes];
|
|
System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
|
|
this.octets = tmp;
|
|
}
|
|
}
|
|
|
|
public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
|
|
{
|
|
this.tag = tagNo;
|
|
this.isConstructed = true;
|
|
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
|
|
|
for (int i = 0; i != vec.size(); i++)
|
|
{
|
|
try
|
|
{
|
|
bOut.write(((ASN1Encodable)vec.get(i)).getEncoded());
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
throw new ASN1ParsingException("malformed object: " + e, e);
|
|
}
|
|
}
|
|
this.octets = bOut.toByteArray();
|
|
}
|
|
|
|
private int getLengthOfLength(byte[] data)
|
|
{
|
|
int count = 2; // TODO: assumes only a 1 byte tag number
|
|
|
|
while((data[count - 1] & 0x80) != 0)
|
|
{
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
public boolean isConstructed()
|
|
{
|
|
return isConstructed;
|
|
}
|
|
|
|
public byte[] getContents()
|
|
{
|
|
return octets;
|
|
}
|
|
|
|
public int getApplicationTag()
|
|
{
|
|
return tag;
|
|
}
|
|
|
|
/**
|
|
* Return the enclosed object assuming explicit tagging.
|
|
*
|
|
* @return the resulting object
|
|
* @throws IOException if reconstruction fails.
|
|
*/
|
|
public DERObject getObject()
|
|
throws IOException
|
|
{
|
|
return new ASN1InputStream(getContents()).readObject();
|
|
}
|
|
|
|
/**
|
|
* Return the enclosed object assuming implicit tagging.
|
|
*
|
|
* @param derTagNo the type tag that should be applied to the object's contents.
|
|
* @return the resulting object
|
|
* @throws IOException if reconstruction fails.
|
|
*/
|
|
public DERObject getObject(int derTagNo)
|
|
throws IOException
|
|
{
|
|
if (derTagNo >= 0x1f)
|
|
{
|
|
throw new IOException("unsupported tag number");
|
|
}
|
|
|
|
byte[] orig = this.getEncoded();
|
|
byte[] tmp = replaceTagNumber(derTagNo, orig);
|
|
|
|
if ((orig[0] & DERTags.CONSTRUCTED) != 0)
|
|
{
|
|
tmp[0] |= DERTags.CONSTRUCTED;
|
|
}
|
|
|
|
return new ASN1InputStream(tmp).readObject();
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream)
|
|
*/
|
|
void encode(DEROutputStream out) throws IOException
|
|
{
|
|
int classBits = DERTags.APPLICATION;
|
|
if (isConstructed)
|
|
{
|
|
classBits |= DERTags.CONSTRUCTED;
|
|
}
|
|
|
|
out.writeEncoded(classBits, tag, octets);
|
|
}
|
|
|
|
boolean asn1Equals(
|
|
DERObject o)
|
|
{
|
|
if (!(o instanceof DERApplicationSpecific))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DERApplicationSpecific other = (DERApplicationSpecific)o;
|
|
|
|
return isConstructed == other.isConstructed
|
|
&& tag == other.tag
|
|
&& Arrays.areEqual(octets, other.octets);
|
|
}
|
|
|
|
public int hashCode()
|
|
{
|
|
return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);
|
|
}
|
|
|
|
private byte[] replaceTagNumber(int newTag, byte[] input)
|
|
throws IOException
|
|
{
|
|
int tagNo = input[0] & 0x1f;
|
|
int index = 1;
|
|
//
|
|
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
|
//
|
|
if (tagNo == 0x1f)
|
|
{
|
|
tagNo = 0;
|
|
|
|
int b = input[index++] & 0xff;
|
|
|
|
// X.690-0207 8.1.2.4.2
|
|
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
|
if ((b & 0x7f) == 0) // Note: -1 will pass
|
|
{
|
|
throw new ASN1ParsingException("corrupted stream - invalid high tag number found");
|
|
}
|
|
|
|
while ((b >= 0) && ((b & 0x80) != 0))
|
|
{
|
|
tagNo |= (b & 0x7f);
|
|
tagNo <<= 7;
|
|
b = input[index++] & 0xff;
|
|
}
|
|
|
|
tagNo |= (b & 0x7f);
|
|
}
|
|
|
|
byte[] tmp = new byte[input.length - index + 1];
|
|
|
|
System.arraycopy(input, index, tmp, 1, tmp.length - 1);
|
|
|
|
tmp[0] = (byte)newTag;
|
|
|
|
return tmp;
|
|
}
|
|
}
|