368 lines · 12.7 KB · Java
RawDownload
/* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.crypto.provider; import java.util.Arrays; import java.security.*;import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*;import javax.crypto.spec.SecretKeySpec; import sun.security.internal.spec.TlsPrfParameterSpec; /** * KeyGenerator implementation for the TLS PRF function. * <p> * This class duplicates the HMAC functionality (RFC 2104) with * performance optimizations (e.g. XOR'ing keys with padding doesn't * need to be redone for each HMAC operation). * * @author  Andreas Sterbenz * @since   1.6 */abstract class TlsPrfGenerator extends KeyGeneratorSpi {     // magic constants and utility functions, also used by other files    // in this package     private final static byte[] B0 = new byte[0];     final static byte[] LABEL_MASTER_SECRET = // "master secret"        { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };     final static byte[] LABEL_KEY_EXPANSION = // "key expansion"        { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };     final static byte[] LABEL_CLIENT_WRITE_KEY = // "client write key"        { 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32,          107, 101, 121 };     final static byte[] LABEL_SERVER_WRITE_KEY = // "server write key"        { 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32,          107, 101, 121 };     final static byte[] LABEL_IV_BLOCK = // "IV block"        { 73, 86, 32, 98, 108, 111, 99, 107 };     /*     * TLS HMAC "inner" and "outer" padding.  This isn't a function     * of the digest algorithm.     */    private static final byte[] HMAC_ipad64  = genPad((byte)0x36, 64);    private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);    private static final byte[] HMAC_opad64  = genPad((byte)0x5c, 64);    private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);     // SSL3 magic mix constants ("A", "BB", "CCC", ...)    final static byte[][] SSL3_CONST = genConst();     static byte[] genPad(byte b, int count) {        byte[] padding = new byte[count];        Arrays.fill(padding, b);        return padding;    }     static byte[] concat(byte[] b1, byte[] b2) {        int n1 = b1.length;        int n2 = b2.length;        byte[] b = new byte[n1 + n2];        System.arraycopy(b1, 0, b, 0, n1);        System.arraycopy(b2, 0, b, n1, n2);        return b;    }     private static byte[][] genConst() {        int n = 10;        byte[][] arr = new byte[n][];        for (int i = 0; i < n; i++) {            byte[] b = new byte[i + 1];            Arrays.fill(b, (byte)('A' + i));            arr[i] = b;        }        return arr;    }     // PRF implementation     private final static String MSG = "TlsPrfGenerator must be "        + "initialized using a TlsPrfParameterSpec";     private TlsPrfParameterSpec spec;     public TlsPrfGenerator() {    }     protected void engineInit(SecureRandom random) {        throw new InvalidParameterException(MSG);    }     protected void engineInit(AlgorithmParameterSpec params,            SecureRandom random) throws InvalidAlgorithmParameterException {        if (params instanceof TlsPrfParameterSpec == false) {            throw new InvalidAlgorithmParameterException(MSG);        }        this.spec = (TlsPrfParameterSpec)params;        SecretKey key = spec.getSecret();        if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {            throw new InvalidAlgorithmParameterException(                "Key encoding format must be RAW");        }    }     protected void engineInit(int keysize, SecureRandom random) {        throw new InvalidParameterException(MSG);    }     SecretKey engineGenerateKey0(boolean tls12) {        if (spec == null) {            throw new IllegalStateException(                "TlsPrfGenerator must be initialized");        }        SecretKey key = spec.getSecret();        byte[] secret = (key == null) ? null : key.getEncoded();        try {            byte[] labelBytes = spec.getLabel().getBytes("UTF8");            int n = spec.getOutputLength();            byte[] prfBytes = (tls12 ?                doTLS12PRF(secret, labelBytes, spec.getSeed(), n,                    spec.getPRFHashAlg(), spec.getPRFHashLength(),                    spec.getPRFBlockSize()) :                doTLS10PRF(secret, labelBytes, spec.getSeed(), n));            return new SecretKeySpec(prfBytes, "TlsPrf");        } catch (GeneralSecurityException e) {            throw new ProviderException("Could not generate PRF", e);        } catch (java.io.UnsupportedEncodingException e) {            throw new ProviderException("Could not generate PRF", e);        }    }     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,            byte[] seed, int outputLength,            String prfHash, int prfHashLength, int prfBlockSize)            throws NoSuchAlgorithmException, DigestException {        if (prfHash == null) {            throw new NoSuchAlgorithmException("Unspecified PRF algorithm");        }        MessageDigest prfMD = MessageDigest.getInstance(prfHash);        return doTLS12PRF(secret, labelBytes, seed, outputLength,            prfMD, prfHashLength, prfBlockSize);    }     static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,            byte[] seed, int outputLength,            MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)            throws DigestException {         if (secret == null) {            secret = B0;        }         // If we have a long secret, digest it first.        if (secret.length > mdPRFBlockSize) {            secret = mdPRF.digest(secret);        }         byte[] output = new byte[outputLength];        byte [] ipad;        byte [] opad;         switch (mdPRFBlockSize) {        case 64:            ipad = HMAC_ipad64.clone();            opad = HMAC_opad64.clone();            break;        case 128:            ipad = HMAC_ipad128.clone();            opad = HMAC_opad128.clone();            break;        default:            throw new DigestException("Unexpected block size.");        }         // P_HASH(Secret, label + seed)        expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,            seed, output, ipad, opad);         return output;    }     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,            byte[] seed, int outputLength) throws NoSuchAlgorithmException,            DigestException {        MessageDigest md5 = MessageDigest.getInstance("MD5");        MessageDigest sha = MessageDigest.getInstance("SHA1");        return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);    }     static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,            byte[] seed, int outputLength, MessageDigest md5,            MessageDigest sha) throws DigestException {        /*         * Split the secret into two halves S1 and S2 of same length.         * S1 is taken from the first half of the secret, S2 from the         * second half.         * Their length is created by rounding up the length of the         * overall secret divided by two; thus, if the original secret         * is an odd number of bytes long, the last byte of S1 will be         * the same as the first byte of S2.         *         * Note: Instead of creating S1 and S2, we determine the offset into         * the overall secret where S2 starts.         */         if (secret == null) {            secret = B0;        }        int off = secret.length >> 1;        int seclen = off + (secret.length & 1);         byte[] output = new byte[outputLength];         // P_MD5(S1, label + seed)        expand(md5, 16, secret, 0, seclen, labelBytes, seed, output,            HMAC_ipad64.clone(), HMAC_opad64.clone());         // P_SHA-1(S2, label + seed)        expand(sha, 20, secret, off, seclen, labelBytes, seed, output,            HMAC_ipad64.clone(), HMAC_opad64.clone());         return output;    }     /*     * @param digest the MessageDigest to produce the HMAC     * @param hmacSize the HMAC size     * @param secret the secret     * @param secOff the offset into the secret     * @param secLen the secret length     * @param label the label     * @param seed the seed     * @param output the output array     */    private static void expand(MessageDigest digest, int hmacSize,            byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,            byte[] output, byte[] pad1, byte[] pad2) throws DigestException {        /*         * modify the padding used, by XORing the key into our copy of that         * padding.  That's to avoid doing that for each HMAC computation.         */        for (int i = 0; i < secLen; i++) {            pad1[i] ^= secret[i + secOff];            pad2[i] ^= secret[i + secOff];        }         byte[] tmp = new byte[hmacSize];        byte[] aBytes = null;         /*         * compute:         *         *     P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +         *                            HMAC_hash(secret, A(2) + seed) +         *                            HMAC_hash(secret, A(3) + seed) + ...         * A() is defined as:         *         *     A(0) = seed         *     A(i) = HMAC_hash(secret, A(i-1))         */        int remaining = output.length;        int ofs = 0;        while (remaining > 0) {            /*             * compute A() ...             */            // inner digest            digest.update(pad1);            if (aBytes == null) {                digest.update(label);                digest.update(seed);            } else {                digest.update(aBytes);            }            digest.digest(tmp, 0, hmacSize);             // outer digest            digest.update(pad2);            digest.update(tmp);            if (aBytes == null) {                aBytes = new byte[hmacSize];            }            digest.digest(aBytes, 0, hmacSize);             /*             * compute HMAC_hash() ...             */            // inner digest            digest.update(pad1);            digest.update(aBytes);            digest.update(label);            digest.update(seed);            digest.digest(tmp, 0, hmacSize);             // outer digest            digest.update(pad2);            digest.update(tmp);            digest.digest(tmp, 0, hmacSize);             int k = Math.min(hmacSize, remaining);            for (int i = 0; i < k; i++) {                output[ofs++] ^= tmp[i];            }            remaining -= k;        }    }     /**     * A KeyGenerator implementation that supports TLS 1.2.     * <p>     * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF     * calculations.  As of 2010, there is no PKCS11-level support for TLS     * 1.2 PRF calculations, and no known OS's have an internal variant     * we could use.  Therefore for TLS 1.2, we are updating JSSE to request     * a different provider algorithm:  "SunTls12Prf".  If we reused the     * name "SunTlsPrf", the PKCS11 provider would need be updated to     * fail correctly when presented with the wrong version number     * (via Provider.Service.supportsParameters()), and add the     * appropriate supportsParamters() checks into KeyGenerators (not     * currently there).     */    static public class V12 extends TlsPrfGenerator {        protected SecretKey engineGenerateKey() {            return engineGenerateKey0(true);        }    }     /**     * A KeyGenerator implementation that supports TLS 1.0/1.1.     */    static public class V10 extends TlsPrfGenerator {        protected SecretKey engineGenerateKey() {            return engineGenerateKey0(false);        }    }}