001: /* $Id: AsnObjectId.java,v 1.1 2004/01/19 02:03:49 rgrimm Exp $
002: *
003: * Copyright (c) 2000 The Cryptix Foundation Limited. All rights reserved.
004: */
005:
006: package cryptix.jce.provider.asn;
007:
008: import java.io.IOException;
009:
010: /**
011: * Immutable object representing an ASN.1 OBJECT ID.
012: *
013: * XXX: Invariant checking needed.
014: *
015: * @version $Revision: 1.1 $
016: * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
017: */
018: public final class AsnObjectId extends AsnObject {
019: private static final int[] _rsaEncryption = { 1, 2, 840, 113549, 1,
020: 1, 1 },
021: _md4WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 3 },
022: _md5WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 4 },
023: _sha1WithRSAEncryption = { 1, 2, 840, 113549, 1, 1, 5 },
024: _rsaOAEPEncryptionSET = { 1, 2, 840, 113549, 1, 1, 6 },
025:
026: // RSADSI digest algorithms
027: _id_hmacWithSHA1 = { 1, 2, 840, 113549, 2, 7 },
028:
029: // RSADSI encryption algorithms
030: _rc2_CBC = { 1, 2, 840, 113549, 3, 2 }, _des_EDE3_CBC = {
031: 1, 2, 840, 113549, 3, 7 }, _rc5_CBC_PAD = { 1, 2,
032: 840, 113549, 3, 9 },
033:
034: _pbeWithMD2AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 1 },
035: _pbeWithMD5AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 3 },
036: _pbeWithMD2AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 4 },
037: _pbeWithMD5AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 6 },
038: _pbeWithSHA1AndDES_CBC = { 1, 2, 840, 113549, 1, 5, 10 },
039: _pbeWithSHA1AndRC2_CBC = { 1, 2, 840, 113549, 1, 5, 11 },
040: _id_PBKDF2 = { 1, 2, 840, 113549, 1, 5, 12 }, _id_PBES2 = {
041: 1, 2, 840, 113549, 1, 5, 13 }, _id_PBMAC1 = { 1, 2,
042: 840, 113549, 1, 5, 14 };
043:
044: /**
045: * Commonly used OBJECT IDs.
046: */
047: public static final AsnObjectId OID_rsaEncryption = new AsnObjectId(
048: _rsaEncryption),
049: OID_md5WithRSAEncryption = new AsnObjectId(
050: _md5WithRSAEncryption);
051:
052: /**
053: * Array containing individual OBJECT IDENTIFIER components.
054: *
055: * <p>Invariant: two or more elements, no element is negative, 2nd element
056: * smaller than (40*first).
057: */
058: private final int[] components;
059:
060: //............................................................................
061:
062: public AsnObjectId(AsnInputStream is) throws IOException {
063: super (AsnObject.TAG_OBJECT_ID);
064:
065: int len = is.readLength();
066: if (len < 2)
067: throw new IOException("Invalid OBJECT_ID.");
068:
069: byte[] payload = is.readBytes(len);
070: this .components = decodePayload(payload);
071: }
072:
073: public AsnObjectId(int[] components) {
074: super (AsnObject.TAG_OBJECT_ID);
075:
076: if (components.length < 2)
077: throw new IllegalArgumentException(
078: "Less than 2 components.");
079:
080: if (components[0] < 0 || components[0] > 2)
081: throw new IllegalArgumentException(
082: "First comp must be 0, 1 or 2.");
083:
084: if (components[1] >= (components[0] * 40))
085: throw new IllegalArgumentException(
086: "Scnd comp >= (First comp*40).");
087:
088: for (int i = 0; i < components.length; i++)
089: if (components[i] < 0)
090: throw new IllegalArgumentException("Negative comp ("
091: + i + ").");
092:
093: this .components = (int[]) components.clone();
094: }
095:
096: //............................................................................
097:
098: private static int[] decodePayload(byte[] payload) {
099: int compCount = 2;
100: for (int i = 1; i < payload.length; i++)
101: if ((payload[i] & 0x80) == 0x00)
102: compCount++;
103:
104: int[] comps = new int[compCount];
105: comps[0] = payload[0] / 40;
106: comps[1] = payload[0] % 40;
107:
108: int payloadOff = 1;
109: for (int i = 2; i < comps.length; i++) {
110: int c = 0;
111: byte b;
112: do {
113: b = payload[payloadOff++];
114: c = (c << 7) | (b & 0x7F);
115: } while ((b & 0x80) == 0x80);
116: comps[i] = c;
117: }
118: return comps;
119: }
120:
121: public String toString(String indent) {
122: String res = "OBJECT ID { ";
123: for (int i = 0; i < this .components.length; i++)
124: res = res + this .components[i] + " ";
125: return indent + res + "}";
126: }
127:
128: public static void main(String[] argv) throws Exception {
129:
130: int[] comps = { 1, 2, 840 };
131: AsnObjectId o = new AsnObjectId(comps);
132:
133: AsnOutputStream aos = new AsnOutputStream();
134: aos.write(o);
135: byte[] enc = aos.toByteArray();
136:
137: AsnInputStream ais = new AsnInputStream(enc);
138: AsnObject oo = ais.read();
139: System.out.println(oo);
140: }
141:
142: /** Write out payload. */
143: protected void encodePayload(AsnOutputStream os) throws IOException {
144:
145: os.writeByte((byte) (40 * components[0] + components[1]));
146: for (int i = 2; i < components.length; i++)
147: this .writeComponent(os, components[i]);
148: }
149:
150: /**
151: * Returns no. of bytes encodePayload will write out when called on
152: * the given AsnOutputStream. Payload length does NOT include length.
153: */
154: protected int getEncodedLengthOfPayload(AsnOutputStream os) {
155:
156: int len = 1; // first two are special
157: for (int i = 2; i < this .components.length; i++)
158: len += getEncodedComponentLen(this .components[i]);
159:
160: return len;
161: }
162:
163: private void writeComponent(AsnOutputStream os, int c)
164: throws IOException {
165: int len = getEncodedComponentLen(c);
166: for (int i = len - 1; i > 0; i--)
167: os.writeByte((byte) ((c >>> i * 7) | 0x80));
168:
169: os.writeByte((byte) (c & 0x7F));
170: }
171:
172: private static int getEncodedComponentLen(int c) {
173: if (c < 0)
174: throw new IllegalArgumentException("c: < 0");
175: else if (c <= 0x7F)
176: return 1;
177: else if (c <= 0x3FFF)
178: return 2;
179: else if (c <= 0x1FFFFF)
180: return 3;
181: else if (c <= 0xFFFFFFF)
182: return 4;
183: else
184: return 5;
185: }
186: }
|