/** * TLS-Attacker - A Modular Penetration Testing Framework for TLS * * Copyright 2014-2016 Ruhr University Bochum / Hackmanit GmbH * * Licensed under Apache License 2.0 * http://www.apache.org/licenses/LICENSE-2.0 */ package de.rub.nds.tlsattacker.util; import java.lang.reflect.Array; import java.math.BigInteger; import java.util.List; /** * @author Juraj Somorovsky <juraj.somorovsky@rub.de> */ public class ArrayConverter { /** * Takes a long value and converts it to 8 bytes (needed for example to * convert SQN numbers in TLS records) * * @param l * @return */ public static final byte[] longToUint64Bytes(long l) { byte[] result = new byte[8]; result[0] = (byte) (l >>> 56); result[1] = (byte) (l >>> 48); result[2] = (byte) (l >>> 40); result[3] = (byte) (l >>> 32); result[4] = (byte) (l >>> 24); result[5] = (byte) (l >>> 16); result[6] = (byte) (l >>> 8); result[7] = (byte) (l); return result; } /** * Takes a long value and converts it to 4 bytes * * @param l * @return */ public static final byte[] longToUint32Bytes(long l) { byte[] result = new byte[4]; result[0] = (byte) (l >>> 24); result[1] = (byte) (l >>> 16); result[2] = (byte) (l >>> 8); result[3] = (byte) (l); return result; } /** * Takes an integer value and stores its last bytes into a byte array * * @param value * integer value * @param size * byte size of the new integer byte array * @return */ public static final byte[] intToBytes(int value, int size) { if (size < 1) { throw new IllegalArgumentException("The array must be at least of size 1"); } byte[] result = new byte[size]; int shift = 0; for (int i = size - 1; i >= 0; i--) { result[i] = (byte) (value >>> shift); shift += 8; } return result; } /** * Takes a long value and stores its last bytes into a byte array * * @param value * long value * @param size * byte size of the new integer byte array * @return */ public static final byte[] longToBytes(long value, int size) { if (size < 1) { throw new IllegalArgumentException("The array must be at least of size 1"); } byte[] result = new byte[size]; int shift = 0; for (int i = size - 1; i >= 0; i--) { result[i] = (byte) (value >>> shift); shift += 8; } return result; } /** * Converts multiple bytes into one int value * * @param value * @return */ public static final int bytesToInt(byte[] value) { int result = 0; int shift = 0; for (int i = value.length - 1; i >= 0; i--) { result += (value[i] & 0xFF) << shift; shift += 8; } return result; } /** * Converts multiple bytes into one long value * * @param value * @return */ public static final long bytesToLong(byte[] value) { int result = 0; int shift = 0; for (int i = value.length - 1; i >= 0; i--) { result += (value[i] & 0xFF) << shift; shift += 8; } return result; } public static String bytesToHexString(byte[] array) { if (array == null) { array = new byte[0]; } return bytesToHexString(array, array.length); } public static String bytesToHexString(byte[] array, int byteSize) { boolean usePrettyPrinting = (byteSize > 15); return bytesToHexString(array, byteSize, usePrettyPrinting); } public static String bytesToHexString(byte[] array, boolean usePrettyPrinting) { if (array == null) { array = new byte[0]; } return bytesToHexString(array, array.length, usePrettyPrinting); } public static String bytesToHexString(byte[] array, int byteSize, boolean usePrettyPrinting) { StringBuilder result = new StringBuilder(); if (usePrettyPrinting) { result.append("\n "); } int bs = (byteSize < array.length) ? byteSize : array.length; for (int i = 0; i < bs; i++) { if (usePrettyPrinting && i != 0) { if (i % 16 == 0) { result.append("\n "); } else if (i % 8 == 0) { result.append(" "); } } byte b = array[i]; result.append(String.format("%02X ", b)); } return result.toString(); } @SafeVarargs public static <T> T[] concatenate(final T[]... arrays) { if (arrays == null || arrays.length == 0) { throw new IllegalArgumentException("The minimal number of parameters for this function is one"); } int length = 0; for (final T[] a : arrays) { length += a.length; } @SuppressWarnings("unchecked") T[] result = (T[]) Array.newInstance(arrays[0].getClass().getComponentType(), length); int currentOffset = 0; for (final T[] a : arrays) { System.arraycopy(a, 0, result, currentOffset, a.length); currentOffset += a.length; } return result; } public static byte[] concatenate(final byte[]... arrays) { if (arrays == null || arrays.length == 0) { throw new IllegalArgumentException("The minimal number of parameters for this function is one"); } int length = 0; for (final byte[] a : arrays) { if (a != null) { length += a.length; } } byte[] result = new byte[length]; int currentOffset = 0; for (final byte[] a : arrays) { if (a != null) { System.arraycopy(a, 0, result, currentOffset, a.length); currentOffset += a.length; } } return result; } public static byte[] concatenate(final byte[] array1, final byte[] array2, int numberOfArray2Bytes) { int length = array1.length + numberOfArray2Bytes; byte[] result = new byte[length]; System.arraycopy(array1, 0, result, 0, array1.length); System.arraycopy(array2, 0, result, array1.length, numberOfArray2Bytes); return result; } public static void makeArrayNonZero(final byte[] array) { for (int i = 0; i < array.length; i++) { if (array[i] == 0) { array[i] = 1; } } } /** * Takes a BigInteger value and returns its byte array representation filled * with 0x00 bytes to achieve the block size length. * * @param value * @param blockSize * @param removeSignByte * in a case the removeSignByte is set, the sign byte is removed * (in case the byte array contains one) * @return */ public static byte[] bigIntegerToByteArray(BigInteger value, int blockSize, boolean removeSignByte) { byte[] array = value.toByteArray(); int remainder = array.length % blockSize; byte[] result = array; byte[] tmp; if (removeSignByte && result[0] == 0x0) { tmp = new byte[result.length - 1]; System.arraycopy(result, 1, tmp, 0, tmp.length); result = tmp; remainder = tmp.length % blockSize; } if (remainder > 0) { // add zeros to fit size tmp = new byte[result.length + blockSize - remainder]; System.arraycopy(result, 0, tmp, blockSize - remainder, result.length); result = tmp; } return result; } /** * Takes a BigInteger value and returns its byte array representation, if * necessary the sign byte is removed. * * @param value * @return */ public static byte[] bigIntegerToByteArray(BigInteger value) { byte[] result = value.toByteArray(); if (result[0] == 0x0) { byte[] tmp = new byte[result.length - 1]; System.arraycopy(result, 1, tmp, 0, tmp.length); result = tmp; } return result; } /** * Converts a list of BigIntegers to an array * * @param list * @return */ public static BigInteger[] convertListToArray(List<BigInteger> list) { BigInteger[] result = new BigInteger[list.size()]; for (int i = 0; i < list.size(); i++) { result[i] = list.get(i); } return result; } /** * Converts a string with an even number of hexadecimal characters to a byte * array. * * @param input * @return */ public static byte[] hexStringToByteArray(String input) { if ((input == null) || (input.length() % 2 != 0)) { throw new IllegalArgumentException("The input must not be null and " + "shall have an even number of hexadecimal characters. Found: " + input); } byte[] output = new byte[input.length() / 2]; for (int i = 0; i < output.length; i++) { output[i] = (byte) ((Character.digit(input.charAt(i * 2), 16) << 4) + Character.digit( input.charAt(i * 2 + 1), 16)); } return output; } /** * Converts a BigInteger into a byte array of given size. If the BigInteger * doesn't fit into the byte array, bits of the BigInteger will simply be * truncated, starting with the most significant bit. If the array is larger * than the BigInteger, prepending bytes in the array will be 0x00. * * @param input * @param outputSizeInBytes * @return */ public static byte[] bigIntegerToNullPaddedByteArray(BigInteger input, int outputSizeInBytes) { if (input == null) { throw new IllegalArgumentException("'input' must not be null."); } byte[] output = new byte[outputSizeInBytes]; int numByteBlocks = input.bitLength() / 8; int remainingBits; if (numByteBlocks < output.length) { remainingBits = input.bitLength() % 8; } else { remainingBits = 0; numByteBlocks = output.length; } int i; for (i = 0; i < numByteBlocks; i++) { output[output.length - 1 - i] = input.shiftRight(i * 8).byteValue(); } if (remainingBits > 0) { output[output.length - 1 - i] = input.shiftRight(i * 8).byteValue(); } return output; } public static byte[] longToUint48Bytes(long input) { byte[] output = new byte[6]; output[0] = (byte) (input >>> 40); output[1] = (byte) (input >>> 32); output[2] = (byte) (input >>> 24); output[3] = (byte) (input >>> 16); output[4] = (byte) (input >>> 8); output[5] = (byte) input; return output; } }