DERBitString.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.asn1; 2 3import java.io.ByteArrayOutputStream; 4import java.io.EOFException; 5import java.io.IOException; 6import java.io.InputStream; 7 8import org.bouncycastle.util.Arrays; 9import org.bouncycastle.util.io.Streams; 10 11public class DERBitString 12 extends ASN1Primitive 13 implements ASN1String 14{ 15 private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 16 17 protected byte[] data; 18 protected int padBits; 19 20 /** 21 * return the correct number of pad bits for a bit string defined in 22 * a 32 bit constant 23 */ 24 static protected int getPadBits( 25 int bitString) 26 { 27 int val = 0; 28 for (int i = 3; i >= 0; i--) 29 { 30 // 31 // this may look a little odd, but if it isn't done like this pre jdk1.2 32 // JVM's break! 33 // 34 if (i != 0) 35 { 36 if ((bitString >> (i * 8)) != 0) 37 { 38 val = (bitString >> (i * 8)) & 0xFF; 39 break; 40 } 41 } 42 else 43 { 44 if (bitString != 0) 45 { 46 val = bitString & 0xFF; 47 break; 48 } 49 } 50 } 51 52 if (val == 0) 53 { 54 return 7; 55 } 56 57 58 int bits = 1; 59 60 while (((val <<= 1) & 0xFF) != 0) 61 { 62 bits++; 63 } 64 65 return 8 - bits; 66 } 67 68 /** 69 * return the correct number of bytes for a bit string defined in 70 * a 32 bit constant 71 */ 72 static protected byte[] getBytes(int bitString) 73 { 74 int bytes = 4; 75 for (int i = 3; i >= 1; i--) 76 { 77 if ((bitString & (0xFF << (i * 8))) != 0) 78 { 79 break; 80 } 81 bytes--; 82 } 83 84 byte[] result = new byte[bytes]; 85 for (int i = 0; i < bytes; i++) 86 { 87 result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); 88 } 89 90 return result; 91 } 92 93 /** 94 * return a Bit String from the passed in object 95 * 96 * @exception IllegalArgumentException if the object cannot be converted. 97 */ 98 public static DERBitString getInstance( 99 Object obj) 100 { 101 if (obj == null || obj instanceof DERBitString) 102 { 103 return (DERBitString)obj; 104 } 105 106 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 107 } 108 109 /** 110 * return a Bit String from a tagged object. 111 * 112 * @param obj the tagged object holding the object we want 113 * @param explicit true if the object is meant to be explicitly 114 * tagged false otherwise. 115 * @exception IllegalArgumentException if the tagged object cannot 116 * be converted. 117 */ 118 public static DERBitString getInstance( 119 ASN1TaggedObject obj, 120 boolean explicit) 121 { 122 ASN1Primitive o = obj.getObject(); 123 124 if (explicit || o instanceof DERBitString) 125 { 126 return getInstance(o); 127 } 128 else 129 { 130 return fromOctetString(((ASN1OctetString)o).getOctets()); 131 } 132 } 133 134 protected DERBitString( 135 byte data, 136 int padBits) 137 { 138 this.data = new byte[1]; 139 this.data[0] = data; 140 this.padBits = padBits; 141 } 142 143 /** 144 * @param data the octets making up the bit string. 145 * @param padBits the number of extra bits at the end of the string. 146 */ 147 public DERBitString( 148 byte[] data, 149 int padBits) 150 { 151 this.data = data; 152 this.padBits = padBits; 153 } 154 155 public DERBitString( 156 byte[] data) 157 { 158 this(data, 0); 159 } 160 161 public DERBitString( 162 ASN1Encodable obj) 163 { 164 try 165 { 166 this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); 167 this.padBits = 0; 168 } 169 catch (IOException e) 170 { 171 throw new IllegalArgumentException("Error processing object : " + e.toString()); 172 } 173 } 174 175 public byte[] getBytes() 176 { 177 return data; 178 } 179 180 public int getPadBits() 181 { 182 return padBits; 183 } 184 185 186 /** 187 * @return the value of the bit string as an int (truncating if necessary) 188 */ 189 public int intValue() 190 { 191 int value = 0; 192 193 for (int i = 0; i != data.length && i != 4; i++) 194 { 195 value |= (data[i] & 0xff) << (8 * i); 196 } 197 198 return value; 199 } 200 201 boolean isConstructed() 202 { 203 return false; 204 } 205 206 int encodedLength() 207 { 208 return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; 209 } 210 211 void encode( 212 ASN1OutputStream out) 213 throws IOException 214 { 215 byte[] bytes = new byte[getBytes().length + 1]; 216 217 bytes[0] = (byte)getPadBits(); 218 System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1); 219 220 out.writeEncoded(BERTags.BIT_STRING, bytes); 221 } 222 223 public int hashCode() 224 { 225 return padBits ^ Arrays.hashCode(data); 226 } 227 228 protected boolean asn1Equals( 229 ASN1Primitive o) 230 { 231 if (!(o instanceof DERBitString)) 232 { 233 return false; 234 } 235 236 DERBitString other = (DERBitString)o; 237 238 return this.padBits == other.padBits 239 && Arrays.areEqual(this.data, other.data); 240 } 241 242 public String getString() 243 { 244 StringBuffer buf = new StringBuffer("#"); 245 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 246 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 247 248 try 249 { 250 aOut.writeObject(this); 251 } 252 catch (IOException e) 253 { 254 throw new RuntimeException("internal error encoding BitString"); 255 } 256 257 byte[] string = bOut.toByteArray(); 258 259 for (int i = 0; i != string.length; i++) 260 { 261 buf.append(table[(string[i] >>> 4) & 0xf]); 262 buf.append(table[string[i] & 0xf]); 263 } 264 265 return buf.toString(); 266 } 267 268 public String toString() 269 { 270 return getString(); 271 } 272 273 static DERBitString fromOctetString(byte[] bytes) 274 { 275 if (bytes.length < 1) 276 { 277 throw new IllegalArgumentException("truncated BIT STRING detected"); 278 } 279 280 int padBits = bytes[0]; 281 byte[] data = new byte[bytes.length - 1]; 282 283 if (data.length != 0) 284 { 285 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 286 } 287 288 return new DERBitString(data, padBits); 289 } 290 291 static DERBitString fromInputStream(int length, InputStream stream) 292 throws IOException 293 { 294 if (length < 1) 295 { 296 throw new IllegalArgumentException("truncated BIT STRING detected"); 297 } 298 299 int padBits = stream.read(); 300 byte[] data = new byte[length - 1]; 301 302 if (data.length != 0) 303 { 304 if (Streams.readFully(stream, data) != data.length) 305 { 306 throw new EOFException("EOF encountered in middle of BIT STRING"); 307 } 308 } 309 310 return new DERBitString(data, padBits); 311 } 312} 313