package model.asn1; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import ui.Utils; import java.math.BigInteger; /** * Represents the ASN.1 BIT STRING (0x3) type. Bit strings represent bytes by padding to the LSB (like a bitstream). * The bits are encoded as multiple bytes, but the unused bits are stored on the lowest part. * For example, consider: *
 *     0b 00000001 10111001 01110111 (pad to the highest)
 *     Will be encoded into
 *     0b 01101110 01011101 11000000 (pad to the lowest)
 *                            ^^^^^^
 * 
* Before the encoded value, there will be another byte denoting how many padding bits are added to the right. * That is, the final encoding is: *
 *     0b 00000110 01101110 01011101 11000000
 *        ^  6   ^ ^ Original Number  ^^Pad^
 * 
* * BIT STRING has nothing to do with encoding bytes as printable strings (base10 or base16 or ASCII). */ public class BitString extends ASN1Object { /** * The X.680 universal class tag assignment. */ public static final Tag TAG = new Tag(TagClass.UNIVERSAL, false, 0x3); private final int unused; private final Byte[] val; /** * EFFECT: Init with tags, unused, and val. For tags, see {@link ASN1Object}. * REQUIRES: 0 <= unused < 8, the last byte in val must have the lowest $unused bits zero. */ public BitString(Tag tag, Tag parentTag, final int unused, final Byte[] val) { super(tag, parentTag); this.unused = unused; this.val = val; } /** * EFFECT: Parse the input DER. * Throws {@link ParseException} if the input is invalid: * - Unused is not in 0 <= unused < 8 * - The last byte does not have its lowest $unused bits zero * - Other issues found according to {@link ASN1Object} */ public BitString(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); this.unused = encoded.require(1, true)[0]; if (unused < 0 || unused > 7) { throw new ParseException("Illegal unused byte: " + unused); } this.val = encoded.require(getLength() - 1, true); if ((byte) (val[val.length - 1] << (8 - unused)) != 0) { throw new ParseException(String.format("The last byte: 0x%02X does not have %d zero bits.", val[val.length - 1], unused)); } } /** * EFFECTS: Get the converted form that has padding on MSB. The leftmost zero byte, if any, is removed. */ public Byte[] getConvertedVal() { return Utils.byteToByte(new BigInteger(Utils.byteToByte(val)).shiftRight(unused).toByteArray()); } /** * EFFECTS: Encode into DER. */ @Override public Byte[] encodeValueDER() { Byte[] arr = new Byte[val.length + 1]; arr[0] = (byte) unused; System.arraycopy(val, 0, arr, 1, val.length); return arr; } public int getUnused() { return unused; } public Byte[] getVal() { return val; } }