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)); } }