All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.crypto.tink.subtle.Bytes Maven / Gradle / Ivy

// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.subtle;

import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;

/**
 * Helper methods that deal with byte arrays.
 *
 * @since 1.0.0
 */
public final class Bytes {
  /**
   * Best effort fix-timing array comparison.
   *
   * @return true if two arrays are equal.
   */
  public static final boolean equal(final byte[] x, final byte[] y) {
    return MessageDigest.isEqual(x, y);
  }

  /**
   * Returns the concatenation of the input arrays in a single array. For example, {@code concat(new
   * byte[] {a, b}, new byte[] {}, new byte[] {c}} returns the array {@code {a, b, c}}.
   *
   * @return a single array containing all the values from the source arrays, in order
   */
  public static byte[] concat(byte[]... chunks) throws GeneralSecurityException {
    int length = 0;
    for (byte[] chunk : chunks) {
      if (length > Integer.MAX_VALUE - chunk.length) {
        throw new GeneralSecurityException("exceeded size limit");
      }
      length += chunk.length;
    }
    byte[] res = new byte[length];
    int pos = 0;
    for (byte[] chunk : chunks) {
      System.arraycopy(chunk, 0, res, pos, chunk.length);
      pos += chunk.length;
    }
    return res;
  }

  /**
   * Computes the xor of two byte arrays, specifying offsets and the length to xor.
   *
   * @return a new byte[] of length len.
   */
  public static final byte[] xor(
      final byte[] x, int offsetX, final byte[] y, int offsetY, int len) {
    if (len < 0 || x.length - len < offsetX || y.length - len < offsetY) {
      throw new IllegalArgumentException(
          "That combination of buffers, offsets and length to xor result in out-of-bond accesses.");
    }
    byte[] res = new byte[len];
    for (int i = 0; i < len; i++) {
      res[i] = (byte) (x[i + offsetX] ^ y[i + offsetY]);
    }
    return res;
  }

  /**
   * Computes the xor of two byte buffers, specifying the length to xor, and stores the result to
   * {@code output}.
   */
  public static final void xor(ByteBuffer output, ByteBuffer x, ByteBuffer y, int len) {
    if (len < 0 || x.remaining() < len || y.remaining() < len || output.remaining() < len) {
      throw new IllegalArgumentException(
          "That combination of buffers, offsets and length to xor result in out-of-bond accesses.");
    }
    for (int i = 0; i < len; i++) {
      output.put((byte) (x.get() ^ y.get()));
    }
  }

  /**
   * Computes the xor of two byte arrays of equal size.
   *
   * @return a new byte[] of length x.length.
   */
  public static final byte[] xor(final byte[] x, final byte[] y) {
    if (x.length != y.length) {
      throw new IllegalArgumentException("The lengths of x and y should match.");
    }
    return xor(x, 0, y, 0, x.length);
  }

  /**
   * xors b to the end of a.
   *
   * @return a new byte[] of length x.length.
   */
  public static final byte[] xorEnd(final byte[] a, final byte[] b) {
    if (a.length < b.length) {
      throw new IllegalArgumentException("xorEnd requires a.length >= b.length");
    }
    int paddingLength = a.length - b.length;
    byte[] res = Arrays.copyOf(a, a.length);
    for (int i = 0; i < b.length; i++) {
      res[paddingLength + i] ^= b[i];
    }
    return res;
  }

  // TODO(thaidn): add checks for boundary conditions/overflows.
  /**
   * Transforms a passed value to a LSB first byte array with the size of the specified capacity
   *
   * @param capacity size of the resulting byte array
   * @param value that should be represented as a byte array
   */
  public static byte[] intToByteArray(int capacity, int value) {
    final byte[] result = new byte[capacity];
    for (int i = 0; i < capacity; i++) {
      result[i] = (byte) ((value >> (8 * i)) & 0xFF);
    }
    return result;
  }

  /**
   * Transforms a passed LSB first byte array to an int
   *
   * @param bytes that should be transformed to a byte array
   */
  public static int byteArrayToInt(byte[] bytes) {
    return byteArrayToInt(bytes, bytes.length);
  }

  /**
   * Transforms a passed LSB first byte array to an int
   *
   * @param bytes that should be transformed to a byte array
   * @param length amount of the passed {@code bytes} that should be transformed
   */
  public static int byteArrayToInt(byte[] bytes, int length) {
    return byteArrayToInt(bytes, 0, length);
  }

  /**
   * Transforms a passed LSB first byte array to an int
   *
   * @param bytes that should be transformed to a byte array
   * @param offset start index to start the transformation
   * @param length amount of the passed {@code bytes} that should be transformed
   */
  public static int byteArrayToInt(byte[] bytes, int offset, int length) {
    int value = 0;
    for (int i = 0; i < length; i++) {
      value += (bytes[i + offset] & 0xFF) << (i * 8);
    }
    return value;
  }

  private Bytes() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy