// This file is currently unlocked (change this line if you lock the file)
//
// $Log: RawKeyGenerator.java,v $
// Revision 1.1.1.1  1997/11/03 22:36:56  hopwood
// + Imported to CVS (tagged as 'start').
//
// Revision 0.1.0.6  1997/08/14  David Hopwood
// + Made this class implement java.security.ExtendedKeyGenerator.
// + Changed isWeak from public to protected.
//
// Revision 0.1.0.5  1997/08/12  David Hopwood
// + Made this class Cloneable.
// + Cosmetic changes.
//
// Revision 0.1.0.4  1997/08/04  David Hopwood
// + Changed uses of InvalidKeyFormatException to InvalidKeyException.
//
// Revision 0.1.0.3  1997/08/01  David Hopwood
// + Renamed strength parameter to seedlength, and added a warning that
//   it is not a cryptographic strength.
// + Added better support for algorithms with variable-length keys:
//   - minimum, default and maximum seed lengths
//   - accessors for these variables
//   - initialize(SecureRandom random, int length) method
//   - isValidKeyLength(int length) method.
// + Added a public isWeak(byte[] key) method that returns false
//   by default.
// + Changed the default implementation of generateKey([B) to use
//   isWeak.
// + Since engineGenerateKey is allowed to modify the seed array,
//   generateKey([B) must always copy it.
// + Renamed private 'rng' field to 'source', for consistency with
//   RSA keygen code.
// + Committed to changes made in 1.0.2 by removing commented-out code.
//
// Revision 0.1.0.2  1997/07/22  R. Naffah
// + Added weakAllowed variable, with accessor methods.
// + Removed allowWeak from signatures since now it's an instance
//   variable.
// + Renamed 'keyBytesFromSeed' to 'engineGenerateKey'.
//
// Revision 0.1.0.1  1997/07/19  R. Naffah
// + Added WeakKeyExceptions where needed.
// + Changed the signature of generateKey(String,[B,Z) to always consider
//   a "RAW" format as the name of the class implies.
// + Added the generateKey([B) convenience method from KeyGenerator class.
// + Added code to the generateKey(String,[B,Z) method to consider only
//   seedlength bytes from user input.
//
// Revision 0.1.0.0  1997/?/0?  David Hopwood
// + Original version.
//
// $Endlog$
/*
 * Copyright (c) 1997 Systemics Ltd
 * on behalf of the Cryptix Development Team.  All rights reserved.
 */

package cryptix.provider.key;

import java.security.SecretKey;
import java.security.SecureRandom;
import java.security.KeyGenerator;
import java.security.ExtendedKeyGenerator;
import java.security.KeyException;
import java.security.WeakKeyException;
import java.security.InvalidKeyException;

/**
 * RawKeyGenerator acts as a superclass for other Cryptix key generator
 * classes.
 * <p>
 *
 * <b>Copyright</b> &copy; 1997
 * <a href="http://www.systemics.com/">Systemics Ltd</a> on behalf of the
 * <a href="http://www.systemics.com/docs/cryptix/">Cryptix Development Team</a>.
 * <br>All rights reserved.
 *
 * <p><b>$Revision: 1.1.1.1 $</b>
 * @author  David Hopwood
 * @author  Raif S. Naffah
 * @since   Cryptix 2.2.0a, 2.2.2
 */
public class RawKeyGenerator
extends KeyGenerator
implements ExtendedKeyGenerator, Cloneable
{

// Constants and variables
//............................................................................
    
    /**
     * A cryptographically secure source of randomness for this key-generator.
     */
    private SecureRandom source;

    /**
     * The minimum length in bytes of seed data needed to create a key.
     */
    private int minLength;

    /**
     * The length in bytes of seed data that will be used by generateKey()
     * to create random keys.
     */
    private int seedLength;

    /**
     * The maximum length in bytes of seed data that can be used to create
     * a key.
     */
    private int maxLength;

    /**
     * Some cipher algorithms exhibit weaknesses when a special class of keys
     * are used to process data. Usually these keys are classified into Weak
     * and Semi-Weak keys, and are documented in the cryptography literature.
     * <p>
     * In this implementation we allow the user to specify if the key generator
     * should check for such a characteristic. We also allow the programmers
     * to provide code for implementing this check. Furthermore, we group both
     * weak and semi-weak keys into one category.
     * <p>
     * This variable when set to true indicates that the user will accept 'Weak'
     * and 'Semi-Weak' keys generated by this key generator. By default it is
     * set to false.
     */
    private boolean weakAllowed; // defaults to false


// Constructors
//............................................................................

    /**
     * Constructor for use by subclasses that require a fixed-length key.
     * Each candidate key will be <i>seedlength</i> bytes long.
     * <p>
     * Note: <i>seedlength</i> does not correspond to a cryptographic
     * strength. In particular, there is no implication that a brute-force
     * attack against the algorithm would require 256^seedlength trials.
     *
     * @param  algorithm    the standard string name of the algorithm.
     * @param  seedlength   the desired seed length in bytes.
     * @exception IllegalArgumentException if seedlength <= 0
     */
    protected RawKeyGenerator (String algorithm, int seedlength)
    throws IllegalArgumentException {
        super(algorithm);
        if (seedlength <= 0)
            throw new IllegalArgumentException("seedlength <= 0");

        minLength = seedlength;
        seedLength = seedlength;
        maxLength = seedlength;
    }

    /**
     * Constructor for use by subclasses that allow variable-length keys.
     * Each candidate key will be a minimum of <i>minlength</i>, and a
     * maximum of <i>maxlength</i> bytes long. If the <code>generateKey()</code>
     * method is used without any other parameters or initialization, the
     * key will be <i>defaultlength</i> bytes long.
     * <p>
     * Note: none of these length parameters correspond to a cryptographic
     * strength. In particular, there is no implication that a brute-force
     * attack against the algorithm would require 256^(length of key) trials.
     *
     * @param  algorithm        the standard string name of the algorithm.
     * @param  minlength        the minimum seed length in bytes.
     * @param  defaultlength    the default seed length in bytes.
     * @param  maxlength        the maximum useful seed length in bytes.
     * @exception IllegalArgumentException if !(0 < minlength &&
     *                          minlength <= defaultlength &&
     *                          defaultlength <= maxlength)
     */
    protected RawKeyGenerator (String algorithm, int minlength,
                               int defaultlength, int maxlength)
    throws IllegalArgumentException {
        super(algorithm);
        if (!(0 < minlength && minlength <= defaultlength && defaultlength <= maxlength))
            throw new IllegalArgumentException(
                "!(0 < minlength && minlength <= defaultlength && defaultlength <= maxlength)");

        minLength = minlength;
        seedLength = defaultlength;
        maxLength = maxlength;
    }


// KeyGenerator abstract methods implementation
//............................................................................

    /**
     * Generates a key. This method generates a new random key every
     * time it is called.
     * <p>
     * If a source of random bytes has not been set using one of the
     * <code>initialize</code> methods, <code>new SecureRandom()</code>
     * will be used.
     *
     * @return the new key.
     */
    public SecretKey generateKey() {
        if (source == null)
            source = new SecureRandom();

        byte[] seed = new byte[seedLength];
        source.nextBytes(seed);

        while (true) {
            try {
                byte[] keybytes = engineGenerateKey(seed);
                return new RawSecretKey(getAlgorithm(), keybytes);
            } catch (KeyException e) { /* try again */
            }
        }
    }

    /**
     * Initializes the key generator.
     *
     * @param random    the source of randomness for this generator.
     */
    public void initialize(SecureRandom random) {
        source = random;
    }


// IJCE additional methods
//............................................................................

    /**
     * Initializes the key generator, and sets a specific key length
     * for use with algorithms that allow variable-length keys.
     * <p>
     * The <i>length</i> parameter only affects randomly generated
     * keys (i.e. the <code>generateKey()</code> method without
     * parameters).
     *
     * @param random    the source of randomness for this generator.
     * @param length    the desired key length in bytes.
     * @exception IllegalArgumentException if length is not valid for
     *          this algorithm.
     */
    public void initialize(SecureRandom random, int length) {
        if (!isValidKeyLength(length))
            throw new IllegalArgumentException("invalid key length for " +
                getAlgorithm() + ": " + length + " bytes");

        source = random;
        seedLength = length;
    }

    /**
     * Returns true if this object is allowed to generate weak and
     * semi-weak keys; false otherwise.
     */
    public boolean isWeakAllowed () {
        return weakAllowed;
    }

    /**
     * Sets whether this object is allowed to generate weak and
     * semi-weak keys.
     *
     * @param allowWeak true if weak/semi-weak keys are allowed.
     */
    public void setWeakAllowed (boolean allowWeak) {
        weakAllowed = allowWeak;
    }

    /**
     * Returns the minimum key length for this algorithm.
     */
    public int getMinimumKeyLength() {
        return minLength;
    }

    /**
     * Returns the key length that will be used by
     * <code>generateKey()</code> to create new random keys. This is
     * either the default key length determined by the KeyGenerator
     * for this algorithm, or the length set using
     * <code>initialize(SecureRandom random, int length)</code>.
     */
    public int getDefaultKeyLength() {
        return seedLength;
    }

    /**
     * Returns the maximum useful key length for this algorithm.
     */
    public int getMaximumKeyLength() {
        return maxLength;
    }

    /**
     * Returns true iff <i>length</i> is a valid key length (in bytes)
     * for this algorithm.
     * <p>
     * The default implementation returns true if <i>length</i> is between
     * the minimum and maximum key lengths. Some algorithms will override
     * this method to specify a more restricted set of values.
     */
    public boolean isValidKeyLength(int length) {
        return length >= minLength && length <= maxLength;
    }

    /**
     * Generates a key from an encoded byte array. The format of the
     * secret key is "RAW". The contents of <i>data</i> will not be
     * modified.
     * <p>
     * The encoded key bytes may differ from <i>data</i> in order to
     * make sure that they represent a valid key. For example, if keys
     * for this algorithm conventionally include parity bits, those
     * bits will be set correctly. For most algorithms, <i>data</i> is
     * used unchanged.
     *
     * @param  data     user supplied raw-encoded data from which a secret
     *                  key will be generated.
     * @return the new key.
     * @exception NullPointerException if data == null
     * @exception WeakKeyException if <i>isWeakAllowed()</i> is false, and
     *                  <i>data</i> represents a weak key for this algorithm.
     * @exception InvalidKeyException if the length of <i>data</i> is not
     *                  valid for this algorithm.
     */
    public SecretKey generateKey (byte[] data)
    throws WeakKeyException, InvalidKeyException {

        if (!isValidKeyLength(data.length))
            throw new InvalidKeyException("invalid key length for " +
                getAlgorithm() + ": " + data.length + " bytes");

        byte[] keybytes = engineGenerateKey((byte[]) (data.clone()));

        return new RawSecretKey(getAlgorithm(), keybytes);
    }

    /**
     * This method allows subclasses to modify the bytes that will be
     * used to generate a key. This might be necessary in order to set
     * parity bits, for example.
     * <p>
     * The <i>seed</i> array contains either randomly generated bytes,
     * or an encoded form of the key. Subclasses should throw a
     * WeakKeyException if <i>isWeakAllowed()</i> is false, and a weak
     * key would have been generated.
     * <p>
     * The default implementation is as follows: If weak keys are not
     * allowed, and the seed array represents a weak key (i.e.
     * <code>!isWeakAllowed() && isWeak(seed)</code>), throw a
     * WeakKeyException. Otherwise, just return the seed array. This
     * is sufficient if the key does not have any special form (for
     * example, parity bits that should be set correctly).
     * <p>
     * The seed array can be modified if that is convenient.
     *
     * @param  seed     the seed bytes for this key.
     * @return the key encoding.
     */
    protected byte[] engineGenerateKey (byte[] seed)
    throws WeakKeyException, InvalidKeyException {
        if (!isWeakAllowed() && isWeak(seed))
            throw new WeakKeyException(getAlgorithm());

        return seed;
    }

    /**
     * Returns true iff <i>key</i> represents a weak or semi-weak key
     * for this algorithm. The length of the array is not checked, and
     * an ArrayIndexOutOfBoundsException may be thrown if it is too short.
     * <p>
     * The default implementation returns false.
     */
    protected boolean isWeak(byte[] key) {
        return false;
    }
}
