Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]
    1   /*
    2    * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.crypto.provider;
   27   
   28   import java.util.Arrays;
   29   
   30   import java.security;
   31   import java.security.spec.AlgorithmParameterSpec;
   32   
   33   import javax.crypto;
   34   import javax.crypto.spec.SecretKeySpec;
   35   
   36   import sun.security.internal.spec.TlsPrfParameterSpec;
   37   
   38   /**
   39    * KeyGenerator implementation for the TLS PRF function.
   40    * <p>
   41    * This class duplicates the HMAC functionality (RFC 2104) with
   42    * performance optimizations (e.g. XOR'ing keys with padding doesn't
   43    * need to be redone for each HMAC operation).
   44    *
   45    * @author  Andreas Sterbenz
   46    * @since   1.6
   47    */
   48   abstract class TlsPrfGenerator extends KeyGeneratorSpi {
   49   
   50       // magic constants and utility functions, also used by other files
   51       // in this package
   52   
   53       private final static byte[] B0 = new byte[0];
   54   
   55       final static byte[] LABEL_MASTER_SECRET = // "master secret"
   56           { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
   57   
   58       final static byte[] LABEL_KEY_EXPANSION = // "key expansion"
   59           { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };
   60   
   61       final static byte[] LABEL_CLIENT_WRITE_KEY = // "client write key"
   62           { 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32,
   63             107, 101, 121 };
   64   
   65       final static byte[] LABEL_SERVER_WRITE_KEY = // "server write key"
   66           { 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32,
   67             107, 101, 121 };
   68   
   69       final static byte[] LABEL_IV_BLOCK = // "IV block"
   70           { 73, 86, 32, 98, 108, 111, 99, 107 };
   71   
   72       /*
   73        * TLS HMAC "inner" and "outer" padding.  This isn't a function
   74        * of the digest algorithm.
   75        */
   76       private static final byte[] HMAC_ipad64  = genPad((byte)0x36, 64);
   77       private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128);
   78       private static final byte[] HMAC_opad64  = genPad((byte)0x5c, 64);
   79       private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128);
   80   
   81       // SSL3 magic mix constants ("A", "BB", "CCC", ...)
   82       final static byte[][] SSL3_CONST = genConst();
   83   
   84       static byte[] genPad(byte b, int count) {
   85           byte[] padding = new byte[count];
   86           Arrays.fill(padding, b);
   87           return padding;
   88       }
   89   
   90       static byte[] concat(byte[] b1, byte[] b2) {
   91           int n1 = b1.length;
   92           int n2 = b2.length;
   93           byte[] b = new byte[n1 + n2];
   94           System.arraycopy(b1, 0, b, 0, n1);
   95           System.arraycopy(b2, 0, b, n1, n2);
   96           return b;
   97       }
   98   
   99       private static byte[][] genConst() {
  100           int n = 10;
  101           byte[][] arr = new byte[n][];
  102           for (int i = 0; i < n; i++) {
  103               byte[] b = new byte[i + 1];
  104               Arrays.fill(b, (byte)('A' + i));
  105               arr[i] = b;
  106           }
  107           return arr;
  108       }
  109   
  110       // PRF implementation
  111   
  112       private final static String MSG = "TlsPrfGenerator must be "
  113           + "initialized using a TlsPrfParameterSpec";
  114   
  115       private TlsPrfParameterSpec spec;
  116   
  117       public TlsPrfGenerator() {
  118       }
  119   
  120       protected void engineInit(SecureRandom random) {
  121           throw new InvalidParameterException(MSG);
  122       }
  123   
  124       protected void engineInit(AlgorithmParameterSpec params,
  125               SecureRandom random) throws InvalidAlgorithmParameterException {
  126           if (params instanceof TlsPrfParameterSpec == false) {
  127               throw new InvalidAlgorithmParameterException(MSG);
  128           }
  129           this.spec = (TlsPrfParameterSpec)params;
  130           SecretKey key = spec.getSecret();
  131           if ((key != null) && ("RAW".equals(key.getFormat()) == false)) {
  132               throw new InvalidAlgorithmParameterException(
  133                   "Key encoding format must be RAW");
  134           }
  135       }
  136   
  137       protected void engineInit(int keysize, SecureRandom random) {
  138           throw new InvalidParameterException(MSG);
  139       }
  140   
  141       SecretKey engineGenerateKey0(boolean tls12) {
  142           if (spec == null) {
  143               throw new IllegalStateException(
  144                   "TlsPrfGenerator must be initialized");
  145           }
  146           SecretKey key = spec.getSecret();
  147           byte[] secret = (key == null) ? null : key.getEncoded();
  148           try {
  149               byte[] labelBytes = spec.getLabel().getBytes("UTF8");
  150               int n = spec.getOutputLength();
  151               byte[] prfBytes = (tls12 ?
  152                   doTLS12PRF(secret, labelBytes, spec.getSeed(), n,
  153                       spec.getPRFHashAlg(), spec.getPRFHashLength(),
  154                       spec.getPRFBlockSize()) :
  155                   doTLS10PRF(secret, labelBytes, spec.getSeed(), n));
  156               return new SecretKeySpec(prfBytes, "TlsPrf");
  157           } catch (GeneralSecurityException e) {
  158               throw new ProviderException("Could not generate PRF", e);
  159           } catch (java.io.UnsupportedEncodingException e) {
  160               throw new ProviderException("Could not generate PRF", e);
  161           }
  162       }
  163   
  164       static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
  165               byte[] seed, int outputLength,
  166               String prfHash, int prfHashLength, int prfBlockSize)
  167               throws NoSuchAlgorithmException, DigestException {
  168           if (prfHash == null) {
  169               throw new NoSuchAlgorithmException("Unspecified PRF algorithm");
  170           }
  171           MessageDigest prfMD = MessageDigest.getInstance(prfHash);
  172           return doTLS12PRF(secret, labelBytes, seed, outputLength,
  173               prfMD, prfHashLength, prfBlockSize);
  174       }
  175   
  176       static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes,
  177               byte[] seed, int outputLength,
  178               MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize)
  179               throws DigestException {
  180   
  181           if (secret == null) {
  182               secret = B0;
  183           }
  184   
  185           // If we have a long secret, digest it first.
  186           if (secret.length > mdPRFBlockSize) {
  187               secret = mdPRF.digest(secret);
  188           }
  189   
  190           byte[] output = new byte[outputLength];
  191           byte [] ipad;
  192           byte [] opad;
  193   
  194           switch (mdPRFBlockSize) {
  195           case 64:
  196               ipad = HMAC_ipad64.clone();
  197               opad = HMAC_opad64.clone();
  198               break;
  199           case 128:
  200               ipad = HMAC_ipad128.clone();
  201               opad = HMAC_opad128.clone();
  202               break;
  203           default:
  204               throw new DigestException("Unexpected block size.");
  205           }
  206   
  207           // P_HASH(Secret, label + seed)
  208           expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes,
  209               seed, output, ipad, opad);
  210   
  211           return output;
  212       }
  213   
  214       static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
  215               byte[] seed, int outputLength) throws NoSuchAlgorithmException,
  216               DigestException {
  217           MessageDigest md5 = MessageDigest.getInstance("MD5");
  218           MessageDigest sha = MessageDigest.getInstance("SHA1");
  219           return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha);
  220       }
  221   
  222       static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes,
  223               byte[] seed, int outputLength, MessageDigest md5,
  224               MessageDigest sha) throws DigestException {
  225           /*
  226            * Split the secret into two halves S1 and S2 of same length.
  227            * S1 is taken from the first half of the secret, S2 from the
  228            * second half.
  229            * Their length is created by rounding up the length of the
  230            * overall secret divided by two; thus, if the original secret
  231            * is an odd number of bytes long, the last byte of S1 will be
  232            * the same as the first byte of S2.
  233            *
  234            * Note: Instead of creating S1 and S2, we determine the offset into
  235            * the overall secret where S2 starts.
  236            */
  237   
  238           if (secret == null) {
  239               secret = B0;
  240           }
  241           int off = secret.length >> 1;
  242           int seclen = off + (secret.length & 1);
  243   
  244           byte[] output = new byte[outputLength];
  245   
  246           // P_MD5(S1, label + seed)
  247           expand(md5, 16, secret, 0, seclen, labelBytes, seed, output,
  248               HMAC_ipad64.clone(), HMAC_opad64.clone());
  249   
  250           // P_SHA-1(S2, label + seed)
  251           expand(sha, 20, secret, off, seclen, labelBytes, seed, output,
  252               HMAC_ipad64.clone(), HMAC_opad64.clone());
  253   
  254           return output;
  255       }
  256   
  257       /*
  258        * @param digest the MessageDigest to produce the HMAC
  259        * @param hmacSize the HMAC size
  260        * @param secret the secret
  261        * @param secOff the offset into the secret
  262        * @param secLen the secret length
  263        * @param label the label
  264        * @param seed the seed
  265        * @param output the output array
  266        */
  267       private static void expand(MessageDigest digest, int hmacSize,
  268               byte[] secret, int secOff, int secLen, byte[] label, byte[] seed,
  269               byte[] output, byte[] pad1, byte[] pad2) throws DigestException {
  270           /*
  271            * modify the padding used, by XORing the key into our copy of that
  272            * padding.  That's to avoid doing that for each HMAC computation.
  273            */
  274           for (int i = 0; i < secLen; i++) {
  275               pad1[i] ^= secret[i + secOff];
  276               pad2[i] ^= secret[i + secOff];
  277           }
  278   
  279           byte[] tmp = new byte[hmacSize];
  280           byte[] aBytes = null;
  281   
  282           /*
  283            * compute:
  284            *
  285            *     P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
  286            *                            HMAC_hash(secret, A(2) + seed) +
  287            *                            HMAC_hash(secret, A(3) + seed) + ...
  288            * A() is defined as:
  289            *
  290            *     A(0) = seed
  291            *     A(i) = HMAC_hash(secret, A(i-1))
  292            */
  293           int remaining = output.length;
  294           int ofs = 0;
  295           while (remaining > 0) {
  296               /*
  297                * compute A() ...
  298                */
  299               // inner digest
  300               digest.update(pad1);
  301               if (aBytes == null) {
  302                   digest.update(label);
  303                   digest.update(seed);
  304               } else {
  305                   digest.update(aBytes);
  306               }
  307               digest.digest(tmp, 0, hmacSize);
  308   
  309               // outer digest
  310               digest.update(pad2);
  311               digest.update(tmp);
  312               if (aBytes == null) {
  313                   aBytes = new byte[hmacSize];
  314               }
  315               digest.digest(aBytes, 0, hmacSize);
  316   
  317               /*
  318                * compute HMAC_hash() ...
  319                */
  320               // inner digest
  321               digest.update(pad1);
  322               digest.update(aBytes);
  323               digest.update(label);
  324               digest.update(seed);
  325               digest.digest(tmp, 0, hmacSize);
  326   
  327               // outer digest
  328               digest.update(pad2);
  329               digest.update(tmp);
  330               digest.digest(tmp, 0, hmacSize);
  331   
  332               int k = Math.min(hmacSize, remaining);
  333               for (int i = 0; i < k; i++) {
  334                   output[ofs++] ^= tmp[i];
  335               }
  336               remaining -= k;
  337           }
  338       }
  339   
  340       /**
  341        * A KeyGenerator implementation that supports TLS 1.2.
  342        * <p>
  343        * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
  344        * calculations.  As of 2010, there is no PKCS11-level support for TLS
  345        * 1.2 PRF calculations, and no known OS's have an internal variant
  346        * we could use.  Therefore for TLS 1.2, we are updating JSSE to request
  347        * a different provider algorithm:  "SunTls12Prf".  If we reused the
  348        * name "SunTlsPrf", the PKCS11 provider would need be updated to
  349        * fail correctly when presented with the wrong version number
  350        * (via Provider.Service.supportsParameters()), and add the
  351        * appropriate supportsParamters() checks into KeyGenerators (not
  352        * currently there).
  353        */
  354       static public class V12 extends TlsPrfGenerator {
  355           protected SecretKey engineGenerateKey() {
  356               return engineGenerateKey0(true);
  357           }
  358       }
  359   
  360       /**
  361        * A KeyGenerator implementation that supports TLS 1.0/1.1.
  362        */
  363       static public class V10 extends TlsPrfGenerator {
  364           protected SecretKey engineGenerateKey() {
  365               return engineGenerateKey0(false);
  366           }
  367       }
  368   }

Save This Page
Home » openjdk-7 » com.sun.crypto » provider » [javadoc | source]