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