• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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