1 package org.bouncycastle.asn1; 2 3 import org.bouncycastle.util.Arrays; 4 5 import java.io.ByteArrayOutputStream; 6 import java.io.IOException; 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 if (obj instanceof ASN1OctetString) 104 { 105 byte[] bytes = ((ASN1OctetString)obj).getOctets(); 106 int padBits = bytes[0]; 107 byte[] data = new byte[bytes.length - 1]; 108 109 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 110 111 return new DERBitString(data, padBits); 112 } 113 114 if (obj instanceof ASN1TaggedObject) 115 { 116 return getInstance(((ASN1TaggedObject)obj).getObject()); 117 } 118 119 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 120 } 121 122 /** 123 * return a Bit String from a tagged object. 124 * 125 * @param obj the tagged object holding the object we want 126 * @param explicit true if the object is meant to be explicitly 127 * tagged false otherwise. 128 * @exception IllegalArgumentException if the tagged object cannot 129 * be converted. 130 */ 131 public static DERBitString getInstance( 132 ASN1TaggedObject obj, 133 boolean explicit) 134 { 135 return getInstance(obj.getObject()); 136 } 137 138 protected DERBitString( 139 byte data, 140 int padBits) 141 { 142 this.data = new byte[1]; 143 this.data[0] = data; 144 this.padBits = padBits; 145 } 146 147 /** 148 * @param data the octets making up the bit string. 149 * @param padBits the number of extra bits at the end of the string. 150 */ 151 public DERBitString( 152 byte[] data, 153 int padBits) 154 { 155 this.data = data; 156 this.padBits = padBits; 157 } 158 159 public DERBitString( 160 byte[] data) 161 { 162 this(data, 0); 163 } 164 165 public DERBitString( 166 DEREncodable obj) 167 { 168 try 169 { 170 this.data = obj.getDERObject().getEncoded(ASN1Encodable.DER); 171 this.padBits = 0; 172 } 173 catch (IOException e) 174 { 175 throw new IllegalArgumentException("Error processing object : " + e.toString()); 176 } 177 } 178 179 public byte[] getBytes() 180 { 181 return data; 182 } 183 184 public int getPadBits() 185 { 186 return padBits; 187 } 188 189 190 /** 191 * @return the value of the bit string as an int (truncating if necessary) 192 */ 193 public int intValue() 194 { 195 int value = 0; 196 197 for (int i = 0; i != data.length && i != 4; i++) 198 { 199 value |= (data[i] & 0xff) << (8 * i); 200 } 201 202 return value; 203 } 204 205 void encode( 206 DEROutputStream out) 207 throws IOException 208 { 209 byte[] bytes = new byte[getBytes().length + 1]; 210 211 bytes[0] = (byte)getPadBits(); 212 System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1); 213 214 out.writeEncoded(BIT_STRING, bytes); 215 } 216 217 public int hashCode() 218 { 219 return padBits ^ Arrays.hashCode(data); 220 } 221 222 protected boolean asn1Equals( 223 DERObject o) 224 { 225 if (!(o instanceof DERBitString)) 226 { 227 return false; 228 } 229 230 DERBitString other = (DERBitString)o; 231 232 return this.padBits == other.padBits 233 && Arrays.areEqual(this.data, other.data); 234 } 235 236 public String getString() 237 { 238 StringBuffer buf = new StringBuffer("#"); 239 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 240 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 241 242 try 243 { 244 aOut.writeObject(this); 245 } 246 catch (IOException e) 247 { 248 throw new RuntimeException("internal error encoding BitString"); 249 } 250 251 byte[] string = bOut.toByteArray(); 252 253 for (int i = 0; i != string.length; i++) 254 { 255 buf.append(table[(string[i] >>> 4) & 0xf]); 256 buf.append(table[string[i] & 0xf]); 257 } 258 259 return buf.toString(); 260 } 261 262 public String toString() 263 { 264 return getString(); 265 } 266 } 267