package cn.hyperchain.sdk.common.utils; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; public class ByteUtil { public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; /** * transfer bytes to hex string. * * @param data bytes * @return hex string */ public static String toHex(byte[] data) { return data == null ? "" : Hex.toHexString(data); } /** * transfer hex string to bytes. * * @param hex hex string * @return bytes */ public static byte[] fromHex(String hex) { if (hex == null) { return EMPTY_BYTE_ARRAY; } if (hex.startsWith("0x")) { hex = hex.substring(2); } if ((hex.length() & 1) == 1) { hex = "0" + hex; } return Hex.decode(hex); } /** * decode hex string to utf-8 string. * * @param hex hex string * @return utf-8 string */ public static String decodeHex(String hex) { return new String(fromHex(hex), StandardCharsets.UTF_8); } /** * transfer short type two bytes. * * @param n short value * @return two bytes */ public static byte[] shortToBytes(short n) { return ByteBuffer.allocate(2).putShort(n).array(); } /** * transfer int type to four bytes. * * @param i int value * @return four bytes */ public static byte[] intToByteArray(int i) { byte[] result = new byte[4]; result[0] = (byte) ((i >> 24) & 0xFF); result[1] = (byte) ((i >> 16) & 0xFF); result[2] = (byte) ((i >> 8) & 0xFF); result[3] = (byte) (i & 0xFF); return result; } /** * The regular {@link BigInteger#toByteArray()} method isn't quite what we often need: * it appends a leading zero to indicate that the number is positive and may need padding. * * @param b the integer to format into a byte array * @param numBytes the desired size of the resulting byte array * @return numBytes byte long array. */ public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { if (b == null) { return null; } byte[] bytes = new byte[numBytes]; byte[] biBytes = b.toByteArray(); int start = (biBytes.length == numBytes + 1) ? 1 : 0; int length = Math.min(biBytes.length, numBytes); System.arraycopy(biBytes, start, bytes, numBytes - length, length); return bytes; } /** * convert BigInteger to signed bytes. * * @param b BigInteger * @param numBytes the desired size * @return numBytes byte long array */ public static byte[] bigIntegerToBytesSigned(BigInteger b, int numBytes) { if (b == null) { return null; } byte[] bytes = new byte[numBytes]; Arrays.fill(bytes, b.signum() < 0 ? (byte) 0xFF : 0x00); byte[] biBytes = b.toByteArray(); int start = (biBytes.length == numBytes + 1) ? 1 : 0; int length = Math.min(biBytes.length, numBytes); System.arraycopy(biBytes, start, bytes, numBytes - length, length); return bytes; } /** * @param arrays - arrays to merge. * @return - merged array */ public static byte[] merge(byte[]... arrays) { int arrCount = 0; int count = 0; for (byte[] array : arrays) { arrCount++; count += array.length; } // Create new array and copy all array contents byte[] mergedArray = new byte[count]; int start = 0; for (byte[] array : arrays) { System.arraycopy(array, 0, mergedArray, start, array.length); start += array.length; } return mergedArray; } /** * transfer BigInteger to 32 bytes. * * @param n BigInteger * @return 32 bytes */ public static byte[] biConvert32Bytes(BigInteger n) { byte[] tmpd = null; if (n == null) { return new byte[0]; } if (n.toByteArray().length == 33) { tmpd = new byte[32]; System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32); } else if (n.toByteArray().length == 32) { tmpd = n.toByteArray(); } else { tmpd = new byte[32]; for (int i = 0; i < 32 - n.toByteArray().length; i++) { tmpd[i] = 0; } System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length); } return tmpd; } /** * todo this is hex encoded value, but method bytesToInteger is not * Cast hex encoded value from byte[] to BigInteger. * null is parsed like byte[0] * * @param bb byte array contains the values * @return unsigned positive BigInteger value. */ public static BigInteger bytesToBigInteger(byte[] bb) { return (bb == null || bb.length == 0) ? BigInteger.ZERO : new BigInteger(1, bb); } /** * Cast byte[] to int. * * @param bytes byte array contains the values * @return int value */ public static int bytesToInteger(byte[] bytes) { if (bytes.length > 4) { throw new IndexOutOfBoundsException("int can only load 4 bytes"); } int n = 0; int temp = 0; for (byte b : bytes) { n <<= 8; temp = b & 0xFF; n |= temp; } return n; } /** * transfer hex string to base64 string. * @param hexOrigin hex string * @return base64 string */ public static String hex2Base64(String hexOrigin) { return base64(ByteUtil.fromHex(hexOrigin)); } /** * encode bytes to base64 string. * @param data bytes * @return base64 string */ public static String base64(byte[] data) { return Base64.toBase64String(data); } /** * copy some bytes array from offset. * * @param origin origin bytes * @param offset from offset * @param length copy length * @return result */ public static byte[] copy(byte[] origin, int offset, int length) { if (origin.length <= offset || origin.length < offset + length) { throw new IndexOutOfBoundsException("the origin array length is " + origin.length); } byte[] newArray = new byte[length]; System.arraycopy(origin, offset, newArray, 0, length); return newArray; } }