From d342a45d98c4795b3a3fe1aaef5236ad4a782b55 Mon Sep 17 00:00:00 2001 From: Yuuta Liang Date: Thu, 12 Oct 2023 12:10:33 +0800 Subject: Implement data structures from X.680, X.501, X.509, and PKCS#10, with X.690 encoding / decoding support The implementation took four days, and it is still a little bit rough. Updated version should arrive soon. Signed-off-by: Yuuta Liang --- src/main/ui/Utils.java | 105 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/main/ui/Utils.java (limited to 'src/main/ui') diff --git a/src/main/ui/Utils.java b/src/main/ui/Utils.java new file mode 100644 index 0000000..ccb244e --- /dev/null +++ b/src/main/ui/Utils.java @@ -0,0 +1,105 @@ +package ui; + +import model.asn1.exceptions.ParseException; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Useful small methods for the whole program. + */ +public final class Utils { + /** + * EFFECTS: Convert the input primitive byte array into the boxed Byte array. + */ + public static Byte[] byteToByte(byte[] array) { + Byte[] arr = new Byte[array.length]; + for (int i = 0; i < arr.length; i++) { + arr[i] = array[i]; + } + return arr; + } + + /** + * EFFECTS: Convert the input boxed Byte array into primitive byte array. + */ + public static byte[] byteToByte(Byte[] array) { + byte[] arr = new byte[array.length]; + for (int i = 0; i < arr.length; i++) { + arr[i] = array[i]; + } + return arr; + } + + /** + * EFFECTS: Pack the big-endian bytes into a 32bit integer. + * Throws {@link model.asn1.exceptions.ParseException} if the value is too large. + */ + public static int bytesToInt(Byte[] array) throws ParseException { + try { + return new BigInteger(byteToByte(array)).intValueExact(); + } catch (ArithmeticException ignored) { + throw new ParseException("Value is too large."); + } + } + + /** + * EFFECTS: Pack the big-endian bytes into a 64bit integer. + * Throws {@link model.asn1.exceptions.ParseException} if the value is too large. + */ + public static long bytesToLong(Byte[] array) throws ParseException { + try { + return new BigInteger(byteToByte(array)).longValueExact(); + } catch (ArithmeticException ignored) { + throw new ParseException("Value is too large."); + } + } + + /** + * EFFECTS: Unpack the multibyte 64bit integer to its shortest array of byte format. + */ + public static Byte[] valToByte(long val) { + byte[] v = BigInteger.valueOf(val).toByteArray(); + if (val != 0 && v[0] == 0) { + if (v.length == 1) { + return new Byte[0]; + } + byte[] arr = new byte[v.length - 1]; + System.arraycopy(v, 1, arr, 0, arr.length); + return byteToByte(arr); + } + return byteToByte(v); + } + + /** + * EFFECTS: Parse the two-digit octet string into an unsigned byte, preserving leading zero and negative values. + * REQUIRES: The input octet must be a two-char string, with each char matching [0-9][A-F]. + */ + public static Byte parseByte(String octet) { + return (byte) Integer.parseInt(octet, 16); + } + + /** + * EFFECTS: Decode the input PEM file, with optional check on tags. + * Throws {@link ParseException} if the desiredTag is specified but the input does not have the specific tag, or + * if the input does not have any tags at all (not a PEM). + */ + public static Byte[] parsePEM(Byte[] input, String desiredTag) throws ParseException { + final String str = new String(byteToByte(input), StandardCharsets.UTF_8); + Pattern pattern = + Pattern.compile("^-----BEGIN " + desiredTag + + "-----$\n^(.*)$\n^-----END " + desiredTag + "-----$", + Pattern.DOTALL | Pattern.MULTILINE); + final Matcher matcher = pattern.matcher(str); + if (!matcher.matches()) { + throw new ParseException("Not a valid PEM"); + } + final String b64 = matcher.group(1).replace("\n", ""); + return byteToByte(Base64.getDecoder().decode(b64)); + } +} -- cgit v1.2.3