Package nl.warper.skein

Source Code of nl.warper.skein.SkeinMain

/*
* Copyright (c) 2008 - $Date: 2008/05/29 13:50:21 $, Sdu Identification BV
* Classificatie: Commercieel vertrouwelijk
*
* File:     $rcsfile$
* Date:     $Date: 2008/05/29 13:50:21 $
* Version:  $Revision: 1.1 $
*/
package nl.warper.skein;

import static nl.warper.skein.Util.*;

import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import nl.warper.threefish.ThreefishImpl;
import nl.warper.threefish.ThreefishSecretKey;

/**
* SkeinMain is used to test the SimpleSkein, UBI64 and Threefish implementations and to see that the test vectors, including initial chaining
* vectors are correct. The output of the main() method has been used to successfully confirm the old and new chaining values as created
* by the Skein team.
* <P>
* The initial implementation incorrectly used the blocksize as size of the configuration encoding instead of the
* real size of the configuration encoding. You can simulate this incorrect behaviour by simply setting the private USE_BLOCK_SIZE constant
* to true.
* <P>
* The Threefish part of the protocol is of course the most difficult part of the algorithm to implement. To test the intermediate values
* of your own implementation, just change the logger settings below. For full logging to the console, just set the logging level
* to Level.FINEST instead of Level.OFF.
* @author maartenb
* @author $Author: $
* @since 5 nov 2008
* @version $Revision: $
*/
public class SkeinMain {
  private static final boolean USE_BLOCK_SIZE = false;
  private static final boolean INITIAL_CHAINING_VALUES_IN_JAVA = false;

  static {
    Logger threefishLogger = Logger.getLogger(ThreefishImpl.class.getName());
  }

  public static void testThreefish(final int blockSize, final int rounds) {
    final ThreefishImpl impl;
    if(rounds <= 0) {
      impl = new ThreefishImpl(blockSize);
    } else {
      impl = new ThreefishImpl(blockSize, rounds);
    }

    byte[] keyData = new byte[blockSize / Byte.SIZE]; // initialized to 00h values, used later on
    final long[] tweak;
    try {
      SecureRandom rnd = SecureRandom.getInstance("SHA1PRNG");
      rnd.nextBytes(keyData);
      tweak = new long[] { rnd.nextLong(), rnd.nextLong() };
    } catch (GeneralSecurityException e) {
      throw new RuntimeException(e);
    }

    ThreefishSecretKey sk = new ThreefishSecretKey(keyData);

    impl.init(sk, tweak);
    final byte[] plain = "Maarten".getBytes();
    final byte[] plainPadded = zeroPad(plain, impl.getBlockSize());

    final long[] encryptedBlock = new long[impl.getBlockSize() / Long.SIZE];

    final long[] plainBlock = lsbBytesToArrayOfLong(plainPadded);
    System.out.printf("Threefish plainbl: %s%n", tohex(lsbArrayOfLongToBytes(plainBlock)));

    // not needed: impl.init(sk, tweak);
    impl.blockEncrypt(plainBlock, encryptedBlock);

    System.out.printf("Threefish encrypt: %s%n", tohex(lsbArrayOfLongToBytes(encryptedBlock)));


    long[] decryptedBlock= new long[encryptedBlock.length];
    impl.blockDecrypt(encryptedBlock, decryptedBlock);

    System.out.printf("Threefish decrypt: %s%n", tohex(lsbArrayOfLongToBytes(decryptedBlock)));
  }

  public static byte[] doSimpleSkein(final int blockSize, final byte[] message, final int outputSize) {
    final int blockSizeBytes = blockSize / Byte.SIZE;

    if(message == null) {
      throw new IllegalArgumentException("Please provide a message, even one of 0 bytes to process");
    }

    if(outputSize <= 0 || outputSize % Byte.SIZE != 0) {
      throw new IllegalArgumentException("The output size N must fullfil N MOD 8 = 0 (a complete number of bytes)");
    }

    // create buffer
    byte[] blockBuffer = new byte[blockSizeBytes];

    // create cipher
    ThreefishImpl threefish = new ThreefishImpl(blockSize);

    // create and init UBI
    UBI64 ubi = new UBI64(threefish);
    ubi.init();

    // create configuration
    Skein.Configuration config = new Skein.Configuration(outputSize, 0, 0, 0);
    byte[] configEncoding = config.getEncoded();

    // padded automatically, block is still filled with 00h values
    System.arraycopy(configEncoding, 0, blockBuffer, 0, configEncoding.length);
    long[] blockWords = lsbBytesToArrayOfLong(blockBuffer);

    // create tweak for configuration
    // used configEncoding.length, but it seems the entire block should be in the tweak value (???) -> see question on site
    int configSize = configEncoding.length;

    Skein.Tweak tweak = new Skein.Tweak(true, true, Skein.Tweak.T_CFG, false, 0, configSize);

    final long configTweak[] = { tweak.getT0(), tweak.getT1() };

    // update UBI with configuration
    //System.out.println("simple update: "+blockWords+" "+configTweak[0]+" "+configTweak[1]);
    ubi.update(blockWords, configTweak);

    // process message in blocks
    int bytesProcessed = 0;

    int messageLength = message.length;
    while (bytesProcessed < messageLength) {
      final int available = messageLength - bytesProcessed;
      final int toblock = Math.min(blockSizeBytes, available);
      System.arraycopy(message, bytesProcessed, blockBuffer, 0, toblock);

      // pad block itself (not the bits)
      if(toblock != blockSizeBytes) {
        for (int i = toblock; i < blockSizeBytes; i++) {
          blockBuffer[i] = 0;
        }
      }

      blockWords = lsbBytesToArrayOfLong(blockBuffer);

      // already update bytesProcessed (needed for tweak)
      bytesProcessed += toblock;

      //System.out.println("simple tweak: "+bytesProcessed+" "+messageLength);
      tweak = new Skein.Tweak(bytesProcessed == messageLength, bytesProcessed <= blockSizeBytes, Skein.Tweak.T_MSG, false, 0, bytesProcessed);

      // finally do the actual update
      //System.out.println("simple update: "+blockWords+" "+tweak.getT0()+" "+tweak.getT1());
      ubi.update(blockWords, new long[] { tweak.getT0(), tweak.getT1() } );
    }

    final int outputBlocks = (outputSize - 1) / blockSize + 1;

    // create a new set of longs of the same size (terrible hack, but whatever)
    long[] inputForOutput = new long[blockWords.length];
    for (int i = 0; i < outputBlocks; i++) {
      // create input for the OUTPUT function
      inputForOutput[0] = i;

      tweak = new Skein.Tweak(i == outputBlocks - 1, i == 0, Skein.Tweak.T_OUT, false, 0, 8);

      ubi.update(inputForOutput, new long[] { tweak.getT0(), tweak.getT1() } );
    }

    final long[] outputWords = ubi.getOutput();

    final byte[] output = lsbArrayOfLongToBytes(outputWords);

    return output;
  }

  private static void update(UBI64 ubi, byte[] blockBuffer, boolean last, boolean first, int type, byte[] data, int offset, int count)
  {
    final int available = data.length - offset;
    final int toblock = Math.min(blockBuffer.length, available);
    System.arraycopy(data, offset, blockBuffer, 0, toblock);

    // pad block itself (not the bits)
    if(toblock != blockBuffer.length)
    {
      for (int i = toblock; i < blockBuffer.length; i++)
      {
        blockBuffer[i] = 0;
      }
    }

    long[] blockWords = lsbBytesToArrayOfLong(blockBuffer);

    Skein.Tweak tweak = new Skein.Tweak(last, first, type, false, 0, count);

    // update UBI with configuration
    //System.out.println("full update: "+blockWords+" "+tweak.getT0()+" "+tweak.getT1());
    ubi.update(blockWords, new long[] { tweak.getT0(), tweak.getT1() });
  }

  public static byte[] fullSkein(final int blockSize, final byte[] key, final byte[] pers, final byte[] pk, final byte[] kdf, final byte[] nonce, final byte[] message, final int outputSize) {
    final int blockSizeBytes = blockSize / Byte.SIZE;

    if(outputSize <= 0 || outputSize % Byte.SIZE != 0) {
      throw new IllegalArgumentException("The output size N must fullfil N MOD 8 = 0 (a complete number of bytes)");
    }

    // create buffer
    byte[] blockBuffer = new byte[blockSizeBytes];

    // create cipher
    ThreefishImpl threefish = new ThreefishImpl(blockSize);

    // create and init UBI
    UBI64 ubi = new UBI64(threefish);
    ubi.init();

    if(key!=null)
    {
      update(ubi, blockBuffer, true, true, Skein.Tweak.T_KEY, key, 0, key.length);
    }

    if(pers!=null)
    {
      update(ubi, blockBuffer, true, true, Skein.Tweak.T_PRS, pers, 0, pers.length);
    }

    if(pk!=null)
    {
      update(ubi, blockBuffer, true, true, Skein.Tweak.T_PK, pk, 0, pk.length);
    }

    if(kdf!=null)
    {
      update(ubi, blockBuffer, true, true, Skein.Tweak.T_KDF, kdf, 0, kdf.length);
    }

    if(nonce!=null)
    {
      update(ubi, blockBuffer, true, true, Skein.Tweak.T_NON, nonce, 0, nonce.length);
    }

    // create configuration
    Skein.Configuration config = new Skein.Configuration(outputSize, 0, 0, 0);
    byte[] configEncoding = config.getEncoded();

    // create tweak for configuration
    update(ubi, blockBuffer, true, true, Skein.Tweak.T_CFG, configEncoding, 0, configEncoding.length);

    if(message!=null)
    {
      // process message in blocks
      int bytesProcessed = 0;
      while (bytesProcessed < message.length)
      {
        int available = message.length - bytesProcessed;
        int toblock = Math.min(blockBuffer.length, available);
        //System.out.println("full tweak: "+(bytesProcessed+toblock)+" "+message.length);
        update(ubi, blockBuffer, bytesProcessed+toblock == message.length, bytesProcessed+toblock <= blockSizeBytes, Skein.Tweak.T_MSG, message, bytesProcessed, bytesProcessed+toblock);
        bytesProcessed += toblock;
      }
    }

    final int outputBlocks = (outputSize - 1) / blockSize + 1;

    // create a new set of longs of the same size (terrible hack, but whatever)
    long[] blockWords = lsbBytesToArrayOfLong(blockBuffer);
    long[] inputForOutput = new long[blockWords.length];
    for (int i = 0; i < outputBlocks; i++)
    {
      // create input for the OUTPUT function
      inputForOutput[0] = i;

      Skein.Tweak tweak = new Skein.Tweak(i == outputBlocks - 1, i == 0, Skein.Tweak.T_OUT, false, 0, 8);

      ubi.update(inputForOutput, new long[] { tweak.getT0(), tweak.getT1() } );
    }

    final long[] outputWords = ubi.getOutput();

    final byte[] output = lsbArrayOfLongToBytes(outputWords);

    return output;
  }

  public static void showConfigurationInit(final int blockSize, final int outputSize) {

    final int blockSizeBytes = blockSize / Byte.SIZE;

    if(outputSize <= 0 || outputSize % Byte.SIZE != 0) {
      throw new IllegalArgumentException("The output size N must fullfil N MOD 8 = 0 (a complete number of bytes)");
    }

    // create buffer
    byte[] blockBuffer = new byte[blockSizeBytes];

    // create cipher
    ThreefishImpl threefish = new ThreefishImpl(blockSize);

    // create and init UBI
    UBI64 ubi = new UBI64(threefish);
    ubi.init();

    // create configuration
    Skein.Configuration config = new Skein.Configuration(outputSize, 0, 0, 0);
    byte[] configEncoding = config.getEncoded();
    // padded automatically, block is still filled with 00h values
    System.arraycopy(configEncoding, 0, blockBuffer, 0, configEncoding.length);
    long[] blockWords = lsbBytesToArrayOfLong(blockBuffer);

    int configSize = configEncoding.length;
    if(USE_BLOCK_SIZE) { // wrong, but whatever
      configSize = blockSizeBytes;
    }


    // create tweak for configuration
    // used configEncoding.length, but it seems the entire block should be in the tweak value (???) -> see question on site
    Skein.Tweak tweak = new Skein.Tweak(true, true, Skein.Tweak.T_CFG, false, 0, configSize);

    final long configTweak[] = { tweak.getT0(), tweak.getT1() };

    // update UBI with configuration
    ubi.update(blockWords, configTweak);
    long[] initialChainingValue = ubi.getOutput();

    if (INITIAL_CHAINING_VALUES_IN_JAVA) {
      System.out.printf("\tpublic static final long[] INITIAL_CHAINING_VALUE_SKEIN_%d_%d = {%n", blockSize, outputSize);

      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < initialChainingValue.length; i++) {
        sb.append(String.format("0x%016XL", initialChainingValue[i]));
        if (i != initialChainingValue.length - 1) {
          sb.append(", ");
          if (i % 4 == 3) {
            sb.append(String.format("%n"));
          }
        }
      }
      sb.append(String.format("%n"));
      System.out.println(sb.toString());
    } else {
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < initialChainingValue.length; i++) {
        sb.append(String.format("0x%016X", initialChainingValue[i]));
        if (i != initialChainingValue.length - 1) {
          sb.append(", ");
          if (i % 4 == 3) {
            sb.append(String.format("%n"));
          }
        }
      }
      System.out.println(sb.toString());

    }
  }

  private static byte[] createTestArray(int bytes) {
    byte[] testArray = new byte[bytes];
    for(int i = 0; i < bytes; i++) {
      testArray[i] = (byte) (- i - 1);
    }
    return testArray;
  }

  /**
   * @param args JAVADOC .
   */
  public static void main(final String ... args) {
    System.out.println();
    System.out.println(" === Threefish encrypt and decyrpt === ");
    testThreefish(256, 72);
    testThreefish(512, 80);
    testThreefish(1024, 80);

    System.out.println();
    System.out.println(" === initial chaining values === ");
    System.out.printf("B.1 Skein-256-128%n%n");
    showConfigurationInit(256, 128);
    System.out.println();

    System.out.printf("B.2 Skein-256-128%n%n");
    showConfigurationInit(256, 160);
    System.out.println();

    System.out.printf("B.3 Skein-256-224%n%n");
    showConfigurationInit(256, 224);
    System.out.println();

    System.out.printf("B.4 Skein-256-256%n%n");
    showConfigurationInit(256, 256);
    System.out.println();

    System.out.printf("B.5 Skein-512-128%n%n");
    showConfigurationInit(512, 128);
    System.out.println();

    System.out.printf("B.6 Skein-512-160%n%n");
    showConfigurationInit(512, 160);
    System.out.println();

    System.out.printf("B.7 Skein-512-224%n%n");
    showConfigurationInit(512, 224);
    System.out.println();

    System.out.printf("B.8 Skein-512-256%n%n");
    showConfigurationInit(512, 256);
    System.out.println();

    System.out.printf("B.9 Skein-512-384%n%n");
    showConfigurationInit(512, 384);
    System.out.println();

    System.out.printf("B.10 Skein-512-512%n%n");
    showConfigurationInit(512, 512);
    System.out.println();

    System.out.printf("B.11 Skein-1024-384%n%n");
    showConfigurationInit(1024, 384);
    System.out.println();

    System.out.printf("B.12 Skein-1024-512%n%n");
    showConfigurationInit(1024, 512);
    System.out.println();

    System.out.printf("B.13 Skein-1024-1024%n%n");
    showConfigurationInit(1024, 1024);
    System.out.println();

    // initialization
    byte[] data;
    int blockSize;
    int outputSize;
    int length;
    byte[] output;

    System.out.println();
    System.out.println(" === test values === ");

    // C.1
    blockSize = 256;
    outputSize = 256;

    length = 1;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.1 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 32;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.1 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 64;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.1 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    // C.2
    blockSize = 512;
    outputSize = 512;

    length = 1;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 64;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 128;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    // C.3
    blockSize = 1024;
    outputSize = 1024;

    length = 1;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 128;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));

    length = 256;
    data = createTestArray(length);
    output = doSimpleSkein(blockSize, data, outputSize);
    System.out.printf("C.2 Skein-%d-%d T(%d) %n%nMessage data:%n%s%nResult:%n%s%n", blockSize, outputSize, length, toFormattedHex(data, 1), toFormattedHex(output, 1));
  }
}
TOP

Related Classes of nl.warper.skein.SkeinMain

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.