Package freenet.crypt

Source Code of freenet.crypt.CTRBlockCipherTest

package freenet.crypt;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import junit.framework.TestCase;

import freenet.crypt.ciphers.Rijndael;
import freenet.support.HexUtil;
import freenet.support.math.MersenneTwister;

public class CTRBlockCipherTest extends TestCase {

  /** Whether to assume JCA is available, and non-crippled. */
  public static final boolean TEST_JCA = Rijndael.AesCtrProvider != null;
 
  static {
    if(!TEST_JCA)
      System.out.println("JCA is crippled, not doing tests requiring JCA");
  }

  private MersenneTwister mt = new MersenneTwister(1634);

  // FIXME test decryptability.

  byte[] NIST_128_ENCRYPT_KEY = HexUtil
      .hexToBytes("2b7e151628aed2a6abf7158809cf4f3c");
  byte[] NIST_128_ENCRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_128_ENCRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_128_ENCRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("874d6191b620e3261bef6864990db6ce"
          + "9806f66b7970fdff8617187bb9fffdff"
          + "5ae4df3edbd5d35e5b4f09020db03eab"
          + "1e031dda2fbe03d1792170a0f3009cee");

  byte[] NIST_128_DECRYPT_KEY = HexUtil
      .hexToBytes("2b7e151628aed2a6abf7158809cf4f3c");
  byte[] NIST_128_DECRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_128_DECRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_128_DECRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("874d6191b620e3261bef6864990db6ce"
          + "9806f66b7970fdff8617187bb9fffdff"
          + "5ae4df3edbd5d35e5b4f09020db03eab"
          + "1e031dda2fbe03d1792170a0f3009cee");

  byte[] NIST_192_ENCRYPT_KEY = HexUtil
      .hexToBytes("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
  byte[] NIST_192_ENCRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_192_ENCRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_192_ENCRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("1abc932417521ca24f2b0459fe7e6e0b"
          + "090339ec0aa6faefd5ccc2c6f4ce8e94"
          + "1e36b26bd1ebc670d1bd1d665620abf7"
          + "4f78a7f6d29809585a97daec58c6b050");

  byte[] NIST_192_DECRYPT_KEY = HexUtil
      .hexToBytes("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
  byte[] NIST_192_DECRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_192_DECRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_192_DECRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("1abc932417521ca24f2b0459fe7e6e0b"
          + "090339ec0aa6faefd5ccc2c6f4ce8e94"
          + "1e36b26bd1ebc670d1bd1d665620abf7"
          + "4f78a7f6d29809585a97daec58c6b050");

  byte[] NIST_256_ENCRYPT_KEY = HexUtil
      .hexToBytes("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
  byte[] NIST_256_ENCRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_256_ENCRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_256_ENCRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("601ec313775789a5b7a7f504bbf3d228"
          + "f443e3ca4d62b59aca84e990cacaf5c5"
          + "2b0930daa23de94ce87017ba2d84988d"
          + "dfc9c58db67aada613c2dd08457941a6");

  byte[] NIST_256_DECRYPT_KEY = HexUtil
      .hexToBytes("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
  byte[] NIST_256_DECRYPT_IV = HexUtil
      .hexToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
  byte[] NIST_256_DECRYPT_PLAINTEXT = HexUtil
      .hexToBytes("6bc1bee22e409f96e93d7e117393172a"
          + "ae2d8a571e03ac9c9eb76fac45af8e51"
          + "30c81c46a35ce411e5fbc1191a0a52ef"
          + "f69f2445df4f9b17ad2b417be66c3710");
  byte[] NIST_256_DECRYPT_CIPHERTEXT = HexUtil
      .hexToBytes("601ec313775789a5b7a7f504bbf3d228"
          + "f443e3ca4d62b59aca84e990cacaf5c5"
          + "2b0930daa23de94ce87017ba2d84988d"
          + "dfc9c58db67aada613c2dd08457941a6");

  public void testNIST() throws UnsupportedCipherException,
      NoSuchAlgorithmException, NoSuchPaddingException,
      InvalidKeyException, InvalidAlgorithmParameterException,
      IllegalBlockSizeException, BadPaddingException {
    // CTR mode test vectors.
    // AES128
    checkNIST(128, NIST_128_ENCRYPT_KEY, NIST_128_ENCRYPT_IV,
        NIST_128_ENCRYPT_PLAINTEXT, NIST_128_ENCRYPT_CIPHERTEXT);
    checkNIST(128, NIST_128_DECRYPT_KEY, NIST_128_DECRYPT_IV,
        NIST_128_DECRYPT_PLAINTEXT, NIST_128_DECRYPT_CIPHERTEXT);
    // AES192
    checkNIST(192, NIST_192_ENCRYPT_KEY, NIST_192_ENCRYPT_IV,
        NIST_192_ENCRYPT_PLAINTEXT, NIST_192_ENCRYPT_CIPHERTEXT);
    checkNIST(192, NIST_192_DECRYPT_KEY, NIST_192_DECRYPT_IV,
        NIST_192_DECRYPT_PLAINTEXT, NIST_192_DECRYPT_CIPHERTEXT);
    // AES256
    checkNIST(256, NIST_256_ENCRYPT_KEY, NIST_256_ENCRYPT_IV,
        NIST_256_ENCRYPT_PLAINTEXT, NIST_256_ENCRYPT_CIPHERTEXT);
    checkNIST(256, NIST_256_DECRYPT_KEY, NIST_256_DECRYPT_IV,
        NIST_256_DECRYPT_PLAINTEXT, NIST_256_DECRYPT_CIPHERTEXT);
  }

  public void testNISTRandomLength() throws UnsupportedCipherException,
      NoSuchAlgorithmException, NoSuchPaddingException,
      InvalidKeyException, InvalidAlgorithmParameterException,
      IllegalBlockSizeException, BadPaddingException,
      ShortBufferException {
    // CTR mode test vectors.
    // AES128
    checkNISTRandomLength(128, NIST_128_ENCRYPT_KEY, NIST_128_ENCRYPT_IV,
        NIST_128_ENCRYPT_PLAINTEXT, NIST_128_ENCRYPT_CIPHERTEXT);
    checkNISTRandomLength(128, NIST_128_DECRYPT_KEY, NIST_128_DECRYPT_IV,
        NIST_128_DECRYPT_PLAINTEXT, NIST_128_DECRYPT_CIPHERTEXT);
    // AES192
    checkNISTRandomLength(192, NIST_192_ENCRYPT_KEY, NIST_192_ENCRYPT_IV,
        NIST_192_ENCRYPT_PLAINTEXT, NIST_192_ENCRYPT_CIPHERTEXT);
    checkNISTRandomLength(192, NIST_192_DECRYPT_KEY, NIST_192_DECRYPT_IV,
        NIST_192_DECRYPT_PLAINTEXT, NIST_192_DECRYPT_CIPHERTEXT);
    // AES256
    checkNISTRandomLength(256, NIST_256_ENCRYPT_KEY, NIST_256_ENCRYPT_IV,
        NIST_256_ENCRYPT_PLAINTEXT, NIST_256_ENCRYPT_CIPHERTEXT);
    checkNISTRandomLength(256, NIST_256_DECRYPT_KEY, NIST_256_DECRYPT_IV,
        NIST_256_DECRYPT_PLAINTEXT, NIST_256_DECRYPT_CIPHERTEXT);
  }

  private void checkNIST(int bits, byte[] key, byte[] iv, byte[] plaintext,
      byte[] ciphertext) throws UnsupportedCipherException,
      NoSuchAlgorithmException, NoSuchPaddingException,
      InvalidKeyException, InvalidAlgorithmParameterException,
      IllegalBlockSizeException, BadPaddingException {
    // First test it with JCA.
    if (TEST_JCA) {
      SecretKeySpec k = new SecretKeySpec(key, "AES");
      Cipher c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
      c.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(iv));
      byte[] output = c.doFinal(plaintext);
      assertTrue(Arrays.equals(output, ciphertext));
    }

    Rijndael cipher = new Rijndael(bits, 128);
    cipher.initialize(key);
    CTRBlockCipher ctr = new CTRBlockCipher(cipher);
    ctr.init(iv);
    byte[] output = new byte[plaintext.length];
    ctr.processBytes(plaintext, 0, plaintext.length, output, 0);
    assertTrue(Arrays.equals(output, ciphertext));
  }

  private void checkNISTRandomLength(int bits, byte[] key, byte[] iv,
      byte[] plaintext, byte[] ciphertext)
      throws UnsupportedCipherException, NoSuchAlgorithmException,
      NoSuchPaddingException, InvalidKeyException,
      InvalidAlgorithmParameterException, IllegalBlockSizeException,
      BadPaddingException, ShortBufferException {
    for (int i = 0; i < 1024; i++) {
      // First test it with JCA.
      long seed = mt.nextLong();
      if (TEST_JCA) {
        SecretKeySpec k = new SecretKeySpec(key, "AES");
        Cipher c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
        c.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(iv));
        MersenneTwister random = new MersenneTwister(seed);
        byte[] output = new byte[plaintext.length];
        int inputPtr = 0;
        int outputPtr = 0;
        // Odd API designed for block ciphers etc.
        // For CTR it should be able to return immediately each time.
        // ... Actually, no. BouncyCastle's CTR breaks this assumption.
        // You must handle when update() produce less than was in input.
        while (inputPtr < plaintext.length) {
          int max = plaintext.length - inputPtr;
          int count = (max == 1) ? 1 : (random.nextInt(max - 1) + 1);
          int moved = c.update(plaintext, inputPtr, count, output,
              outputPtr);
          outputPtr += moved;
          inputPtr += count;
        }
        c.doFinal(plaintext, 0, plaintext.length - inputPtr, output,
            outputPtr);
        assertTrue(Arrays.equals(output, ciphertext));
      }

      Rijndael cipher = new Rijndael(bits, 128);
      cipher.initialize(key);
      CTRBlockCipher ctr = new CTRBlockCipher(cipher);
      ctr.init(iv);
      byte[] output = new byte[plaintext.length];
      MersenneTwister random = new MersenneTwister(seed);
      int ptr = 0;
      while (ptr < plaintext.length) {
        int max = plaintext.length - ptr;
        int count = (max == 1) ? 1 : (random.nextInt(max - 1) + 1);
        ctr.processBytes(plaintext, ptr, count, output, ptr);
        ptr += count;
      }
      assertTrue(Arrays.equals(output, ciphertext));
    }
  }
 
  public void testRandomJCA() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
    if(!TEST_JCA) return;
    for(int i=0;i<1024;i++) {
      byte[] plaintext = new byte[mt.nextInt(4096)+1];
      byte[] key = new byte[32];
      byte[] iv = new byte[16];
      mt.nextBytes(plaintext);
      mt.nextBytes(key);
      mt.nextBytes(iv);
      SecretKeySpec k = new SecretKeySpec(key, "AES");
      Cipher c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
      c.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(iv));
      byte[] output = c.doFinal(plaintext);
      c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
      c.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(iv));
      byte[] decrypted = c.doFinal(output);
      assertTrue(Arrays.equals(decrypted, plaintext));
    }
  }
 
  public void testRandom() throws UnsupportedCipherException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
    for(int i=0;i<1024;i++) {
      byte[] plaintext = new byte[mt.nextInt(4096)+1];
      byte[] key = new byte[32];
      byte[] iv = new byte[16];
      mt.nextBytes(plaintext);
      mt.nextBytes(key);
      mt.nextBytes(iv);
      // First encrypt as a block.
      Rijndael cipher = new Rijndael(256, 128);
      cipher.initialize(key);
      CTRBlockCipher ctr = new CTRBlockCipher(cipher);
      ctr.init(iv);
      byte[] ciphertext = new byte[plaintext.length];
      ctr.processBytes(plaintext, 0, plaintext.length, ciphertext, 0);
      // Now decrypt.
      ctr = new CTRBlockCipher(cipher);
      ctr.init(iv);
      byte[] finalPlaintext = new byte[plaintext.length];
      ctr.processBytes(ciphertext, 0, ciphertext.length, finalPlaintext, 0);
      assertTrue(Arrays.equals(finalPlaintext, plaintext));
      if(TEST_JCA) {
        SecretKeySpec k = new SecretKeySpec(key, "AES");
        Cipher c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
        c.init(Cipher.ENCRYPT_MODE, k, new IvParameterSpec(iv));
        byte[] output = c.doFinal(plaintext);
        assertTrue(Arrays.equals(output, ciphertext));
        c = Cipher.getInstance("AES/CTR/NOPADDING", Rijndael.AesCtrProvider);
        c.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(iv));
        byte[] decrypted = c.doFinal(output);
        assertTrue(Arrays.equals(decrypted, plaintext));
      }
      // Now encrypt again, in random pieces.
      cipher.initialize(key);
      ctr = new CTRBlockCipher(cipher);
      ctr.init(iv);
      byte[] output = new byte[plaintext.length];
      MersenneTwister random = new MersenneTwister(mt.nextLong());
      int ptr = 0;
      while (ptr < plaintext.length) {
        int max = plaintext.length - ptr;
        int count = (max == 1) ? 1 : (random.nextInt(max - 1) + 1);
        ctr.processBytes(plaintext, ptr, count, output, ptr);
        ptr += count;
      }
      assertTrue(Arrays.equals(output, ciphertext));
     
    }
  }

}
TOP

Related Classes of freenet.crypt.CTRBlockCipherTest

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.