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