aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/asn1/Int.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/model/asn1/Int.java')
-rw-r--r--src/main/model/asn1/Int.java81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/main/model/asn1/Int.java b/src/main/model/asn1/Int.java
new file mode 100644
index 0000000..5b75a73
--- /dev/null
+++ b/src/main/model/asn1/Int.java
@@ -0,0 +1,81 @@
+package model.asn1;
+
+import model.asn1.exceptions.ParseException;
+import model.asn1.parsing.BytesReader;
+import model.pki.cert.TbsCertificate;
+import ui.Utils;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * An ASN.1 INTEGER type. By spec, it can be arbitrarily long. But just like it's impossible to have an
+ * endless tape in a turing machine, this implementation uses fixed length internally to represent ints.
+ */
+public class Int extends ASN1Object {
+ /**
+ * The X.680 universal class tag assignment.
+ */
+ public static final Tag TAG = new Tag(TagClass.UNIVERSAL, false, 0x2);
+
+ private final BigInteger value;
+
+ /**
+ * EFFECTS: Initiate the INTEGER object with the given tag and an optional context-specific tag number for explicit
+ * encoding. For more information, consult {@link ASN1Object}.
+ * REQUIRES: Consult {@link ASN1Object}.
+ */
+ public Int(Tag tag, Tag parentTag, long value) {
+ super(tag, parentTag);
+ this.value = BigInteger.valueOf(value);
+ }
+
+ /**
+ * EFFECTS: Parse input and get the int value. Tags are parsed in {@link ASN1Object}.
+ * Throws {@link ParseException} if encoded value are invalid:
+ * - Early EOF (not enough bytes)
+ * - Zero bytes length
+ * - Other issues denoted in {@link ASN1Object}
+ * MODIFIES: this, encoded
+ */
+ public Int(BytesReader encoded, boolean hasParentTag) throws ParseException {
+ super(encoded, hasParentTag);
+ if (getLength() == 0) {
+ throw new ParseException("Integer with zero length");
+ }
+ this.value = new BigInteger(Utils.byteToByte(encoded.require(getLength(), true)));
+ }
+
+ /**
+ * EFFECTS: Produce the big-endian two's complement encoding of the value, in the shortest possible way (i.e., no
+ * leading 0x0 bytes, and no leading 0xFF bytes if negative). Notes, if a positive number is desired (or mandated
+ * like {@link TbsCertificate#getSerialNumber()}, append 0x0 to the MSB manually. This method always results in a
+ * signed integer. For simplicity, the first 0x0 is always removed except when the number itself is 0, and others
+ * are kept.
+ */
+ @Override
+ public Byte[] encodeValueDER() {
+ Byte[] bytes = Utils.byteToByte(value.toByteArray());
+ if (bytes.length == 1) {
+ return bytes;
+ }
+ if (bytes[0] == 0x0) {
+ return Arrays.stream(bytes)
+ .skip(1)
+ .toArray(Byte[]::new);
+ }
+ return bytes;
+ }
+
+ /**
+ * EFFECTS: Get the value in long.
+ * Throws {@link ArithmeticException} if the value is too large for long.
+ */
+ public long getLong() throws ArithmeticException {
+ return value.longValueExact();
+ }
+
+ public BigInteger getValue() {
+ return value;
+ }
+}