/*
 * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package sun.security.provider;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.util.*;

import sun.security.pkcs.PKCS8Key;
import sun.security.pkcs.EncryptedPrivateKeyInfo;
import sun.security.x509.AlgorithmId;
import sun.security.util.ObjectIdentifier;
import sun.security.util.DerValue;

/**
 * This is an implementation of a Sun proprietary, exportable algorithm
 * intended for use when protecting (or recovering the cleartext version of)
 * sensitive keys.
 * This algorithm is not intended as a general purpose cipher.
 *
 * This is how the algorithm works for key protection:
 *
 * p - user password
 * s - random salt
 * X - xor key
 * P - to-be-protected key
 * Y - protected key
 * R - what gets stored in the keystore
 *
 * Step 1:
 * Take the user's password, append a random salt (of fixed size) to it,
 * and hash it: d1 = digest(p, s)
 * Store d1 in X.
 *
 * Step 2:
 * Take the user's password, append the digest result from the previous step,
 * and hash it: dn = digest(p, dn-1).
 * Store dn in X (append it to the previously stored digests).
 * Repeat this step until the length of X matches the length of the private key
 * P.
 *
 * Step 3:
 * XOR X and P, and store the result in Y: Y = X XOR P.
 *
 * Step 4:
 * Store s, Y, and digest(p, P) in the result buffer R:
 * R = s + Y + digest(p, P), where "+" denotes concatenation.
 * (NOTE: digest(p, P) is stored in the result buffer, so that when the key is
 * recovered, we can check if the recovered key indeed matches the original
 * key.) R is stored in the keystore.
 *
 * The protected key is recovered as follows:
 *
 * Step1 and Step2 are the same as above, except that the salt is not randomly
 * generated, but taken from the result R of step 4 (the first length(s)
 * bytes).
 *
 * Step 3 (XOR operation) yields the plaintext key.
 *
 * Then concatenate the password with the recovered key, and compare with the
 * last length(digest(p, P)) bytes of R. If they match, the recovered key is
 * indeed the same key as the original key.
 *
 * @author Jan Luehe
 *
 *
 * @see java.security.KeyStore
 * @see JavaKeyStore
 * @see KeyTool
 *
 * @since 1.2
 */

final class KeyProtector {

    private static final int SALT_LEN = 20; // the salt length
    private static final String DIGEST_ALG = "SHA";
    private static final int DIGEST_LEN = 20;

    // defined by JavaSoft
    private static final String KEY_PROTECTOR_OID = "1.3.6.1.4.1.42.2.17.1.1";

    // The password used for protecting/recovering keys passed through this
    // key protector. We store it as a byte array, so that we can digest it.
    private byte[] passwdBytes;

    private MessageDigest md;


    /**
     * Creates an instance of this class, and initializes it with the given
     * password.
     *
     * <p>The password is expected to be in printable ASCII.
     * Normal rules for good password selection apply: at least
     * seven characters, mixed case, with punctuation encouraged.
     * Phrases or words which are easily guessed, for example by
     * being found in dictionaries, are bad.
     */
    public KeyProtector(char[] password)
        throws NoSuchAlgorithmException
    {
        int i, j;

        if (password == null) {
           throw new IllegalArgumentException("password can't be null");
        }
        md = MessageDigest.getInstance(DIGEST_ALG);
        // Convert password to byte array, so that it can be digested
        passwdBytes = new byte[password.length * 2];
        for (i=0, j=0; i<password.length; i++) {
            passwdBytes[j++] = (byte)(password[i] >> 8);
            passwdBytes[j++] = (byte)password[i];
        }
    }

    /**
     * Ensures that the password bytes of this key protector are
     * set to zero when there are no more references to it.
     */
    protected void finalize() {
        if (passwdBytes != null) {
            Arrays.fill(passwdBytes, (byte)0x00);
            passwdBytes = null;
        }
    }

    /*
     * Protects the given plaintext key, using the password provided at
     * construction time.
     */
    public byte[] protect(Key key) throws KeyStoreException
    {
        int i;
        int numRounds;
        byte[] digest;
        int xorOffset; // offset in xorKey where next digest will be stored
        int encrKeyOffset = 0;

        if (key == null) {
            throw new IllegalArgumentException("plaintext key can't be null");
        }

        if (!"PKCS#8".equalsIgnoreCase(key.getFormat())) {
            throw new KeyStoreException(
                "Cannot get key bytes, not PKCS#8 encoded");
        }

        byte[] plainKey = key.getEncoded();
        if (plainKey == null) {
            throw new KeyStoreException(
                "Cannot get key bytes, encoding not supported");
        }

        // Determine the number of digest rounds
        numRounds = plainKey.length / DIGEST_LEN;
        if ((plainKey.length % DIGEST_LEN) != 0)
            numRounds++;

        // Create a random salt
        byte[] salt = new byte[SALT_LEN];
        SecureRandom random = new SecureRandom();
        random.nextBytes(salt);

        // Set up the byte array which will be XORed with "plainKey"
        byte[] xorKey = new byte[plainKey.length];

        // Compute the digests, and store them in "xorKey"
        for (i = 0, xorOffset = 0, digest = salt;
             i < numRounds;
             i++, xorOffset += DIGEST_LEN) {
            md.update(passwdBytes);
            md.update(digest);
            digest = md.digest();
            md.reset();
            // Copy the digest into "xorKey"
            if (i < numRounds - 1) {
                System.arraycopy(digest, 0, xorKey, xorOffset,
                                 digest.length);
            } else {
                System.arraycopy(digest, 0, xorKey, xorOffset,
                                 xorKey.length - xorOffset);
            }
        }

        // XOR "plainKey" with "xorKey", and store the result in "tmpKey"
        byte[] tmpKey = new byte[plainKey.length];
        for (i = 0; i < tmpKey.length; i++) {
            tmpKey[i] = (byte)(plainKey[i] ^ xorKey[i]);
        }

        // Store salt and "tmpKey" in "encrKey"
        byte[] encrKey = new byte[salt.length + tmpKey.length + DIGEST_LEN];
        System.arraycopy(salt, 0, encrKey, encrKeyOffset, salt.length);
        encrKeyOffset += salt.length;
        System.arraycopy(tmpKey, 0, encrKey, encrKeyOffset, tmpKey.length);
        encrKeyOffset += tmpKey.length;

        // Append digest(password, plainKey) as an integrity check to "encrKey"
        md.update(passwdBytes);
        Arrays.fill(passwdBytes, (byte)0x00);
        passwdBytes = null;
        md.update(plainKey);
        digest = md.digest();
        md.reset();
        System.arraycopy(digest, 0, encrKey, encrKeyOffset, digest.length);

        // wrap the protected private key in a PKCS#8-style
        // EncryptedPrivateKeyInfo, and returns its encoding
        AlgorithmId encrAlg;
        try {
            encrAlg = new AlgorithmId(new ObjectIdentifier(KEY_PROTECTOR_OID));
            return new EncryptedPrivateKeyInfo(encrAlg,encrKey).getEncoded();
        } catch (IOException ioe) {
            throw new KeyStoreException(ioe.getMessage());
        }
    }

    /*
     * Recovers the plaintext version of the given key (in protected format),
     * using the password provided at construction time.
     */
    public Key recover(EncryptedPrivateKeyInfo encrInfo)
        throws UnrecoverableKeyException
    {
        int i;
        byte[] digest;
        int numRounds;
        int xorOffset; // offset in xorKey where next digest will be stored
        int encrKeyLen; // the length of the encrpyted key

        // do we support the algorithm?
        AlgorithmId encrAlg = encrInfo.getAlgorithm();
        if (!(encrAlg.getOID().toString().equals(KEY_PROTECTOR_OID))) {
            throw new UnrecoverableKeyException("Unsupported key protection "
                                                + "algorithm");
        }

        byte[] protectedKey = encrInfo.getEncryptedData();

        /*
         * Get the salt associated with this key (the first SALT_LEN bytes of
         * <code>protectedKey</code>)
         */
        byte[] salt = new byte[SALT_LEN];
        System.arraycopy(protectedKey, 0, salt, 0, SALT_LEN);

        // Determine the number of digest rounds
        encrKeyLen = protectedKey.length - SALT_LEN - DIGEST_LEN;
        numRounds = encrKeyLen / DIGEST_LEN;
        if ((encrKeyLen % DIGEST_LEN) != 0) numRounds++;

        // Get the encrypted key portion and store it in "encrKey"
        byte[] encrKey = new byte[encrKeyLen];
        System.arraycopy(protectedKey, SALT_LEN, encrKey, 0, encrKeyLen);

        // Set up the byte array which will be XORed with "encrKey"
        byte[] xorKey = new byte[encrKey.length];

        // Compute the digests, and store them in "xorKey"
        for (i = 0, xorOffset = 0, digest = salt;
             i < numRounds;
             i++, xorOffset += DIGEST_LEN) {
            md.update(passwdBytes);
            md.update(digest);
            digest = md.digest();
            md.reset();
            // Copy the digest into "xorKey"
            if (i < numRounds - 1) {
                System.arraycopy(digest, 0, xorKey, xorOffset,
                                 digest.length);
            } else {
                System.arraycopy(digest, 0, xorKey, xorOffset,
                                 xorKey.length - xorOffset);
            }
        }

        // XOR "encrKey" with "xorKey", and store the result in "plainKey"
        byte[] plainKey = new byte[encrKey.length];
        for (i = 0; i < plainKey.length; i++) {
            plainKey[i] = (byte)(encrKey[i] ^ xorKey[i]);
        }

        /*
         * Check the integrity of the recovered key by concatenating it with
         * the password, digesting the concatenation, and comparing the
         * result of the digest operation with the digest provided at the end
         * of <code>protectedKey</code>. If the two digest values are
         * different, throw an exception.
         */
        md.update(passwdBytes);
        Arrays.fill(passwdBytes, (byte)0x00);
        passwdBytes = null;
        md.update(plainKey);
        digest = md.digest();
        md.reset();
        for (i = 0; i < digest.length; i++) {
            if (digest[i] != protectedKey[SALT_LEN + encrKeyLen + i]) {
                throw new UnrecoverableKeyException("Cannot recover key");
            }
        }

        // The parseKey() method of PKCS8Key parses the key
        // algorithm and instantiates the appropriate key factory,
        // which in turn parses the key material.
        try {
            return PKCS8Key.parseKey(new DerValue(plainKey));
        } catch (IOException ioe) {
            throw new UnrecoverableKeyException(ioe.getMessage());
        }
    }
}
