祕鑰生成器類KeyGenerator瞭解

這裏是祕鑰生成器類KeyGenerator源碼中開篇的英文翻譯,是對客戶端有沒有顯式初始化密鑰生成器的論述(通過調用<code>init</code>方法),如果沒有顯示的初始化祕鑰生成器則默認使用由每個提供者提供的一個默認的初始化。

  這個類提供了一個祕密的(對稱的)密鑰生成器的功能。
  密鑰生成器被構建出來是通過使用這個類中的一個類方法<code>getInstance</code>構建的。
  密鑰生成器對象是可重用的,即,在一個祕鑰生成之後,可以重用相同的KeyGenerator對象來進一步生成其他的祕鑰。
  有兩種方法生成一個祕鑰:algorithm-independent manner(單獨\獨立算法方式)、algorithm-specific manner(特定於算法的方式),兩者唯一的區別是對象的初始化:

① Algorithm-Independent初始化:
   所有密鑰生成器共用 <i>密鑰大小</i>和一個隨機性的來源(這裏指的是SecureRandom類型的參數:SecureRandom random)
   在這個KeyGenerator類中有一個方法 {@link #init(int, java.security.SecureRandom) init},它接受兩個普遍的共享類型參數。它還有一個方法只需要接收一個<code>keysize</code>參數,並使用SecureRandom實現最高優先級的已安裝的提供商(安卓提供商)作爲隨機性的源(或系統提供的隨機源,如果沒有已安裝的提供商則提供了一個SecureRandom實現),還有一個只需要一個隨機性的來源(這裏如果看不懂可以直接去看下面的源碼: init()方法,這一大堆的都是對這個初始化方法參數的描述)。
   Since no other parameters are specified when you call the above algorithm-independent <code>init</code> methods, it is up to the provider what to do about the algorithm-specific parameters (if any) to be associated with each of the keys(結合上面的話,這句話應該不難看懂).
② Algorithm-Specific初始化:
    對於已經有一組特定算法的參數存在的情況(也就是init()方法參數裏如果想使用特定的算法,這些算法也存在的情況),有兩個init()初始化方法{@link #init(java.security.spec.AlgorithmParameterSpec)init},它們具有一個<code>AlgorithmParameterSpec</code>參數。其中一個方法有一個<code>SecureRandom</code>參數,而其他使用SecureRandom實現最高優先級的已安裝的提供商作爲隨機的來源(或系統提供的隨機源,如果沒有安裝提供者則提供了一個SecureRandom實現)(同樣,這裏如果看不懂可以直接去看下面的源碼: init()方法,這一大堆的都是對這個初始化方法參數的描述)。。

以防客戶端沒有顯式初始化密鑰生成器(通過調用<code>init</code>方法),每個提供者必須提供一個默認初始化。
* Java密碼學體系結構標準算法名稱文檔。
* @作者Jan Lueh
* @see SecretKey
* @since 1.4
* /

package javax.crypto;

import java.util.*;

import java.security.*;
import java.security.Provider.Service;
import java.security.spec.*;

import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;

/**
 * This class provides the functionality of a secret (symmetric) key generator.
 *
 * <p>Key generators are constructed using one of the <code>getInstance</code>
 * class methods of this class.
 *
 * <p>KeyGenerator objects are reusable, i.e., after a key has been
 * generated, the same KeyGenerator object can be re-used to generate further
 * keys.
 *
 * <p>There are two ways to generate a key: in an algorithm-independent
 * manner, and in an algorithm-specific manner.
 * The only difference between the two is the initialization of the object:
 *
 * <ul>
 * <li><b>Algorithm-Independent Initialization</b>
 * <p>All key generators share the concepts of a <i>keysize</i> and a
 * <i>source of randomness</i>.
 * There is an
 * {@link #init(int, java.security.SecureRandom) init}
 * method in this KeyGenerator class that takes these two universally
 * shared types of arguments. There is also one that takes just a
 * <code>keysize</code> argument, and uses the SecureRandom implementation
 * of the highest-priority installed provider as the source of randomness
 * (or a system-provided source of randomness if none of the installed
 * providers supply a SecureRandom implementation), and one that takes just a
 * source of randomness.
 *
 * <p>Since no other parameters are specified when you call the above
 * algorithm-independent <code>init</code> methods, it is up to the
 * provider what to do about the algorithm-specific parameters (if any) to be
 * associated with each of the keys.
 *
 * <li><b>Algorithm-Specific Initialization</b>
 * <p>For situations where a set of algorithm-specific parameters already
 * exists, there are two
 * {@link #init(java.security.spec.AlgorithmParameterSpec) init}
 * methods that have an <code>AlgorithmParameterSpec</code>
 * argument. One also has a <code>SecureRandom</code> argument, while the
 * other uses the SecureRandom implementation
 * of the highest-priority installed provider as the source of randomness
 * (or a system-provided source of randomness if none of the installed
 * providers supply a SecureRandom implementation).
 * </ul>
 *
 * <p>In case the client does not explicitly initialize the KeyGenerator
 * (via a call to an <code>init</code> method), each provider must
 * supply (and document) a default initialization.
 *
 * <p> Android provides the following <code>KeyGenerator</code> algorithms:
 
 * These algorithms are described in the <a href=
 * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
 * KeyGenerator section</a> of the
 * Java Cryptography Architecture Standard Algorithm Name Documentation.
 *
 * @author Jan Luehe
 *
 * @see SecretKey
 * @since 1.4
 */

public class KeyGenerator {
     
    // Android-removed: this debugging mechanism is not used in Android.
    // Android-removed: Android中不使用這種調試機制。
    /*
    private static final Debug pdebug =
                        Debug.getInstance("provider", "Provider");
    private static final boolean skipDebug =
        Debug.isOn("engine=") && !Debug.isOn("keygenerator");
    */

    // see java.security.KeyPairGenerator for failover notes

    private final static int I_NONE   = 1;
    private final static int I_RANDOM = 2;
    private final static int I_PARAMS = 3;
    private final static int I_SIZE   = 4;

    // The provider
    private Provider provider;

    // The provider implementation (delegate)
    private volatile KeyGeneratorSpi spi;

    // The algorithm
    private final String algorithm;

    private final Object lock = new Object();

    private Iterator<Service> serviceIterator;

    private int initType;
    private int initKeySize;
    private AlgorithmParameterSpec initParams;
    private SecureRandom initRandom;

    /**創建密鑰生成器對象。
     * Creates a KeyGenerator object.
     *
     * @param keyGenSpi the delegate
     * @param provider the provider
     * @param algorithm the algorithm
     */
    protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider,
                           String algorithm) {
        this.spi = keyGenSpi;
        this.provider = provider;
        this.algorithm = algorithm;

        // Android-removed: this debugging mechanism is not used in Android.
        /*
        if (!skipDebug && pdebug != null) {
            pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                this.provider.getName());
        }
        */
    }

    private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
        this.algorithm = algorithm;
        List<Service> list =
                GetInstance.getServices("KeyGenerator", algorithm);
        serviceIterator = list.iterator();
        initType = I_NONE;
        // fetch and instantiate initial spi
        if (nextSpi(null, false) == null) {
            throw new NoSuchAlgorithmException
                (algorithm + " KeyGenerator not available");
        }

        // Android-removed: this debugging mechanism is not used in Android.
        /*
        if (!skipDebug && pdebug != null) {
            pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
                this.provider.getName());
        }
        */
    }

    /**返回此<code>KeyGenerator</code>對象的算法名。
     * Returns the algorithm name of this <code>KeyGenerator</code> object.
     *
     * <p>This is the same name that was specified in one of the
     * <code>getInstance</code> calls that created this
     * <code>KeyGenerator</code> object.
     *
     * @return the algorithm name of this <code>KeyGenerator</code> object.
     */
    public final String getAlgorithm() {
        return this.algorithm;
    }

    /**返回一個<code>KeyGenerator</code>對象,該對象爲指定的算法生成密鑰。
     * Returns a <code>KeyGenerator</code> object that generates secret keys
     * for the specified algorithm.
     *此方法遍歷已註冊的安全提供程序列表,從首選的提供程序開始。返回一個新的KeyGenerator對象, 
     *該對象封裝了來自第一個支持指定算法的提供程序的KeyGeneratorSpi實現。
     * <p> This method traverses the list of registered security Providers,
     * starting with the most preferred Provider.
     * A new KeyGenerator object encapsulating the
     * KeyGeneratorSpi implementation from the first
     * Provider that supports the specified algorithm is returned.
     *注意,註冊的提供者列表可以通過{@link Security#getProviders() Security.getProviders()}方法來檢索
     * <p> Note that the list of registered providers may be retrieved via
     * the {@link Security#getProviders() Security.getProviders()} method.
     *
     * @param algorithm the standard name of the requested key algorithm.
     * See the KeyGenerator section in the <a href=
     * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
     * for information about standard algorithm names.
     *
     * @return the new <code>KeyGenerator</code> object.
     *
     * @exception NullPointerException if the specified algorithm is null.
     *
     * @exception NoSuchAlgorithmException if no Provider supports a
     *          KeyGeneratorSpi implementation for the
     *          specified algorithm.
     *
     * @see java.security.Provider
     */
    //只有一個參數的getInstance()方法
    public static final KeyGenerator getInstance(String algorithm)
            throws NoSuchAlgorithmException {
        return new KeyGenerator(algorithm);
    }

    /**
     * Returns a <code>KeyGenerator</code> object that generates secret keys
     * for the specified algorithm.
     *
     * <p> A new KeyGenerator object encapsulating the
     * KeyGeneratorSpi implementation from the specified provider
     * is returned.  The specified provider must be registered
     * in the security provider list.
     *
     * <p> Note that the list of registered providers may be retrieved via
     * the {@link Security#getProviders() Security.getProviders()} method.
     *
     * @param algorithm the standard name of the requested key algorithm.
     * See the KeyGenerator section in the <a href=
     * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
     * for information about standard algorithm names.
     *
     * @param provider the name of the provider.
     *
     * @return the new <code>KeyGenerator</code> object.
     *
     * @exception NullPointerException if the specified algorithm is null.
     *
     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
     *          implementation for the specified algorithm is not
     *          available from the specified provider.
     *
     * @exception NoSuchProviderException if the specified provider is not
     *          registered in the security provider list.
     *
     * @exception IllegalArgumentException if the <code>provider</code>
     *          is null or empty.
     *
     * @see java.security.Provider
     */
    public static final KeyGenerator getInstance(String algorithm,
            String provider) throws NoSuchAlgorithmException,
            NoSuchProviderException {
        // Android-added: Check for Bouncy Castle deprecation
        Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
        Instance instance = JceSecurity.getInstance("KeyGenerator",
                KeyGeneratorSpi.class, algorithm, provider);
        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
                instance.provider, algorithm);
    }

    /**返回一個<code>KeyGenerator</code>對象,該對象爲指定的算法生成密鑰。
     * Returns a <code>KeyGenerator</code> object that generates secret keys
     * for the specified algorithm.
     *
     * <p> A new KeyGenerator object encapsulating the
     * KeyGeneratorSpi implementation from the specified Provider
     * object is returned.  Note that the specified Provider object
     * does not have to be registered in the provider list.
     *
     * @param algorithm the standard name of the requested key algorithm.
     * See the KeyGenerator section in the <a href=
     * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
     * for information about standard algorithm names.
     *
     * @param provider the provider.
     *
     * @return the new <code>KeyGenerator</code> object.
     *
     * @exception NullPointerException if the specified algorithm is null.
     *
     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
     *          implementation for the specified algorithm is not available
     *          from the specified Provider object.
     *
     * @exception IllegalArgumentException if the <code>provider</code>
     *          is null.
     *
     * @see java.security.Provider
     */
    //包含2個參數的getInstance()方法
    public static final KeyGenerator getInstance(String algorithm,
            Provider provider) throws NoSuchAlgorithmException {
        // Android-added: Check for Bouncy Castle deprecation
        Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
        Instance instance = JceSecurity.getInstance("KeyGenerator",
                KeyGeneratorSpi.class, algorithm, provider);
        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
                instance.provider, algorithm);
    }

    /**返回此<code>KeyGenerator</code> 對象的提供程者。
     * Returns the provider of this <code>KeyGenerator</code> object.
     *
     * @return the provider of this <code>KeyGenerator</code> object
     */
    public final Provider getProvider() {
        synchronized (lock) {
            disableFailover();
            return provider;
        }
    }

    /**
     * Update the active spi of this class and return the next
     * implementation for failover. If no more implemenations are
     * available, this method returns null. However, the active spi of
     * this class is never set to null.
     */
    private KeyGeneratorSpi nextSpi(KeyGeneratorSpi oldSpi,
            boolean reinit) {
        synchronized (lock) {
            // somebody else did a failover concurrently
            // try that spi now
            if ((oldSpi != null) && (oldSpi != spi)) {
                return spi;
            }
            if (serviceIterator == null) {
                return null;
            }
            while (serviceIterator.hasNext()) {
                Service s = serviceIterator.next();
                if (JceSecurity.canUseProvider(s.getProvider()) == false) {
                    continue;
                }
                try {
                    Object inst = s.newInstance(null);
                    // ignore non-spis
                    if (inst instanceof KeyGeneratorSpi == false) {
                        continue;
                    }
                    KeyGeneratorSpi spi = (KeyGeneratorSpi)inst;
                    if (reinit) {
                        if (initType == I_SIZE) {
                            spi.engineInit(initKeySize, initRandom);
                        } else if (initType == I_PARAMS) {
                            spi.engineInit(initParams, initRandom);
                        } else if (initType == I_RANDOM) {
                            spi.engineInit(initRandom);
                        } else if (initType != I_NONE) {
                            throw new AssertionError
                                ("KeyGenerator initType: " + initType);
                        }
                    }
                    provider = s.getProvider();
                    this.spi = spi;
                    return spi;
                } catch (Exception e) {
                    // ignore
                }
            }
            disableFailover();
            return null;
        }
    }

    void disableFailover() {
        serviceIterator = null;
        initType = 0;
        initParams = null;
        initRandom = null;
    }

    /**初始化祕鑰生成器,注意比較參數
     * Initializes this key generator.
     *
     * @param random the source of randomness for this generator
     */
    public final void init(SecureRandom random) {
        if (serviceIterator == null) {
            spi.engineInit(random);
            return;
        }
        RuntimeException failure = null;
        KeyGeneratorSpi mySpi = spi;
        do {
            try {
                mySpi.engineInit(random);
                initType = I_RANDOM;
                initKeySize = 0;
                initParams = null;
                initRandom = random;
                return;
            } catch (RuntimeException e) {
                if (failure == null) {
                    failure = e;
                }
                mySpi = nextSpi(mySpi, false);
            }
        } while (mySpi != null);
        throw failure;
    }

    /**使用指定的參數集初始化此密鑰生成器。
     * Initializes this key generator with the specified parameter set.
     *
     * <p> If this key generator requires any random bytes, it will get them
     * using the {@link java.security.SecureRandom}
     * implementation of the highest-priority installed
     * provider as the source of randomness.
     * (If none of the installed providers supply an implementation of
     * SecureRandom, a system-provided source of randomness will be used.)
     *
     * @param params the key generation parameters
     *
     * @exception InvalidAlgorithmParameterException if the given parameters
     * are inappropriate for this key generator
     */
    public final void init(AlgorithmParameterSpec params)
        throws InvalidAlgorithmParameterException
    {
        init(params, JceSecurity.RANDOM);
    }

    /**使用指定的參數集和用戶提供的隨機源初始化此密鑰生成器。
     * Initializes this key generator with the specified parameter
     * set and a user-provided source of randomness.
     *
     * @param params the key generation parameters
     * @param random the source of randomness for this key generator
     *
     * @exception InvalidAlgorithmParameterException if <code>params</code> is
     * inappropriate for this key generator
     */
    public final void init(AlgorithmParameterSpec params, SecureRandom random)
        throws InvalidAlgorithmParameterException
    {
        if (serviceIterator == null) {
            spi.engineInit(params, random);
            return;
        }
        Exception failure = null;
        KeyGeneratorSpi mySpi = spi;
        do {
            try {
                mySpi.engineInit(params, random);
                initType = I_PARAMS;
                initKeySize = 0;
                initParams = params;
                initRandom = random;
                return;
            } catch (Exception e) {
                if (failure == null) {
                    failure = e;
                }
                mySpi = nextSpi(mySpi, false);
            }
        } while (mySpi != null);
        if (failure instanceof InvalidAlgorithmParameterException) {
            throw (InvalidAlgorithmParameterException)failure;
        }
        if (failure instanceof RuntimeException) {
            throw (RuntimeException)failure;
        }
        throw new InvalidAlgorithmParameterException("init() failed", failure);
    }

    /**通過確定的密鑰大小初始化此密鑰生成器。
     * Initializes this key generator for a certain keysize.
     *
     * <p> If this key generator requires any random bytes, it will get them
     * using the
     * {@link java.security.SecureRandom}
     * implementation of the highest-priority installed
     * provider as the source of randomness.
     * (If none of the installed providers supply an implementation of
     * SecureRandom, a system-provided source of randomness will be used.)
     *
     * @param keysize the keysize. This is an algorithm-specific metric,
     * specified in number of bits.
     *
     * @exception InvalidParameterException if the keysize is wrong or not
     * supported.
     */
    public final void init(int keysize) {
        init(keysize, JceSecurity.RANDOM);
    }

    /**通過使用用戶提供的隨機源和使用特定的密鑰大小初始化密鑰生成器
     * Initializes this key generator for a certain keysize, using a
     * user-provided source of randomness.
     *
     * @param keysize the keysize. This is an algorithm-specific metric,
     * specified in number of bits.
     * @param random the source of randomness for this key generator
     *
     * @exception InvalidParameterException if the keysize is wrong or not
     * supported.
     */
    public final void init(int keysize, SecureRandom random) {
        if (serviceIterator == null) {
            spi.engineInit(keysize, random);
            return;
        }
        RuntimeException failure = null;
        KeyGeneratorSpi mySpi = spi;
        do {
            try {
                mySpi.engineInit(keysize, random);
                initType = I_SIZE;
                initKeySize = keysize;
                initParams = null;
                initRandom = random;
                return;
            } catch (RuntimeException e) {
                if (failure == null) {
                    failure = e;
                }
                mySpi = nextSpi(mySpi, false);
            }
        } while (mySpi != null);
        throw failure;
    }

    /**創建祕鑰
     * Generates a secret key.
     *
     * @return the new key
     */
    public final SecretKey generateKey() {
        if (serviceIterator == null) {
            return spi.engineGenerateKey();
        }
        RuntimeException failure = null;
        KeyGeneratorSpi mySpi = spi;
        do {
            try {
                return mySpi.engineGenerateKey();
            } catch (RuntimeException e) {
                if (failure == null) {
                    failure = e;
                }
                mySpi = nextSpi(mySpi, true);
            }
        } while (mySpi != null);
        throw failure;
   }
}

使用實例:

void CreateKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM, KEYSTORE_NAME);
        KeyGenParameterSpec keyGenSpec =
                new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                        .setBlockModes(BLOCK_MODE)
                        .setEncryptionPaddings(ENCRYPTION_PADDING)
                        .setUserAuthenticationRequired(true)
                        .build();
        keyGen.init(keyGenSpec);
        keyGen.generateKey();
    }

其中第一行代碼:

KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM, KEYSTORE_NAME);

進入這個getInstance()方法看看,他們所謂的provider就是KEYSTORE_NAME:

    /**
     * Returns a <code>KeyGenerator</code> object that generates secret keys
     * for the specified algorithm.
     *
     * <p> A new KeyGenerator object encapsulating the
     * KeyGeneratorSpi implementation from the specified provider
     * is returned.  The specified provider must be registered
     * in the security provider list.
     *
     * <p> Note that the list of registered providers may be retrieved via
     * the {@link Security#getProviders() Security.getProviders()} method.
     *
     * @param algorithm the standard name of the requested key algorithm.
     * See the KeyGenerator section in the <a href=
     * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyGenerator">
     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
     * for information about standard algorithm names.
     *
     * @param provider the name of the provider.
     *
     * @return the new <code>KeyGenerator</code> object.
     *
     * @exception NullPointerException if the specified algorithm is null.
     *
     * @exception NoSuchAlgorithmException if a KeyGeneratorSpi
     *          implementation for the specified algorithm is not
     *          available from the specified provider.
     *
     * @exception NoSuchProviderException if the specified provider is not
     *          registered in the security provider list.
     *
     * @exception IllegalArgumentException if the <code>provider</code>
     *          is null or empty.
     *
     * @see java.security.Provider
     */
    public static final KeyGenerator getInstance(String algorithm,
            String provider) throws NoSuchAlgorithmException,
            NoSuchProviderException {
        // Android-added: Check for Bouncy Castle deprecation
        Providers.checkBouncyCastleDeprecation(provider, "KeyGenerator", algorithm);
        Instance instance = JceSecurity.getInstance("KeyGenerator",
                KeyGeneratorSpi.class, algorithm, provider);
        return new KeyGenerator((KeyGeneratorSpi)instance.impl,
                instance.provider, algorithm);
    }
static final String KEYSTORE_NAME="AndroidKeyStore";

好了,到這裏吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章