aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/asn1/BitString.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/model/asn1/BitString.java')
-rw-r--r--src/main/model/asn1/BitString.java95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/main/model/asn1/BitString.java b/src/main/model/asn1/BitString.java
new file mode 100644
index 0000000..0561f24
--- /dev/null
+++ b/src/main/model/asn1/BitString.java
@@ -0,0 +1,95 @@
+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 <b>lowest</b> part.
+ * For example, consider:
+ * <pre>
+ * 0b 00000001 10111001 01110111 (pad to the highest)
+ * Will be encoded into
+ * 0b 01101110 01011101 11000000 (pad to the lowest)
+ * ^^^^^^
+ * </pre>
+ * 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:
+ * <pre>
+ * 0b 00000110 01101110 01011101 11000000
+ * ^ 6 ^ ^ Original Number ^^Pad^
+ * </pre>
+ *
+ * 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;
+ }
+}