/*
 * Created on Apr 17, 2005
 * 
 * This source code is provided "as is" with no support.
 * Softabar.com disclaims all warranties, expressed or implied, including, but
 * not limited to, the warranties of merchantability and fitness for any
 * purpose. In no event shall Softabar.com be liable for any direct, indirect,
 * incidental, special, exemplary, or consequential damages (including, but not
 * limited to, procurement of substitute goods or services; loss of use, data,
 * or profits; or business interruption), however caused and on any theory of
 * liability, whether in contract, strict liability or tort (including
 * negligence or otherwise) arising in any way out of the use of this source
 * code or any code derived or based on this source code, even if advised of the
 * possibility of such damage. Copyright (c) 2005 Softabar.com
 */
package com.softabar.crypt;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;


/**
 * Helper methods for {@link SoftaCrypt}. See usage in {@link #main}.
 * 
 * @version 1.0 Copyright (C) 2005 softabar.com
 */
public class SoftaCryptHelper
{

  /**
   * @param algorithm
   *          Digest algorithm (sha1, sha224, sha256, sha384 or sha512)
   * @param text
   *          Text to calculate digest
   * @return String presentation of digest value
   */
  public static String digest(String algorithm, String text)
  {
    return digest(algorithm, new ByteArrayInputStream(text.getBytes()));
  }

  /**
   * @param algorithm
   *          Digest algorithm (sha1, sha224, sha256, sha384 or sha512)
   * @param file
   *          File to calculate digest
   * @return String presentation of digest value
   */
  public static String digest(String algorithm, File file)
  {
    try
    {
      return digest(algorithm, new FileInputStream(file));
    }
    catch (FileNotFoundException e)
    {
      e.printStackTrace();
      return null;
    }

  }

  private static String digest(String algorithm, InputStream inputStream)
  {
    try
    {

      SoftaCrypt sc = new SoftaCrypt();
      Class cl = sc.getClass();
      Class[] params =
      { InputStream.class };
      Method method = cl.getDeclaredMethod(algorithm, params);
      Object[] args =
      { inputStream };
      byte[] bDigest = (byte[]) method.invoke(sc, args);
      return sc.toHexString(bDigest);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }

  }

  /**
   * @param text
   *          Text to calculate CRC32
   * @return CRC32 as hexadecimal string
   */
  public static String crc32(String text)
  {
    return crc32(new ByteArrayInputStream(text.getBytes()));
  }

  /**
   * @param file
   *          File to calculate CRC32
   * @return CRC32 as hexadecimal string
   */
  public static String crc32(File file)
  {
    try
    {
      return crc32(new FileInputStream(file));
    }
    catch (FileNotFoundException e)
    {
      e.printStackTrace();
      return null;
    }

  }

  private static String crc32(InputStream inputStream)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      int crc32Value=sc.crc32(inputStream);
      return Integer.toHexString(crc32Value);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }

  }

  /**
   * @param inFile
   *          File to encode
   * @param outFile
   *          Encoded file
   */
  public static void base64Encode(File inFile, File outFile)
  {
    try
    {

      SoftaCrypt sc = new SoftaCrypt();
      sc.base64Encode(new FileInputStream(inFile),
          new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param inFile
   *          File to decode
   * @param outFile
   *          Decoded file
   */
  public static void base64Decode(File inFile, File outFile)
  {
    try
    {

      SoftaCrypt sc = new SoftaCrypt();
      sc.base64Decode(new FileInputStream(inFile),
          new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Any string as passphrase
   * @return 16-byte key. Key is generated by calculating SHA-1 of passphrase
   *         and returning 16 left most bytes. If exception happened, returns
   *         key full of zeros
   */
  public static byte[] makeKey(String passPhrase)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      byte[] key = sc.sha1(new ByteArrayInputStream(passPhrase.getBytes()));

      return sc.to16Bytes(key);

    }
    catch (Exception e)
    {
      byte[] zeroKey =
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
      return zeroKey;
    }
  }

  /**
   * @param passPhrase
   *          Passphrase for AES encryption
   * @param inFile
   *          File to encrypt
   * @param outFile
   *          Encrypted file
   */
  public static void aesEncrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {

      SoftaCrypt sc = new SoftaCrypt();
      sc.setKey(makeKey(passPhrase));
      sc.encrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Passphrase for AES decryption
   * @param inFile
   *          File to decrypt
   * @param outFile
   *          Decrypted file
   */
  public static void aesDecrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {

      SoftaCrypt sc = new SoftaCrypt();
      sc.setKey(makeKey(passPhrase));
      sc.decrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Passphrase for TwoFish decryption
   * @param inFile
   *          File to encrypt
   * @param outFile
   *          Encrypted file
   */
  public static void twofishEncrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      sc.setAlgorithm(SoftaCrypt.TWOFISH);
      sc.setKey(makeKey(passPhrase));
      sc.encrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Passphrase for TwoFish decryption
   * @param inFile
   *          File to decrypt
   * @param outFile
   *          Decrypted file
   */
  public static void twofishDecrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      sc.setKey(makeKey(passPhrase));
      sc.setAlgorithm(SoftaCrypt.TWOFISH);
      sc.decrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Passphrase for XTEA decryption
   * @param inFile
   *          File to encrypt
   * @param outFile
   *          Encrypted file
   */
  public static void xteaEncrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      sc.setAlgorithm(SoftaCrypt.XTEA);
      sc.setKey(makeKey(passPhrase));
      sc.encrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * @param passPhrase
   *          Passphrase for XTEA decryption
   * @param inFile
   *          File to decrypt
   * @param outFile
   *          Decrypted file
   */
  public static void xteaDecrypt(String passPhrase, File inFile, File outFile)
  {
    try
    {
      SoftaCrypt sc = new SoftaCrypt();
      sc.setKey(makeKey(passPhrase));
      sc.setAlgorithm(SoftaCrypt.XTEA);
      sc.decrypt(new FileInputStream(inFile), new FileOutputStream(outFile));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }

  }

  /**
   * <pre>
   *       Usage:
   *         java com.softabar.crypt.SoftaCryptHelper &lt;command&gt; &lt;argument1&gt; &lt;argument2&gt; ...
   *       
   *       Possible commands:
   *         sha1 -T&lt;text to calculate digest&gt; 
   *         sha1 &lt;file name to calculate digest&gt;
   *         sha224 -T&lt;text to calculate digest&gt; 
   *         sha224 &lt;file name to calculate digest&gt; 
   *         sha256 -T&lt;text to calculate digest&gt; 
   *         sha256 &lt;file name to calculate digest&gt; 
   *         sha384 -T&lt;text to calculate digest&gt; 
   *         sha384 &lt;file name to calculate digest&gt; 
   *         sha512 -T&lt;text to calculate digest&gt; 
   *         sha512 &lt;file name to calculate digest&gt; 
   *         crc32 -T&lt;text to calculate crc32&gt; 
   *         crc32 &lt;file name to calculate crc32&gt; 
   *         base64encode &lt;input file&gt; &lt;output file&gt; 
   *         base64decode &lt;input file&gt; &lt;output file&gt; 
   *         aes-encrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   *         aes-decrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   *         twofish-encrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   *         twofish-decrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   *         xtea-encrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   *         xtea-decrypt &lt;pass phrase&gt; &lt;input file&gt; &lt;output file&gt; 
   * </pre>
   * 
   * @param args
   */
  public static void main(String[] args)
  {
    try
    {
      String command = args[0].toLowerCase();
      if (command.startsWith("sha"))
      {
        String file = args[1];
        if (file.startsWith("-T"))
        {
          System.out.println(digest(command, file.substring(2)));
        }
        else
        {
          System.out.println(digest(command, new File(file)));

        }
      }

      if (command.startsWith("crc"))
      {
        String file = args[1];
        if (file.startsWith("-T"))
        {
          System.out.println(crc32(file.substring(2)));
        }
        else
        {
          System.out.println(crc32(new File(file)));

        }

      }

      if (command.startsWith("base64encode"))
      {
        String inFile = args[1];
        String outFile = args[2];
        base64Encode(new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("base64decode"))
      {
        String inFile = args[1];
        String outFile = args[2];
        base64Decode(new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("aes-encrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        aesEncrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("aes-decrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        aesDecrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("twofish-encrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        twofishEncrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("twofish-decrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        twofishDecrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("xtea-encrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        xteaEncrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

      if (command.startsWith("xtea-decrypt"))
      {
        String passPhrase = args[1];
        String inFile = args[2];
        String outFile = args[3];
        xteaDecrypt(passPhrase, new File(inFile), new File(outFile));
        System.out.println("Done.");

      }

    }
    catch (Exception e)
    {
      System.out.println(e.toString());
      // usage
      System.out.println("Usage:");
      System.out
          .println("  java com.softabar.crypt.SoftaCryptHelper <command> <argument1> <argument2> ...");
      System.out.println();
      System.out.println("Possible commands:");
      System.out.println("  sha1 -T<text to calculate digest>");
      System.out.println("  sha1 <file name to calculate digest>");
      System.out.println("  sha224 -T<text to calculate digest>");
      System.out.println("  sha224 <file name to calculate digest>");
      System.out.println("  sha256 -T<text to calculate digest>");
      System.out.println("  sha256 <file name to calculate digest>");
      System.out.println("  sha384 -T<text to calculate digest>");
      System.out.println("  sha384 <file name to calculate digest>");
      System.out.println("  sha512 -T<text to calculate digest>");
      System.out.println("  sha512 <file name to calculate digest>");
      System.out.println("  crc32 -T<text to calculate crc32>");
      System.out.println("  crc32 <file name to calculate crc32>");
      System.out.println("  base64encode <input file> <output file>");
      System.out.println("  base64decode <input file> <output file>");
      System.out
          .println("  aes-encrypt <pass phrase> <input file> <output file>");
      System.out
          .println("  aes-decrypt <pass phrase> <input file> <output file>");
      System.out
          .println("  twofish-encrypt <pass phrase> <input file> <output file>");
      System.out
          .println("  twofish-decrypt <pass phrase> <input file> <output file>");
      System.out
          .println("  xtea-encrypt <pass phrase> <input file> <output file>");
      System.out
          .println("  xtea-decrypt <pass phrase> <input file> <output file>");

      System.exit(-1);
    }
  }
}
