1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.subtle; 18 19 import java.nio.ByteBuffer; 20 import java.security.GeneralSecurityException; 21 import java.security.MessageDigest; 22 import java.util.Arrays; 23 24 /** 25 * Helper methods that deal with byte arrays. 26 * 27 * @since 1.0.0 28 */ 29 public final class Bytes { 30 /** 31 * Best effort fix-timing array comparison. 32 * 33 * @return true if two arrays are equal. 34 */ equal(final byte[] x, final byte[] y)35 public static final boolean equal(final byte[] x, final byte[] y) { 36 return MessageDigest.isEqual(x, y); 37 } 38 39 /** 40 * Returns the concatenation of the input arrays in a single array. For example, {@code concat(new 41 * byte[] {a, b}, new byte[] {}, new byte[] {c}} returns the array {@code {a, b, c}}. 42 * 43 * @return a single array containing all the values from the source arrays, in order 44 */ concat(byte[]... chunks)45 public static byte[] concat(byte[]... chunks) throws GeneralSecurityException { 46 int length = 0; 47 for (byte[] chunk : chunks) { 48 if (length > Integer.MAX_VALUE - chunk.length) { 49 throw new GeneralSecurityException("exceeded size limit"); 50 } 51 length += chunk.length; 52 } 53 byte[] res = new byte[length]; 54 int pos = 0; 55 for (byte[] chunk : chunks) { 56 System.arraycopy(chunk, 0, res, pos, chunk.length); 57 pos += chunk.length; 58 } 59 return res; 60 } 61 62 /** 63 * Computes the xor of two byte arrays, specifying offsets and the length to xor. 64 * 65 * @return a new byte[] of length len. 66 */ xor( final byte[] x, int offsetX, final byte[] y, int offsetY, int len)67 public static final byte[] xor( 68 final byte[] x, int offsetX, final byte[] y, int offsetY, int len) { 69 if (len < 0 || x.length - len < offsetX || y.length - len < offsetY) { 70 throw new IllegalArgumentException( 71 "That combination of buffers, offsets and length to xor result in out-of-bond accesses."); 72 } 73 byte[] res = new byte[len]; 74 for (int i = 0; i < len; i++) { 75 res[i] = (byte) (x[i + offsetX] ^ y[i + offsetY]); 76 } 77 return res; 78 } 79 80 /** 81 * Computes the xor of two byte buffers, specifying the length to xor, and stores the result to 82 * {@code output}. 83 */ xor(ByteBuffer output, ByteBuffer x, ByteBuffer y, int len)84 public static final void xor(ByteBuffer output, ByteBuffer x, ByteBuffer y, int len) { 85 if (len < 0 || x.remaining() < len || y.remaining() < len || output.remaining() < len) { 86 throw new IllegalArgumentException( 87 "That combination of buffers, offsets and length to xor result in out-of-bond accesses."); 88 } 89 for (int i = 0; i < len; i++) { 90 output.put((byte) (x.get() ^ y.get())); 91 } 92 } 93 94 /** 95 * Computes the xor of two byte arrays of equal size. 96 * 97 * @return a new byte[] of length x.length. 98 */ xor(final byte[] x, final byte[] y)99 public static final byte[] xor(final byte[] x, final byte[] y) { 100 if (x.length != y.length) { 101 throw new IllegalArgumentException("The lengths of x and y should match."); 102 } 103 return xor(x, 0, y, 0, x.length); 104 } 105 106 /** 107 * xors b to the end of a. 108 * 109 * @return a new byte[] of length x.length. 110 */ xorEnd(final byte[] a, final byte[] b)111 public static final byte[] xorEnd(final byte[] a, final byte[] b) { 112 if (a.length < b.length) { 113 throw new IllegalArgumentException("xorEnd requires a.length >= b.length"); 114 } 115 int paddingLength = a.length - b.length; 116 byte[] res = Arrays.copyOf(a, a.length); 117 for (int i = 0; i < b.length; i++) { 118 res[paddingLength + i] ^= b[i]; 119 } 120 return res; 121 } 122 123 /** 124 * Transforms a passed value to a LSB first byte array with the size of the specified capacity 125 * 126 * @param capacity size of the resulting byte array 127 * @param value that should be represented as a byte array. 0 <= value < 256^capacity. 128 */ intToByteArray(int capacity, int value)129 public static byte[] intToByteArray(int capacity, int value) { 130 if ((capacity > 4) || (capacity < 0)) { 131 throw new IllegalArgumentException("capacity must be between 0 and 4"); 132 } 133 // Check that 0 <= value < 256^capacity. 134 // For capacity == 4, all positive values are valid. 135 if (value < 0 || (capacity < 4 && (value >= 1 << (8 * capacity)))) { 136 throw new IllegalArgumentException("value too large"); 137 } 138 final byte[] result = new byte[capacity]; 139 for (int i = 0; i < capacity; i++) { 140 result[i] = (byte) ((value >> (8 * i)) & 0xFF); 141 } 142 return result; 143 } 144 145 /** 146 * Transforms a passed LSB first byte array to an int 147 * 148 * @param bytes that should be transformed to a byte array 149 */ byteArrayToInt(byte[] bytes)150 public static int byteArrayToInt(byte[] bytes) { 151 return byteArrayToInt(bytes, bytes.length); 152 } 153 154 /** 155 * Transforms a passed LSB first byte array to an int 156 * 157 * @param bytes that should be transformed to a byte array 158 * @param length amount of the passed {@code bytes} that should be transformed 159 */ byteArrayToInt(byte[] bytes, int length)160 public static int byteArrayToInt(byte[] bytes, int length) { 161 return byteArrayToInt(bytes, 0, length); 162 } 163 164 /** 165 * Transforms a passed LSB first byte array to an int 166 * 167 * @param bytes that should be transformed to a byte array 168 * @param offset start index to start the transformation 169 * @param length amount of the passed {@code bytes} that should be transformed 170 */ byteArrayToInt(byte[] bytes, int offset, int length)171 public static int byteArrayToInt(byte[] bytes, int offset, int length) { 172 if ((length > 4) || (length < 0)) { 173 throw new IllegalArgumentException("length must be between 0 and 4"); 174 } 175 if (offset < 0 || offset + length > bytes.length) { 176 throw new IllegalArgumentException("offset and length are out of bounds"); 177 } 178 int value = 0; 179 for (int i = 0; i < length; i++) { 180 value += (bytes[i + offset] & 0xFF) << (i * 8); 181 } 182 return value; 183 } 184 Bytes()185 private Bytes() {} 186 } 187