| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
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');  | 
 | 
        }  | 
 | 
 | 
 | 
        SecretKey s;  | 
 | 
        PBKDF2Core kdf = getKDFImpl(kdfAlgo);  | 
 | 
        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();  | 
 | 
        SecretKey cipherKey = new SecretKeySpec(derivedKey, kdfAlgo);  | 
 | 
 | 
 | 
        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); | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |