001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.crypto.asn1;
017:
018: import java.io.ByteArrayOutputStream;
019: import java.io.IOException;
020:
021: public class DERBitString extends DERObject implements DERString {
022: private static final char[] table = { '0', '1', '2', '3', '4', '5',
023: '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
024:
025: protected byte[] data;
026: protected int padBits;
027:
028: /**
029: * return the correct number of pad bits for a bit string defined in
030: * a 32 bit constant
031: */
032: static protected int getPadBits(int bitString) {
033: int val = 0;
034: for (int i = 3; i >= 0; i--) {
035: //
036: // this may look a little odd, but if it isn't done like this pre jdk1.2
037: // JVM's break!
038: //
039: if (i != 0) {
040: if ((bitString >> (i * 8)) != 0) {
041: val = (bitString >> (i * 8)) & 0xFF;
042: break;
043: }
044: } else {
045: if (bitString != 0) {
046: val = bitString & 0xFF;
047: break;
048: }
049: }
050: }
051:
052: if (val == 0) {
053: return 7;
054: }
055:
056: int bits = 1;
057:
058: while (((val <<= 1) & 0xFF) != 0) {
059: bits++;
060: }
061:
062: return 8 - bits;
063: }
064:
065: /**
066: * return the correct number of bytes for a bit string defined in
067: * a 32 bit constant
068: */
069: static protected byte[] getBytes(int bitString) {
070: int bytes = 4;
071: for (int i = 3; i >= 1; i--) {
072: if ((bitString & (0xFF << (i * 8))) != 0) {
073: break;
074: }
075: bytes--;
076: }
077:
078: byte[] result = new byte[bytes];
079: for (int i = 0; i < bytes; i++) {
080: result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
081: }
082:
083: return result;
084: }
085:
086: /**
087: * return a Bit String from the passed in object
088: *
089: * @exception IllegalArgumentException if the object cannot be converted.
090: */
091: public static DERBitString getInstance(Object obj) {
092: if (obj == null || obj instanceof DERBitString) {
093: return (DERBitString) obj;
094: }
095:
096: if (obj instanceof ASN1OctetString) {
097: byte[] bytes = ((ASN1OctetString) obj).getOctets();
098: int padBits = bytes[0];
099: byte[] data = new byte[bytes.length - 1];
100:
101: System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
102:
103: return new DERBitString(data, padBits);
104: }
105:
106: if (obj instanceof ASN1TaggedObject) {
107: return getInstance(((ASN1TaggedObject) obj).getObject());
108: }
109:
110: throw new IllegalArgumentException(
111: "illegal object in getInstance: "
112: + obj.getClass().getName());
113: }
114:
115: /**
116: * return a Bit String from a tagged object.
117: *
118: * @param obj the tagged object holding the object we want
119: * @param explicit true if the object is meant to be explicitly
120: * tagged false otherwise.
121: * @exception IllegalArgumentException if the tagged object cannot
122: * be converted.
123: */
124: public static DERBitString getInstance(ASN1TaggedObject obj,
125: boolean explicit) {
126: return getInstance(obj.getObject());
127: }
128:
129: protected DERBitString(byte data, int padBits) {
130: this .data = new byte[1];
131: this .data[0] = data;
132: this .padBits = padBits;
133: }
134:
135: /**
136: * @param data the octets making up the bit string.
137: * @param padBits the number of extra bits at the end of the string.
138: */
139: public DERBitString(byte[] data, int padBits) {
140: this .data = data;
141: this .padBits = padBits;
142: }
143:
144: public DERBitString(byte[] data) {
145: this (data, 0);
146: }
147:
148: public DERBitString(DEREncodable obj) {
149: try {
150: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
151: DEROutputStream dOut = new DEROutputStream(bOut);
152:
153: dOut.writeObject(obj);
154: dOut.close();
155:
156: this .data = bOut.toByteArray();
157: this .padBits = 0;
158: } catch (IOException e) {
159: throw new IllegalArgumentException(
160: "Error processing object : " + e.getMessage(), e);
161: }
162: }
163:
164: public byte[] getBytes() {
165: return data;
166: }
167:
168: public int getPadBits() {
169: return padBits;
170: }
171:
172: /**
173: * @return the value of the bit string as an int (truncating if necessary)
174: */
175: public int intValue() {
176: int value = 0;
177:
178: for (int i = 0; i != data.length && i != 4; i++) {
179: value |= (data[i] & 0xff) << (8 * i);
180: }
181:
182: return value;
183: }
184:
185: void encode(DEROutputStream out) throws IOException {
186: byte[] bytes = new byte[getBytes().length + 1];
187:
188: bytes[0] = (byte) getPadBits();
189: System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
190:
191: out.writeEncoded(BIT_STRING, bytes);
192: }
193:
194: public int hashCode() {
195: int value = 0;
196:
197: for (int i = 0; i != data.length; i++) {
198: value ^= (data[i] & 0xff) << (i % 4);
199: }
200:
201: return value;
202: }
203:
204: public boolean equals(Object o) {
205: if (o == null || !(o instanceof DERBitString)) {
206: return false;
207: }
208:
209: DERBitString other = (DERBitString) o;
210:
211: if (data.length != other.data.length) {
212: return false;
213: }
214:
215: for (int i = 0; i != data.length; i++) {
216: if (data[i] != other.data[i]) {
217: return false;
218: }
219: }
220:
221: return (padBits == other.padBits);
222: }
223:
224: public String getString() {
225: StringBuffer buf = new StringBuffer("#");
226: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
227: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
228:
229: try {
230: aOut.writeObject(this );
231: } catch (IOException e) {
232: throw new RuntimeException(
233: "internal error encoding BitString", e);
234: }
235:
236: byte[] string = bOut.toByteArray();
237:
238: for (int i = 0; i != string.length; i++) {
239: buf.append(table[(string[i] >>> 4) % 0xf]);
240: buf.append(table[string[i] & 0xf]);
241: }
242:
243: return buf.toString();
244: }
245: }
|