序
本文主要研究一下jasypt的IVGenerator
IVGenerator
org/jasypt/salt/IVGenerator.java
/**
*
* Common interface for all IV generators which can be applied in digest
* or encryption operations.
*
*
* Every implementation of this interface must be thread-safe.
*
*
* @since 1.9.3
*
* @author Alex Scal
*
*/
public interface IVGenerator {
/**
*
* This method will be called for requesting the generation of a new
* IV of the specified length.
*
*
* @param length the requested length for the IV.
* @return the generated IV.
*/
byte[] generateIV(int length);
/**
*
* 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.
*
*
* 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.
*
*
* @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 FixedStringIVGenerator using
* the default charset.
*
* @param iv the specified salt.
*/
public StringFixedIVGenerator(final String iv) {
this(iv, null);
}
/**
* Creates a new instance of FixedStringIVGenerator
*
* @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 RandomIVGenerator using the
* default secure random number generation algorithm.
*/
public RandomIVGenerator() {
this(GENERATOR_ALGORITHM);
}
/**
* Creates a new instance of RandomIVGenerator 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")异常