Package org.keyczar.util

Source Code of org.keyczar.util.Util

/*
* Copyright 2008 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 org.keyczar.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.keyczar.exceptions.KeyczarException;

import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
* A miscellaneous utility class. Includes random number generation, int-to-byte
* conversion, etc.
*
* @author steveweis@gmail.com (Steve Weis)
*
*/
public class Util {
  private static final ConcurrentLinkedQueue<MessageDigest> DIGEST_QUEUE =
    new ConcurrentLinkedQueue<MessageDigest>();
  private static final ConcurrentLinkedQueue<SecureRandom> RAND_QUEUE =
    new ConcurrentLinkedQueue<SecureRandom>();

  private Util() {
    // Don't new me.
  }

  private static final Gson GSON =
    new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

  public static Gson gson() {
    return GSON;
  }

  public static byte[] stripLeadingZeros(byte[] input) {
    int zeros = 0;
   
    // Find the first non-zero byte
    while (zeros < input.length && input[zeros] == 0) {
      zeros++;
    }
   
    if (zeros == 0) {
      return input;
    } else {
      byte[] output = new byte[input.length - zeros];
      System.arraycopy(input, zeros, output, 0, output.length);
      return output;
    }
  }
 
  /**
   * Returns a byte array containing 4 big-endian ordered bytes representing the
   * given integer.
   *
   * @param input The integer to convert to a byte array.
   * @return A byte array representation of an integer.
   */
  public static byte[] fromInt(int input) {
    byte[] output = new byte[4];
    writeInt(input, output, 0);
    return output;
  }

  /**
   * Returns a byte array containing 8 big-endian ordered bytes representing the
   * given long.
   *
   * @param input The long to convert to a byte array.
   * @return A byte array representation of a long.
   */
  public static byte[] fromLong(long input) {
    byte[] output = new byte[8];
    writeLong(input, output, 0);
    return output;
  }

  /**
   * Takes a variable number of byte arrays as input and hashes each one
   * prefixed by an integer representation of its size. For example,
   * prefixHash({0, 1, 2}, {1}) would hash the bytes equivalent to:
   * {3, 0, 1, 2, 1, 1}
   *
   * @param inputs The inputs to hash
   * @return The hash output
   * @throws KeyczarException If the SHA-1 algorithm is not found
   */
  public static byte[] prefixHash(byte[]... inputs) throws KeyczarException {
    MessageDigest md = DIGEST_QUEUE.poll();
    if (md == null) {
      try {
        md = MessageDigest.getInstance("SHA-1");
      } catch (NoSuchAlgorithmException e) {
        throw new KeyczarException(e);
      }
    }
    for (byte[] array : inputs) {
      md.update(fromInt(array.length));
      md.update(array);
    }
    byte[] digest = md.digest();
    DIGEST_QUEUE.add(md);
    return digest;
  }
 
  /**
   * Packs a set of input arrays into a single array. The packed array is
   * prefixed by an integer value of the number of arrays. Then each individual
   * array is prefixed by its length, followed by the contents of the array
   * itself. Thus, three arrays A, B, C would output:
   *   {3, len(A), A, len(B), B, len(C), C}
   *
   * @param inputArrays A list of arrays to pack together
   * @return A packed list of arrays, with each preceded by its integer length
   */
  public static byte[] lenPrefixPack(byte[]... inputArrays) {
    // Count an int for each input array
    int outputSize = (1 + inputArrays.length) * 4;
    for (byte[] array : inputArrays) {
      outputSize += array.length;
    }
    byte[] output = new byte[outputSize];
    ByteBuffer outputBuffer = ByteBuffer.wrap(output);
    // Put the number of total arrays
    outputBuffer.putInt(inputArrays.length);
    for (byte[] array : inputArrays) {
      // Put the size of this array
      outputBuffer.putInt(array.length);
      // Put the array itself
      outputBuffer.put(array);
    }
    return output;
  }
 
  /**
   * Unpack an input buffer into an array of byte arrays
   *
   * @param packedInput A packed representation of an array of byte arrays
   * @return A two dimensional array of arrays
   */
  public static byte[][] lenPrefixUnpack(byte[] packedInput) {
    ByteBuffer input = ByteBuffer.wrap(packedInput);
    int numArrays = input.getInt();
    byte[][] output = new byte[numArrays][];
    for (int i = 0; i < numArrays; i++) {
      int len = input.getInt();
      byte[] array = new byte[len];
      input.get(array);
      output[i] = array;
    }
    return output;
  }
 
  /**
   * Hashes a variable number of byte arrays
   *
   * @param inputs The inputs to hash
   * @return The hash output
   * @throws KeyczarException If the SHA-1 algorithm is not found
   */
  public static byte[] hash(byte[]... inputs) throws KeyczarException {
    MessageDigest md = DIGEST_QUEUE.poll();
    if (md == null) {
      try {
        md = MessageDigest.getInstance("SHA-1");
      } catch (NoSuchAlgorithmException e) {
        throw new KeyczarException(e);
      }
    }
    for (byte[] array : inputs) {
      md.update(array);
    }
    byte[] digest = md.digest();
    DIGEST_QUEUE.add(md);
    return digest;
  }

  /**
   * Write random bytes into the destination. Uses pre-cached secure random
   * objects
   *
   * @param dest Destionation to write the data
   */
  public static void rand(byte[] dest) {
    SecureRandom random = RAND_QUEUE.poll();
    if (random == null) {
      random = new SecureRandom();
    }
    random.nextBytes(dest);
    RAND_QUEUE.add(random);
  }

  /**
   * Returns an array of random bytes of the given length
   * @param len The length of the random array to output
   * @return A random array of bytes
   */
  public static byte[] rand(int len) {
    byte[] output = new byte[len];
    rand(output);
    return output;
  }

  /**
   * Reads 4 big-endian ordered bytes from a given offset in an array and
   * returns an integer representation.
   *
   * This method does not check the source array length.
   *
   * @param src The source array to read bytes from
   * @param offset The offset to start reading bytes from.
   * @return The integer value represented by the source array from the offset
   */
  static int readInt(byte[] src, int offset) {
    int output = 0;
    output |= (src[offset++] & 0xFF) << 24;
    output |= (src[offset++] & 0xFF) << 16;
    output |= (src[offset++] & 0xFF) << 8;
    output |= (src[offset++] & 0xFF);
    return output;
  }

  /**
   * Reads 8 big-endian ordered bytes from a given offset in an array and
   * returns a long representation.
   *
   * This method does not check the source array length.
   *
   * @param src The source array to read bytes from
   * @param offset The offset to start reading bytes from.
   * @return The long value represented by the source array from the offset
   */
  static long readLong(byte[] src, int offset) {
    long output = 0;
    output |= (src[offset++] & 0xFFL) << 56;
    output |= (src[offset++] & 0xFFL) << 48;
    output |= (src[offset++] & 0xFFL) << 40;
    output |= (src[offset++] & 0xFFL) << 32;
    output |= (src[offset++] & 0xFFL) << 24;
    output |= (src[offset++] & 0xFFL) << 16;
    output |= (src[offset++] & 0xFFL) << 8;
    output |= (src[offset++] & 0xFFL);
    return output;
  }

  /**
   * Converts a given byte array to an integer. Reads the bytes in big-endian
   * order.
   *
   * This method does not check the source array length.
   *
   * @param src A big-endian representation of an integer
   * @return The integer value represented by the source array
   */
  public static int toInt(byte[] src) {
    return readInt(src, 0);
  }

  /**
   * Converts a given byte array to a long. Reads the bytes in big-endian order.
   *
   * This method does not check the source array length.
   *
   * @param src A big-endian representation of a long
   * @return The long value represented by the source array
   */
  public static long toLong(byte[] src) {
    return readLong(src, 0);
  }

  /**
   * Writes 4 big-endian ordered bytes representing the given integer into the
   * destination byte array starting from the given offset.
   *
   * This method does not check the destination array length.
   *
   * @param input The integer to convert to bytes
   * @param dest The array in which to write the integer byte representation
   * @param offset The offset to start writing the bytes from
   */
  static void writeInt(int input, byte[] dest, int offset) {
    dest[offset++] = (byte) (input >> 24);
    dest[offset++] = (byte) (input >> 16);
    dest[offset++] = (byte) (input >> 8);
    dest[offset++] = (byte) (input);
  }

  /**
   * Writes 8 big-endian ordered bytes representing the given long into the
   * destination byte array starting from the given offset.
   *
   * This method does not check the destination array length.
   *
   * @param input The long to convert to bytes
   * @param dest The array in which to write the long byte representation
   * @param offset The offset to start writing the bytes from
   */
  static void writeLong(long input, byte[] dest, int offset) {
    dest[offset++] = (byte) (input >> 56);
    dest[offset++] = (byte) (input >> 48);
    dest[offset++] = (byte) (input >> 40);
    dest[offset++] = (byte) (input >> 32);
    dest[offset++] = (byte) (input >> 24);
    dest[offset++] = (byte) (input >> 16);
    dest[offset++] = (byte) (input >> 8);
    dest[offset++] = (byte) (input);
  }
 
  /**
   * An array comparison that is safe from timing attacks. If two arrays are
   * of equal length, this code will always check all elements, rather than
   * exiting once it encounters a differing byte.
   *
   * @param a1 An array to compare
   * @param a2 Another array to compare
   * @return True if these arrays are both null or if they have equal length
   *         and equal bytes in all elements
   */
  public static boolean safeArrayEquals(byte[] a1, byte[] a2) {
    if (a1 == null || a2 == null) {
        return (a1 == a2);
    }
    if (a1.length != a2.length) {
      return false;
    }
    byte result = 0;
    for (int i = 0; i < a1.length; i++) {
      result |= a1[i] ^ a2[i];
    }
    return (result == 0);
  }
}
TOP

Related Classes of org.keyczar.util.Util

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.