/* $Id: AsnObjectId.java,v 1.1 2004/01/19 02:03:49 rgrimm Exp $
*
* Copyright (c) 2000 The Cryptix Foundation Limited. All rights reserved.
*/
package cryptix.jce.provider.asn;
import java.io.IOException;
/**
* Immutable object representing an ASN.1 OBJECT ID.
*
* XXX: Invariant checking needed.
*
* @version $Revision: 1.1 $
* @author Jeroen C. van Gelderen (gelderen@cryptix.org)
*/
public final class AsnObjectId extends AsnObject
{
private static final int[]
_rsaEncryption = { 1, 2, 840, 113549, 1, 1, 1 },
_md4WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 3 },
_md5WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 4 },
_sha1WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 5 },
_rsaOAEPEncryptionSET = { 1, 2, 840, 113549, 1, 1, 6 },
// RSADSI digest algorithms
_id_hmacWithSHA1 = { 1, 2, 840, 113549, 2, 7 },
// RSADSI encryption algorithms
_rc2_CBC = { 1, 2, 840, 113549, 3, 2 },
_des_EDE3_CBC = { 1, 2, 840, 113549, 3, 7 },
_rc5_CBC_PAD = { 1, 2, 840, 113549, 3, 9 },
_pbeWithMD2AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 1 },
_pbeWithMD5AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 3 },
_pbeWithMD2AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 4 },
_pbeWithMD5AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 6 },
_pbeWithSHA1AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 10 },
_pbeWithSHA1AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 11 },
_id_PBKDF2 = { 1, 2, 840, 113549, 1, 5, 12 },
_id_PBES2 = { 1, 2, 840, 113549, 1, 5, 13 },
_id_PBMAC1 = { 1, 2, 840, 113549, 1, 5, 14 };
/**
* Commonly used OBJECT IDs.
*/
public static final AsnObjectId
OID_rsaEncryption = new AsnObjectId(_rsaEncryption),
OID_md5WithRSAEncryption = new AsnObjectId(_md5WithRSAEncryption);
/**
* Array containing individual OBJECT IDENTIFIER components.
*
* <p>Invariant: two or more elements, no element is negative, 2nd element
* smaller than (40*first).
*/
private final int[] components;
//............................................................................
public AsnObjectId(AsnInputStream is) throws IOException {
super(AsnObject.TAG_OBJECT_ID);
int len = is.readLength();
if( len < 2 )
throw new IOException("Invalid OBJECT_ID.");
byte[] payload = is.readBytes(len);
this.components = decodePayload(payload);
}
public AsnObjectId(int[] components) {
super(AsnObject.TAG_OBJECT_ID);
if( components.length < 2 )
throw new IllegalArgumentException("Less than 2 components.");
if( components[0] < 0 || components[0] > 2 )
throw new IllegalArgumentException("First comp must be 0, 1 or 2.");
if( components[1] >= (components[0]*40) )
throw new IllegalArgumentException("Scnd comp >= (First comp*40).");
for(int i=0; i<components.length; i++)
if( components[i] < 0 )
throw new IllegalArgumentException("Negative comp ("+i+").");
this.components = (int[])components.clone();
}
//............................................................................
private static int[] decodePayload(byte[] payload) {
int compCount = 2;
for(int i=1; i<payload.length; i++)
if ((payload[i] & 0x80)==0x00) compCount++;
int[] comps = new int[compCount];
comps[0] = payload[0] / 40;
comps[1] = payload[0] % 40;
int payloadOff = 1;
for( int i=2; i<comps.length; i++) {
int c = 0;
byte b;
do {
b = payload[payloadOff++];
c = (c << 7) | (b&0x7F);
} while( (b&0x80) == 0x80 );
comps[i] = c;
}
return comps;
}
public String toString(String indent) {
String res = "OBJECT ID { ";
for( int i=0; i<this.components.length; i++ )
res = res + this.components[i] + " ";
return indent + res + "}";
}
public static void main(String[] argv) throws Exception {
int[] comps = { 1, 2, 840 };
AsnObjectId o = new AsnObjectId(comps);
AsnOutputStream aos = new AsnOutputStream();
aos.write(o);
byte[] enc = aos.toByteArray();
AsnInputStream ais = new AsnInputStream(enc);
AsnObject oo = ais.read();
System.out.println(oo);
}
/** Write out payload. */
protected void encodePayload(AsnOutputStream os) throws IOException {
os.writeByte( (byte)(40*components[0] + components[1]) );
for(int i=2; i<components.length; i++)
this.writeComponent( os, components[i] );
}
/**
* Returns no. of bytes encodePayload will write out when called on
* the given AsnOutputStream. Payload length does NOT include length.
*/
protected int getEncodedLengthOfPayload(AsnOutputStream os) {
int len = 1; // first two are special
for(int i=2; i<this.components.length; i++)
len += getEncodedComponentLen( this.components[i] );
return len;
}
private void writeComponent(AsnOutputStream os, int c) throws IOException {
int len = getEncodedComponentLen(c);
for(int i=len-1; i>0; i--)
os.writeByte( (byte)((c>>>i*7) | 0x80) );
os.writeByte( (byte)(c&0x7F) );
}
private static int getEncodedComponentLen(int c) {
if( c < 0 )
throw new IllegalArgumentException("c: < 0");
else if( c <= 0x7F )
return 1;
else if( c <= 0x3FFF )
return 2;
else if( c <= 0x1FFFFF )
return 3;
else if( c <= 0xFFFFFFF )
return 4;
else
return 5;
}
}