序
本文次要钻研一下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")异样