Package de.esoco.microsafe.crypto

Source Code of de.esoco.microsafe.crypto.CryptoHandler

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// MicroSafe source file
// Copyright (c) 2006 Elmar Sonnenschein / esoco GmbH
// Last Change: 28.09.2006 by eso
//
// MicroSafe is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// MicroSafe is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// MicroSafe; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA   02111-1307   USA or use the contact information
// from the GNU website http://www.gnu.org
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package de.esoco.microsafe.crypto;

import de.esoco.j2me.resource.ResourceBundle;
import de.esoco.j2me.util.Arrays;
import de.esoco.j2me.util.ProgressMonitor;

import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.engines.TwofishEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;


/********************************************************************
* An instance of this class handles the encryption and decryption of data with
* a particular algorithm.
*
* @author eso
*/
public class CryptoHandler
{
  //~ Static fields/initializers ---------------------------------------------

  /** Char constant for current encryption type (T = Twofish) */
  private static final char ENCRYPTION_TYPE = 'T';

  private static final int MAX_KEY_LENGTH = 32;

  private static final byte KEY_VERIFICATION_VERSION = 1;

  //~ Instance fields --------------------------------------------------------

  private BufferedBlockCipher aCipher;
  private KeyParameter      aFullKey;

  /**
   * If set this monitor will be notified of encryption and other long tasks
   */
  private ProgressMonitor rProgressMonitor = null;

  //~ Constructors -----------------------------------------------------------

  /***************************************
   * Constructor that initializes a default cryptographic cipher (currently a
   * Twofish cipher) with a byte array key.
   *
   * @param rKey A byte array containing the key to encrypt the data with
   */
  public CryptoHandler(byte[] rKey)
  {
    this(new TwofishEngine(), rKey);
  }

  /***************************************
   * Initialize the cryptographic engine with a particular algorithm and a
   * byte array key.
   *
   * @param rAlgorithm The encryption algorithm cipher to use
   * @param rKey       A byte array containing the key to encrypt the data
   *                   with
   */
  public CryptoHandler(BlockCipher rAlgorithm, byte[] rKey)
  {
    SHA1Digest aDigest = new SHA1Digest();
    byte[]     aKey    = new byte[32];

    aCipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(rAlgorithm));

    aDigest.update(rKey, 0, rKey.length);
    aDigest.doFinal(aKey, 0);

    for (int i = aDigest.getDigestSize(); i < aKey.length; i++)
    {
      aKey[i] = (byte) i;
    }

    System.arraycopy(rKey, 0, aKey, 0, rKey.length);
    aFullKey = new KeyParameter(aKey);
  }

  //~ Methods ----------------------------------------------------------------

  /***************************************
   * Returns a char constant describing the encryption type used by
   * CryptoHandler instances.
   *
   * @return The encryption type constant
   */
  public static char getEncryptionType()
  {
    return ENCRYPTION_TYPE;
  }

  /***************************************
   * Returns the maximum key length in bytes that the crypto handler will use
   * when it evaluates a key.
   *
   * @return The maximum key length in bytes
   */
  public static int getMaxKeyLength()
  {
    return MAX_KEY_LENGTH;
  }

  /***************************************
   * Decrypts an array of byte values with the set key and returns a new array
   * with the result.
   *
   * @param  rData The data to decrypt
   *
   * @return A new byte array with the decrypted data
   *
   * @throws CryptoException If a cryptography error occurs
   */
  public byte[] decrypt(byte[] rData) throws CryptoException
  {
    if ((rData == null) || (rData.length == 0))
    {
      return new byte[0];
    }

    return callCipher(rData, false);
  }

  /***************************************
   * Decrypts an array of byte values with the set key and returns a string.
   *
   * @param  rData The data to decrypt
   *
   * @return A new byte array with the decrypted data
   *
   * @throws CryptoException If a cryptography error occurs
   */
  public String decryptString(byte[] rData) throws CryptoException
  {
    return new String(decrypt(rData));
  }

  /***************************************
   * Encrypts an array of byte values with the set key and returns the
   * encrypted data in a new byte array.
   *
   * @param  rData The data to encrypt
   *
   * @return A new byte array with the encrypted data
   *
   * @throws CryptoException If a cryptography error occurs
   */
  public byte[] encrypt(byte[] rData) throws CryptoException
  {
    if ((rData == null) || (rData.length == 0))
    {
      return new byte[0];
    }

    return callCipher(rData, true);
  }

  /***************************************
   * Encrypts a string with the set key and returns the encrypted data in a
   * new byte array.
   *
   * @param  sData The data to encrypt
   *
   * @return A new byte array with the encrypted data
   *
   * @throws CryptoException If a cryptography error occurs
   */
  public byte[] encryptString(String sData) throws CryptoException
  {
    return encrypt(sData.getBytes());
  }

  /***************************************
   * To check if another CrytptoHandler contains the same encryption
   * parameters as this instance.
   *
   * @param  rObj The object to compare with this one
   *
   * @return TRUE if the object is an equal CryptoHandler
   */
  public boolean equals(Object rObj)
  {
    if (rObj instanceof CryptoHandler)
    {
      CryptoHandler rOther    = (CryptoHandler) rObj;
      String      a1      = rOther.aCipher.getUnderlyingCipher()
                          .getAlgorithmName();
      String      a2      = aCipher.getUnderlyingCipher()
                       .getAlgorithmName();
      byte[]      rOtherKey = rOther.aFullKey.getKey();

      return ((a1 == a2) && Arrays.equals(rOtherKey, aFullKey.getKey()));
    }
    else
    {
      return false;
    }
  }

  /***************************************
   * Creates encrypted data that can be used for later verification of the
   * internal key with the method <code>verifyKey()</code>.
   *
   * @param  nIterations The number of iterations to perform to increase
   *                     security
   *
   * @return A new byte array containing the key verification data
   *
   * @see    #verifyKey(byte[])
   */
  public byte[] generateKeyVerification(int nIterations)
    throws CryptoException
  {
    byte[] aVerifyData;
    byte[] aEncryptedKey = aFullKey.getKey();

    if (rProgressMonitor != null)
    {
      rProgressMonitor.init(nIterations,
                  ResourceBundle.getCurrent().getString("MS_KeySetup"));
    }

    try
    {
      for (int i = 0; i < nIterations; i++)
      {
        aEncryptedKey = encrypt(aEncryptedKey);

        if (rProgressMonitor != null)
        {
          rProgressMonitor.advance(1);
        }
      }
    }
    finally
    {
      if (rProgressMonitor != null)
      {
        rProgressMonitor.reset();
      }
    }

    aVerifyData    = new byte[aEncryptedKey.length + 2];
    aVerifyData[0] = KEY_VERIFICATION_VERSION;
    aVerifyData[1] = (byte) nIterations;

    System.arraycopy(aEncryptedKey, 0, aVerifyData, 2,
             aEncryptedKey.length);

    return aVerifyData;
  }

  /***************************************
   * To return a copy of the internal encryption key.
   *
   * @return A new byte array containing a copy of the key
   */
  public byte[] getKey()
  {
    return Arrays.copy(aFullKey.getKey());
  }

  /***************************************
   * Sets the current progress monitor instance used by the handler. If set
   * this monitor will be notified of long running encryption tasks.
   *
   * @param aMonitor The progress monitor to notify or NULL to disable
   */
  public void setProgressMonitor(ProgressMonitor aMonitor)
  {
    rProgressMonitor = aMonitor;
  }

  /***************************************
   * Verifies a key based on a data set generated previously by a call to the
   * method <code>generateKeyVerification()</code>. If the key is not valid an
   * InvalidKeyException will be thrown.
   *
   * @param  rVerifyData A data set created by generateKeyVerification()
   *
   * @throws InvalidKeyException If the key could not be verified
   * @throws CryptoException     If the de/encryption process involved fails
   *
   * @see    #generateKeyVerification()
   */
  public void verifyKey(byte[] rVerifyData) throws CryptoException,
                           InvalidKeyException
  {
    boolean bVerified = false;

    if (rVerifyData[0] == KEY_VERIFICATION_VERSION)
    {
      int    nLoops   = rVerifyData[1];
      byte[] aCompare = generateKeyVerification(nLoops);

      bVerified = Arrays.equals(rVerifyData, aCompare);
    }

    if (!bVerified)
    {
      throw new InvalidKeyException();
    }
  }

  /***************************************
   * Internal routine that invokes the cryptographic algorithm.
   *
   * @param  rData    The data to convert
   * @param  bEncrypt TRUE for encryption, FALSE for decryption
   *
   * @return A new byte array containing the result data
   *
   * @throws CryptoException If initialisation or excution of the cipher fails
   */
  private byte[] callCipher(byte[] rData, boolean bEncrypt)
    throws CryptoException
  {
    try
    {
      aCipher.init(bEncrypt, aFullKey);

      int    nLen     = rData.length;
      int    nOutSize = aCipher.getOutputSize(nLen);
      byte[] aResult  = new byte[nOutSize];

      nLen =  aCipher.processBytes(rData, 0, nLen, aResult, 0);
      nLen += aCipher.doFinal(aResult, nLen);

      if (nLen < nOutSize)
      {
        // if the generated data is shorter (may happen due to padding)
        // then copy the output to a smaller buffer
        byte[] tmp = new byte[nLen];

        System.arraycopy(aResult, 0, tmp, 0, nLen);
        aResult = tmp;
      }

      return aResult;
    }
    catch (Exception e)
    {
      throw new CryptoException("Cryptography failure: " +
                    e.getMessage());
    }
  }
}
TOP

Related Classes of de.esoco.microsafe.crypto.CryptoHandler

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.