本文次要钻研一下jasypt的IVGenerator

IVGenerator

org/jasypt/salt/IVGenerator.java

/** * <p> * Common interface for all IV generators which can be applied in digest * or encryption operations. * </p> * <p> * <b>Every implementation of this interface must be thread-safe</b>. * </p> * * @since 1.9.3 * * @author Alex Scal * */public interface IVGenerator {    /**     * <p>     * This method will be called for requesting the generation of a new     * IV of the specified length.     * </p>     *     * @param length the requested length for the IV.     * @return the generated IV.     */    byte[] generateIV(int length);    /**     * <p>     * Determines if the digests and encrypted messages created with a     * specific IV generator will include (prepended) the unencrypted     * IV itself, so that it can be used for matching and decryption     * operations.     * </p>     * <p>     * Generally, including the IV unencrypted in encryption results will     * be mandatory for randomly generated IVs, or for those generated in a     * non-predictable manner.     * Otherwise, digest matching and decryption operations will always fail.     * </p>     *     * @return whether the plain (unencrypted) IV has to be included in     *         encryption results or not.     */    public boolean includePlainIVInEncryptionResults();}
IVGenerator定义了generateIV及includePlainIVInEncryptionResults办法,它有三个实现类,别离是NoOpIVGenerator、StringFixedIVGenerator、RandomIVGenerator

NoOpIVGenerator

public class NoOpIVGenerator implements IVGenerator {    /**     * Return IV with the specified byte length.     *     * @param lengthBytes length in bytes.     * @return the generated salt.     */     @Override    public byte[] generateIV(final int lengthBytes) {        return null;    }    /**     * As this salt generator provides a fixed IV, its inclusion     * unencrypted in encryption results     * is not necessary, and in fact not desirable (so that it remains hidden).     *     * @return false     */    @Override    public boolean includePlainIVInEncryptionResults() {        return false;    }}
次要用于解密旧版(不应用iv)的明码

StringFixedIVGenerator

org/jasypt/salt/StringFixedIVGenerator.java

public class StringFixedIVGenerator implements IVGenerator {    private static final String DEFAULT_CHARSET = "UTF-8";    private final String iv;    private final String charset;    private final byte[] ivBytes;    /**     * Creates a new instance of <tt>FixedStringIVGenerator</tt> using     * the default charset.     *     * @param iv the specified salt.     */    public StringFixedIVGenerator(final String iv) {        this(iv, null);    }    /**     * Creates a new instance of <tt>FixedStringIVGenerator</tt>     *     * @param iv the specified salt.     * @param charset the specified charset     */    public StringFixedIVGenerator(final String iv, final String charset) {        super();        CommonUtils.validateNotNull(iv, "IV cannot be set null");        this.iv = iv;        this.charset = (charset != null? charset : DEFAULT_CHARSET);        try {            this.ivBytes = this.iv.getBytes(this.charset);        } catch (UnsupportedEncodingException e) {            throw new EncryptionInitializationException(                    "Invalid charset specified: " + this.charset);        }    }    /**     * Return IV with the specified byte length.     *     * @param lengthBytes length in bytes.     * @return the generated salt.     */    public byte[] generateIV(final int lengthBytes) {        if (this.ivBytes.length < lengthBytes) {            throw new EncryptionInitializationException(                    "Requested IV larger than set");        }        final byte[] generatedIV = new byte[lengthBytes];        System.arraycopy(this.ivBytes, 0, generatedIV, 0, lengthBytes);        return generatedIV;    }    /**     * As this salt generator provides a fixed IV, its inclusion     * unencrypted in encryption results     * is not necessary, and in fact not desirable (so that it remains hidden).     *     * @return false     */    @Override    public boolean includePlainIVInEncryptionResults() {        return false;    }}
StringFixedIVGenerator依据固定的值和长度来生成iv,如果固定值的长度小于申请生成iv的长度则抛出EncryptionInitializationException,否则从后面取指定长度返回

RandomIVGenerator

org/jasypt/salt/RandomIVGenerator.java

public class RandomIVGenerator implements IVGenerator {    /**     * The default algorithm to be used for secure random number     * generation: set to SHA1PRNG.     */    private static final String GENERATOR_ALGORITHM = "SHA1PRNG";    private final SecureRandom random;    /**     * Creates a new instance of <tt>RandomIVGenerator</tt> using the     * default secure random number generation algorithm.     */    public RandomIVGenerator() {        this(GENERATOR_ALGORITHM);    }    /**     * Creates a new instance of <tt>RandomIVGenerator</tt> specifying a     * secure random number generation algorithm.     *     * @since 1.9.3     *     */    public RandomIVGenerator(String secureRandomAlgorithm) {        super();        try {            this.random = SecureRandom.getInstance(secureRandomAlgorithm);        } catch (NoSuchAlgorithmException e) {            throw new EncryptionInitializationException(e);        }    }    /**     * Generate a random IV of the specified length in bytes.     *     * @param length length in bytes.     * @return the generated IV.     */    @Override    public byte[] generateIV(int length) {        byte[] iv = new byte[length / 8];        random.nextBytes(iv);        return iv;    }    /**     * This IV generator needs the salt to be included unencrypted in     * encryption results, because of its being random. This method will always     * return true.     *     * @return true     */    @Override    public boolean includePlainIVInEncryptionResults() {        return true;    }}
RandomIVGenerator能够依据传入的secureRandomAlgorithm来生成iv,如果不传默认是SHA1PRNG

PBES2Core

com/sun/crypto/provider/PBES2Core.java

protected void engineInit(int opmode, Key key,                              AlgorithmParameterSpec params,                              SecureRandom random)        throws InvalidKeyException, InvalidAlgorithmParameterException {        if (key == null) {            throw new InvalidKeyException("Null key");        }        byte[] passwdBytes = key.getEncoded();        char[] passwdChars = null;        PBEKeySpec pbeSpec;        try {            if ((passwdBytes == null) ||                    !(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3))) {                throw new InvalidKeyException("Missing password");            }            // TBD: consolidate the salt, ic and IV parameter checks below            // Extract salt and iteration count from the key, if present            if (key instanceof javax.crypto.interfaces.PBEKey) {                salt = ((javax.crypto.interfaces.PBEKey)key).getSalt();                if (salt != null && salt.length < 8) {                    throw new InvalidAlgorithmParameterException(                            "Salt must be at least 8 bytes long");                }                iCount = ((javax.crypto.interfaces.PBEKey)key).getIterationCount();                if (iCount == 0) {                    iCount = DEFAULT_COUNT;                } else if (iCount < 0) {                    throw new InvalidAlgorithmParameterException(                            "Iteration count must be a positive number");                }            }            // Extract salt, iteration count and IV from the params, if present            if (params == null) {                if (salt == null) {                    // generate random salt and use default iteration count                    salt = new byte[DEFAULT_SALT_LENGTH];                    random.nextBytes(salt);                    iCount = DEFAULT_COUNT;                }                if ((opmode == Cipher.ENCRYPT_MODE) ||                        (opmode == Cipher.WRAP_MODE)) {                    // generate random IV                    byte[] ivBytes = new byte[blkSize];                    random.nextBytes(ivBytes);                    ivSpec = new IvParameterSpec(ivBytes);                }            } else {                if (!(params instanceof PBEParameterSpec)) {                    throw new InvalidAlgorithmParameterException                            ("Wrong parameter type: PBE expected");                }                // salt and iteration count from the params take precedence                byte[] specSalt = ((PBEParameterSpec) params).getSalt();                if (specSalt != null && specSalt.length < 8) {                    throw new InvalidAlgorithmParameterException(                            "Salt must be at least 8 bytes long");                }                salt = specSalt;                int specICount = ((PBEParameterSpec) params).getIterationCount();                if (specICount == 0) {                    specICount = DEFAULT_COUNT;                } else if (specICount < 0) {                    throw new InvalidAlgorithmParameterException(                            "Iteration count must be a positive number");                }                iCount = specICount;                AlgorithmParameterSpec specParams =                        ((PBEParameterSpec) params).getParameterSpec();                if (specParams != null) {                    if (specParams instanceof IvParameterSpec) {                        ivSpec = (IvParameterSpec)specParams;                    } else {                        throw new InvalidAlgorithmParameterException(                                "Wrong parameter type: IV expected");                    }                } else if ((opmode == Cipher.ENCRYPT_MODE) ||                        (opmode == Cipher.WRAP_MODE)) {                    // generate random IV                    byte[] ivBytes = new byte[blkSize];                    random.nextBytes(ivBytes);                    ivSpec = new IvParameterSpec(ivBytes);                } else {                    throw new InvalidAlgorithmParameterException(                            "Missing parameter type: IV expected");                }            }            passwdChars = new char[passwdBytes.length];            for (int i = 0; i < passwdChars.length; i++)                passwdChars[i] = (char) (passwdBytes[i] & 0x7f);            pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, keyLength);            // password char[] was cloned in PBEKeySpec constructor,            // so we can zero it out here        } finally {            if (passwdChars != null) Arrays.fill(passwdChars, '\0');            if (passwdBytes != null) Arrays.fill(passwdBytes, (byte)0x00);        }        SecretKey s = null;        try {            s = kdf.engineGenerateSecret(pbeSpec);        } catch (InvalidKeySpecException ikse) {            InvalidKeyException ike =                new InvalidKeyException("Cannot construct PBE key");            ike.initCause(ikse);            throw ike;        }        byte[] derivedKey = s.getEncoded();        SecretKeySpec cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);        // initialize the underlying cipher        cipher.init(opmode, cipherKey, ivSpec, random);    }
PBES2Core的engineInit在PBEParameterSpec的PBEParameterSpec不为null但又不是IvParameterSpec类型时抛出InvalidAlgorithmParameterException("Wrong parameter type: IV expected")异样;如果是encrypt或者wrap模式,如果不传iv则会主动生成,而不是encrypt或者wrap模式(个别是decrypt模式),则在iv为null时抛出InvalidAlgorithmParameterException("Missing parameter type: IV expected")异样

小结

IVGenerator定义了generateIV及includePlainIVInEncryptionResults办法,它有三个实现类,别离是NoOpIVGenerator、StringFixedIVGenerator、RandomIVGenerator;对于PBE算法,如果iv不传,在decrypt模式会抛出InvalidAlgorithmParameterException("Missing parameter type: IV expected")异样