Package freenet.crypt

Source Code of freenet.crypt.Util

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.crypt;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.DigestException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import net.i2p.util.NativeBigInteger;
import freenet.crypt.JceLoader;
import freenet.crypt.ciphers.Rijndael;
import freenet.support.HexUtil;
import freenet.support.Loader;
import freenet.support.Logger;
import freenet.support.math.MersenneTwister;

public class Util {

  // bah, i'm tired of chasing down dynamically loaded classes..
  // this is for getCipherByName()
  static {
    Rijndael.class.toString();
  }

  protected static final int BUFFER_SIZE = 32768;

  public static void fillByteArrayFromInts(int[] ints, byte[] bytes) {
    int ic = 0;
    for (int i: ints) {
      bytes[ic++] = (byte) (i >> 24);
      bytes[ic++] = (byte) (i >> 16);
      bytes[ic++] = (byte) (i >> 8);
      bytes[ic++] = (bytei;
    }
  }

  public static void fillByteArrayFromLongs(long[] ints, byte[] bytes) {
    int ic = 0;
    for (long l: ints) {
      bytes[ic++] = (byte) (l >> 56);
      bytes[ic++] = (byte) (l >> 48);
      bytes[ic++] = (byte) (l >> 40);
      bytes[ic++] = (byte) (l >> 32);
      bytes[ic++] = (byte) (l >> 24);
      bytes[ic++] = (byte) (l >> 16);
      bytes[ic++] = (byte) (l >> 8);
      bytes[ic++] = (bytel;
    }
  }

  // Crypto utility methods:
  public static final NativeBigInteger TWO = new NativeBigInteger(BigInteger.valueOf(2));

  // we should really try reading the JFC documentation sometime..
  // - the byte array generated by BigInteger.toByteArray() is
  //   compatible with the BigInteger(byte[]) constructor
  // - the byte length is ceil((bitLength()+1) / 8)

  public static byte[] MPIbytes(BigInteger num) {
    int len = num.bitLength();
    byte[] bytes = new byte[2 + ((len + 8) >> 3)];
    System.arraycopy(num.toByteArray(), 0, bytes, 2, bytes.length - 2);
    bytes[0] = (byte) (len >> 8);
    bytes[1] = (byte) len;
    return bytes;
  }

  public static void writeMPI(BigInteger num, OutputStream out)
    throws IOException {
    out.write(MPIbytes(num));
  }

  public static BigInteger readMPI(InputStream in) throws IOException {
    int b1 = in.read();
    int b2 = in.read();
    if ((b1 == -1) || (b2 == -1))
      throw new EOFException();
    byte[] data = new byte[(((b1 << 8) + b2) + 8) >> 3];
    readFully(in, data, 0, data.length);
    //(new DataInputStream(in)).readFully(data, 0, data.length);
    // REDFLAG: This can't possibly be negative, right?
    return new NativeBigInteger(1, data);
  }

  public static byte[] hashBytes(MessageDigest d, byte[] b) {
    return hashBytes(d, b, 0, b.length);
  }

  public static byte[] hashBytes(
    MessageDigest d,
    byte[] b,
    int offset,
    int length) {
    d.update(b, offset, length);
    return d.digest();
  }

  /**
   * Hashes a string in a consistent manner
   */
  public static byte[] hashString(MessageDigest d, String s) {
    try {
      byte[] sbytes = s.getBytes("UTF-8");
      d.update(sbytes, 0, sbytes.length);
      return d.digest();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  public static byte[] xor(byte[] b1, byte[] b2) {
    int maxl = Math.max(b1.length, b2.length);
    byte[] rv = new byte[maxl];

    int minl = Math.min(b1.length, b2.length);
    for (int i = 0; i < minl; i++)
      rv[i] = (byte) (b1[i] ^ b2[i]);
    return rv;
  }

  static public void randomBytes(SecureRandom r, byte[] buf) {
    r.nextBytes(buf);
  }

  static public void randomBytes(SecureRandom r, byte[] buf, int from, int len) {
    randomBytesSlowNextInt(r, buf, from, len);
  }

  /** Fill specified range of byte array with random data. */
  static private void randomBytesSlowNextInt(Random r, byte[] buf, int from, int len) {
     if (from == 0 && len == buf.length) {
       r.nextBytes(buf);
       return;
     }
     byte [] tmp = new byte[len];
     r.nextBytes(tmp);
     System.arraycopy(tmp, 0, buf, from, len);
  }

  /** Fill byte array with random data.
   * randomBytes(random, buf) is same as random.nextBytes(buf)
   */
  static public void randomBytes(Random r, byte[] buf) {
    randomBytes(r, buf, 0, buf.length);
  }

  /** Fill specified range of byte array with random data.
   * Optimised version for Random with fast nextInt().
   * Must be same as randomBytesSlowNextInt(buf, from, len).
   * WARNING: full compatibility with randomBytesSlowNextInt() is *critical*!
   */
  /*
   * Why, why, why? Why Random have no nextBytes(buf, from, len) method?
   */
  static public void randomBytes(Random r, byte[] buf, int from, int len) {
    if (!(r instanceof MersenneTwister)) {
      /* SecureRandom's nextInt() have *abysmal* performance */
      /* But more generally we can't guarantee this will work except for MT. */
      randomBytesSlowNextInt(r, buf, from, len);
      return;
    }
    assert(Integer.SIZE/Byte.SIZE == 4);
    final int to = from + len;
    while(from + 4 <= to) {
      int rnd = r.nextInt();
      buf[from++] = (byte)rnd; rnd >>= 8;
      buf[from++] = (byte)rnd; rnd >>= 8;
      buf[from++] = (byte)rnd; rnd >>= 8;
      buf[from++] = (byte)rnd; rnd >>= 8;
    }
    if(to > from) {
      assert(to - from < Integer.SIZE/Byte.SIZE);
      for (int rnd = r.nextInt(); from < to; rnd >>= 8)
        buf[from++] = (byte)rnd;
    }
  }
 
  @Deprecated // use freenet.support.Fields instead
  public static boolean byteArrayEqual(byte[] a, byte[] b, int offset, int length) {
    return freenet.support.Fields.byteArrayEqual(a, b, offset, offset, length);
  }

  private static final MessageDigest ctx;
  private static final int ctx_length;

  public static final Map<String, Provider> mdProviders;

  static private long benchmark(MessageDigest md) throws GeneralSecurityException
  {
    long times = Long.MAX_VALUE;
    byte[] input = new byte[1024];
    byte[] output = new byte[md.getDigestLength()];
    // warm-up
    for (int i = 0; i < 32; i++) {
      md.update(input, 0, input.length);
      md.digest(output, 0, output.length);
      System.arraycopy(output, 0, input, (i*output.length)%(input.length-output.length), output.length);
    }
    for (int i = 0; i < 128; i++) {
      long startTime = System.nanoTime();
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 32; k ++) {
          md.update(input, 0, input.length);
        }
        md.digest(output, 0, output.length);
      }
      long endTime = System.nanoTime();
      times = Math.min(endTime - startTime, times);
      System.arraycopy(output, 0, input, 0, output.length);
    }
    return times;
  }

  static {
    try {
      HashMap<String,Provider> mdProviders_internal = new HashMap<String, Provider>();

      for (String algo: new String[] {
        "SHA1", "MD5", "SHA-256", "SHA-384", "SHA-512"
      }) {
        final Class<?> clazz = Util.class;
        final Provider sun = JceLoader.SUN;
        MessageDigest md = MessageDigest.getInstance(algo);
        md.digest();
        if (sun != null) {
          // SUN provider is faster (in some configurations)
          try {
            MessageDigest sun_md = MessageDigest.getInstance(algo, sun);
            sun_md.digest();
            if (md.getProvider() != sun_md.getProvider()) {
              long time_def = benchmark(md);
              long time_sun = benchmark(sun_md);
              System.out.println(algo + " (" + md.getProvider() + "): " + time_def + "ns");
              System.out.println(algo + " (" + sun_md.getProvider() + "): " + time_sun + "ns");
              Logger.minor(clazz, algo + " (" + md.getProvider() + "): " + time_def + "ns");
              Logger.minor(clazz, algo + " (" + sun_md.getProvider() + "): " + time_sun + "ns");
              if (time_sun < time_def) {
                md = sun_md;
              }
            }
          } catch(GeneralSecurityException e) {
            // ignore
            Logger.warning(clazz, algo + "@" + sun + " benchmark failed", e);
          } catch(Throwable e) {
            // ignore
            Logger.error(clazz, algo + "@" + sun + " benchmark failed", e);
          }
        }
        Provider mdProvider = md.getProvider();
        System.out.println(algo + ": using " + mdProvider);
        Logger.normal(clazz, algo + ": using " + mdProvider);
        mdProviders_internal.put(algo, mdProvider);
      }
      mdProviders = Collections.unmodifiableMap(mdProviders_internal);

      ctx = MessageDigest.getInstance("SHA1", mdProviders.get("SHA1"));
      ctx_length = ctx.getDigestLength();
    } catch(NoSuchAlgorithmException e) {
      // impossible
      throw new Error(e);
    }
  }

  public static void makeKey(
    byte[] entropy,
    byte[] key,
    int offset,
    int len) {
    try {
    synchronized (ctx) {
      ctx.digest(); // reinitialize

      int ic = 0;
      while (len > 0) {
        ic++;
        for (int i = 0; i < ic; i++)
          ctx.update((byte) 0);
        ctx.update(entropy, 0, entropy.length);
        int bc;
        if (len > ctx_length) {
          ctx.digest(key, offset, ctx_length);
          bc = ctx_length;
        } else {
          byte[] hash = ctx.digest();
          bc = Math.min(len, hash.length);
          System.arraycopy(hash, 0, key, offset, bc);
        }
        offset += bc;
        len -= bc;
      }
    }
    Arrays.fill(entropy, (byte) 0);
    } catch(DigestException e) {
      // impossible
      throw new Error(e);
    }
  }

  public static BlockCipher getCipherByName(String name) {
    //throws UnsupportedCipherException {
    try {
      return (BlockCipher) Loader.getInstance(
        "freenet.crypt.ciphers." + name);
    } catch (Exception e) {
      //throw new UnsupportedCipherException(""+e);
      e.printStackTrace();
      return null;
    }
  }

  public static BlockCipher getCipherByName(String name, int keySize) {
    //throws UnsupportedCipherException {
    try {
      return (BlockCipher) Loader.getInstance(
        "freenet.crypt.ciphers." + name,
        new Class<?>[] { Integer.class },
        new Object[] { Integer.valueOf(keySize)});
    } catch (Exception e) {
      //throw new UnsupportedCipherException(""+e);
      e.printStackTrace();
      return null;
    }
  }

  public static void main(String[] args) throws Exception {
    if ((args.length == 0) || args[0].equals("write")) {
      writeMPI(new BigInteger("9"), System.out);
      writeMPI(new BigInteger("1234567890123456789"), System.out);
      writeMPI(new BigInteger("100200300400500600700800900"), System.out);
    } else if (args[0].equals("read")) {
      System.out.println("9");
      System.out.println(readMPI(System.in));
      System.out.println("1234567890123456789");
      System.out.println(readMPI(System.in));
      System.out.println("100200300400500600700800900");
      System.out.println(readMPI(System.in));
    } else if (args[0].equals("write-mpi")) {
      writeMPI(new BigInteger(args[1]), System.out);
    } else if (args[0].equals("read-mpi")) {
      System.err.println(readMPI(System.in));
    } else if (args[0].equals("keygen")) {
      byte[] entropy = readMPI(System.in).toByteArray();
      byte[] key =
        new byte[(args.length > 1 ? Integer.parseInt(args[1]) : 16)];
      makeKey(entropy, key, 0, key.length);
      System.err.println(HexUtil.bytesToHex(key, 0, key.length));
    } else if (args[0].equals("shatest")) {
      synchronized (ctx) {
        ctx.digest();
        ctx.update((byte) 'a');
        ctx.update((byte) 'b');
        ctx.update((byte) 'c');
        System.err.println(HexUtil.bytesToHex(ctx.digest()));
      }
    }
  }

  /**
   * @return log2 of n, rounded up to the nearest integer
   */
  public static int log2(long n) {
    int log2 = 0;
    while ((log2 < 63) && (1L << log2 < n))
      ++log2;
    return log2;
  }

  public static void readFully(InputStream in, byte[] b) throws IOException {
    readFully(in, b, 0, b.length);
  }

  public static void readFully(InputStream in, byte[] b, int off, int length)
    throws IOException {
    int total = 0;
    while (total < length) {
      int got = in.read(b, off + total, length - total);
      if (got == -1) {
        throw new EOFException();
      }
      total += got;
    }
  }

}
TOP

Related Classes of freenet.crypt.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.