|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.crypto.provider; |
|
|
|
import java.util.Arrays; |
|
import java.nio.ByteBuffer; |
|
|
|
import javax.crypto.MacSpi; |
|
import javax.crypto.SecretKey; |
|
import javax.crypto.spec.SecretKeySpec; |
|
import javax.crypto.spec.PBEKeySpec; |
|
import javax.crypto.spec.PBEParameterSpec; |
|
import java.security.*; |
|
import java.security.spec.*; |
|
|
|
|
|
|
|
|
|
*/ |
|
abstract class PBMAC1Core extends HmacCore { |
|
|
|
// NOTE: this class inherits the Cloneable interface from HmacCore |
|
|
|
private final String kdfAlgo; |
|
private final String hashAlgo; |
|
private final int blockLength; |
|
|
|
|
|
|
|
|
|
*/ |
|
PBMAC1Core(String kdfAlgo, String hashAlgo, int blockLength) |
|
throws NoSuchAlgorithmException { |
|
super(hashAlgo, blockLength); |
|
this.kdfAlgo = kdfAlgo; |
|
this.hashAlgo = hashAlgo; |
|
this.blockLength = blockLength; |
|
} |
|
|
|
private static PBKDF2Core getKDFImpl(String algo) { |
|
PBKDF2Core kdf = null; |
|
switch(algo) { |
|
case "HmacSHA1": |
|
kdf = new PBKDF2Core.HmacSHA1(); |
|
break; |
|
case "HmacSHA224": |
|
kdf = new PBKDF2Core.HmacSHA224(); |
|
break; |
|
case "HmacSHA256": |
|
kdf = new PBKDF2Core.HmacSHA256(); |
|
break; |
|
case "HmacSHA384": |
|
kdf = new PBKDF2Core.HmacSHA384(); |
|
break; |
|
case "HmacSHA512": |
|
kdf = new PBKDF2Core.HmacSHA512(); |
|
break; |
|
default: |
|
throw new ProviderException( |
|
"No MAC implementation for " + algo); |
|
} |
|
return kdf; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void engineInit(Key key, AlgorithmParameterSpec params) |
|
throws InvalidKeyException, InvalidAlgorithmParameterException { |
|
char[] passwdChars; |
|
byte[] salt = null; |
|
int iCount = 0; |
|
if (key instanceof javax.crypto.interfaces.PBEKey) { |
|
javax.crypto.interfaces.PBEKey pbeKey = |
|
(javax.crypto.interfaces.PBEKey) key; |
|
passwdChars = pbeKey.getPassword(); |
|
salt = pbeKey.getSalt(); |
|
iCount = pbeKey.getIterationCount(); |
|
} else if (key instanceof SecretKey) { |
|
byte[] passwdBytes; |
|
if (!(key.getAlgorithm().regionMatches(true, 0, "PBE", 0, 3)) || |
|
(passwdBytes = key.getEncoded()) == null) { |
|
throw new InvalidKeyException("Missing password"); |
|
} |
|
passwdChars = new char[passwdBytes.length]; |
|
for (int i=0; i<passwdChars.length; i++) { |
|
passwdChars[i] = (char) (passwdBytes[i] & 0x7f); |
|
} |
|
Arrays.fill(passwdBytes, (byte)0x00); |
|
} else { |
|
throw new InvalidKeyException("SecretKey of PBE type required"); |
|
} |
|
|
|
PBEKeySpec pbeSpec; |
|
try { |
|
if (params == null) { |
|
// should not auto-generate default values since current |
|
// javax.crypto.Mac api does not have any method for caller to |
|
|
|
if ((salt == null) || (iCount == 0)) { |
|
throw new InvalidAlgorithmParameterException |
|
("PBEParameterSpec required for salt and iteration count"); |
|
} |
|
} else if (!(params instanceof PBEParameterSpec)) { |
|
throw new InvalidAlgorithmParameterException |
|
("PBEParameterSpec type required"); |
|
} else { |
|
PBEParameterSpec pbeParams = (PBEParameterSpec) params; |
|
|
|
if (salt != null) { |
|
if (!Arrays.equals(salt, pbeParams.getSalt())) { |
|
throw new InvalidAlgorithmParameterException |
|
("Inconsistent value of salt between key and params"); |
|
} |
|
} else { |
|
salt = pbeParams.getSalt(); |
|
} |
|
if (iCount != 0) { |
|
if (iCount != pbeParams.getIterationCount()) { |
|
throw new InvalidAlgorithmParameterException |
|
("Different iteration count between key and params"); |
|
} |
|
} else { |
|
iCount = pbeParams.getIterationCount(); |
|
} |
|
} |
|
// For security purpose, we need to enforce a minimum length |
|
// for salt; just require the minimum salt length to be 8-byte |
|
|
|
if (salt.length < 8) { |
|
throw new InvalidAlgorithmParameterException |
|
("Salt must be at least 8 bytes long"); |
|
} |
|
if (iCount <= 0) { |
|
throw new InvalidAlgorithmParameterException |
|
("IterationCount must be a positive number"); |
|
} |
|
|
|
pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, blockLength); |
|
// password char[] was cloned in PBEKeySpec constructor, |
|
// so we can zero it out here |
|
} finally { |
|
Arrays.fill(passwdChars, '\0'); |
|
} |
|
|
|
PBKDF2KeyImpl s = null; |
|
PBKDF2Core kdf = getKDFImpl(kdfAlgo); |
|
byte[] derivedKey; |
|
try { |
|
s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec); |
|
derivedKey = s.getEncoded(); |
|
} catch (InvalidKeySpecException ikse) { |
|
InvalidKeyException ike = |
|
new InvalidKeyException("Cannot construct PBE key"); |
|
ike.initCause(ikse); |
|
throw ike; |
|
} finally { |
|
pbeSpec.clearPassword(); |
|
if (s != null) { |
|
s.clearPassword(); |
|
} |
|
} |
|
SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo); |
|
Arrays.fill(derivedKey, (byte)0); |
|
|
|
super.engineInit(cipherKey, null); |
|
} |
|
|
|
public static final class HmacSHA1 extends PBMAC1Core { |
|
public HmacSHA1() throws NoSuchAlgorithmException { |
|
super("HmacSHA1", "SHA1", 64); |
|
} |
|
} |
|
|
|
public static final class HmacSHA224 extends PBMAC1Core { |
|
public HmacSHA224() throws NoSuchAlgorithmException { |
|
super("HmacSHA224", "SHA-224", 64); |
|
} |
|
} |
|
|
|
public static final class HmacSHA256 extends PBMAC1Core { |
|
public HmacSHA256() throws NoSuchAlgorithmException { |
|
super("HmacSHA256", "SHA-256", 64); |
|
} |
|
} |
|
|
|
public static final class HmacSHA384 extends PBMAC1Core { |
|
public HmacSHA384() throws NoSuchAlgorithmException { |
|
super("HmacSHA384", "SHA-384", 128); |
|
} |
|
} |
|
|
|
public static final class HmacSHA512 extends PBMAC1Core { |
|
public HmacSHA512() throws NoSuchAlgorithmException { |
|
super("HmacSHA512", "SHA-512", 128); |
|
} |
|
} |
|
} |