Package freenet.crypt.ciphers

Source Code of freenet.crypt.ciphers.Rijndael

package freenet.crypt.ciphers;

import java.security.InvalidKeyException;
import java.security.GeneralSecurityException;
import java.security.Provider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import freenet.crypt.BlockCipher;
import freenet.crypt.JceLoader;
import freenet.crypt.UnsupportedCipherException;
import freenet.support.Logger;

/*
  This code is part of the Java Adaptive Network Client by Ian Clarke.
  It is distributed under the GNU Public Licence (GPL) version 2.  See
  http://www.gnu.org/ for further details of the GPL.
*/

/**
* Interfaces with the Rijndael AES candidate to implement the Rijndael
* algorithm
*/
public class Rijndael implements BlockCipher {
  private Object sessionKey;
  private final int keysize, blocksize;

  public static final Provider AesCtrProvider = getAesCtrProvider();
 
  public static String getProviderName() {
    return AesCtrProvider != null ? AesCtrProvider.getName() : null;
  }
 
  static private long benchmark(Cipher cipher, SecretKeySpec key, IvParameterSpec IV) throws GeneralSecurityException
  {
    long times = Long.MAX_VALUE;
    byte[] input = new byte[1024];
    byte[] output = new byte[input.length*32];
    cipher.init(Cipher.ENCRYPT_MODE, key, IV);
    // warm-up
    for (int i = 0; i < 32; i++) {
      cipher.doFinal(input, 0, input.length, output, 0);
      System.arraycopy(output, 0, input, 0, input.length);
    }
    for (int i = 0; i < 128; i++) {
      long startTime = System.nanoTime();
      cipher.init(Cipher.ENCRYPT_MODE, key, IV);
      for (int j = 0; j < 4; j++) {
        int ofs = 0;
        for (int k = 0; k < 32; k ++) {
          ofs += cipher.update(input, 0, input.length, output, ofs);
        }
        cipher.doFinal(output, ofs);
      }
      long endTime = System.nanoTime();
      times = Math.min(endTime - startTime, times);
      System.arraycopy(output, 0, input, 0, input.length);
    }
    return times;
  }

  /** @return null if JCA is crippled (restricted to 128-bit) so we need
   * to use this class. */
  private static Provider getAesCtrProvider() {
    try {
      final String algo = "AES/CTR/NOPADDING";
      final Provider bcastle = JceLoader.BouncyCastle;
      final Class<?> clazz = Rijndael.class;

      byte[] key = new byte[32]; // Test for whether 256-bit works.
      byte[] iv = new byte[16];
      byte[] plaintext = new byte[16];
      SecretKeySpec k = new SecretKeySpec(key, "AES");
      IvParameterSpec IV = new IvParameterSpec(iv);

      Cipher c = Cipher.getInstance(algo);
      c.init(Cipher.ENCRYPT_MODE, k, IV);
      // ^^^ resolve provider
      Provider provider = c.getProvider();
      if (bcastle != null) {
        // BouncyCastle provider is faster (in some configurations)
        try {
          Cipher bcastle_cipher = Cipher.getInstance(algo, bcastle);
          bcastle_cipher.init(Cipher.ENCRYPT_MODE, k, IV);
          Provider bcastle_provider = bcastle_cipher.getProvider();
          if (provider != bcastle_provider) {
            long time_def = benchmark(c, k, IV);
            long time_bcastle = benchmark(bcastle_cipher, k, IV);
            System.out.println(algo + " (" + provider + "): " + time_def + "ns");
            System.out.println(algo + " (" + bcastle_provider + "): " + time_bcastle + "ns");
            Logger.minor(clazz, algo + "/" + provider + ": " + time_def + "ns");
            Logger.minor(clazz, algo + "/" + bcastle_provider + ": " + time_bcastle + "ns");
            if (time_bcastle < time_def) {
              provider = bcastle_provider;
              c = bcastle_cipher;
            }
          }
        } catch(GeneralSecurityException e) {
          // ignore
          Logger.warning(clazz, algo + "@" + bcastle + " benchmark failed", e);

        } catch(Throwable e) {
          // ignore
          Logger.error(clazz, algo + "@" + bcastle + " benchmark failed", e);
        }
      }
      c = Cipher.getInstance(algo, provider);
      c.init(Cipher.ENCRYPT_MODE, k, IV);
      c.doFinal(plaintext);
      Logger.normal(Rijndael.class, "Using JCA: provider "+provider);
      System.out.println("Using JCA cipher provider: "+provider);
      return provider;
    } catch (GeneralSecurityException e) {
      Logger.warning(Rijndael.class, "Not using JCA as it is crippled (can't use 256-bit keys). Will use built-in encryption. ", e);
      return null;
    }
  }
 
  /**
   * Create a Rijndael instance.
   * @param keysize The key size.
   * @param blocksize The block size.
   * @throws UnsupportedCipherException
   */
  public Rijndael(int keysize, int blocksize) throws UnsupportedCipherException {
    if (! ((keysize == 128) ||
        (keysize == 192) ||
        (keysize == 256)))
      throw new UnsupportedCipherException("Invalid keysize");
    if (! ((blocksize == 128) ||
        (blocksize == 256)))
      throw new UnsupportedCipherException("Invalid blocksize");
    this.keysize=keysize;
    this.blocksize=blocksize;
  }

  // for Util.getCipherByName..  and yes, screw you too, java
  public Rijndael() {
    this.keysize   = 128;
    this.blocksize = 128;
  }

  @Override
  public final int getBlockSize() {
    return blocksize;
  }

  @Override
  public final int getKeySize() {
    return keysize;
  }

  @Override
  public final void initialize(byte[] key) {
    try {
      byte[] nkey=new byte[keysize>>3];
      System.arraycopy(key, 0, nkey, 0, nkey.length);
      sessionKey=Rijndael_Algorithm.makeKey(nkey, blocksize/8);
    } catch (InvalidKeyException e) {
      e.printStackTrace();
      Logger.error(this,"Invalid key");
    }
  }

  @Override
  public synchronized final void encipher(byte[] block, byte[] result) {
    if(block.length != blocksize/8)
      throw new IllegalArgumentException();
    Rijndael_Algorithm.blockEncrypt(block, result, 0, sessionKey, blocksize/8);
  }

  @Override
  public synchronized final void decipher(byte[] block, byte[] result) {
    if(block.length != blocksize/8)
      throw new IllegalArgumentException();
    Rijndael_Algorithm.blockDecrypt(block, result, 0, sessionKey, blocksize/8);
  }
}
TOP

Related Classes of freenet.crypt.ciphers.Rijndael

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.