jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java
changeset 37796 256c45c4af5d
child 37895 f59fdd7fb4fb
equal deleted inserted replaced
37795:c5dc5ab60139 37796:256c45c4af5d
       
     1 /*
       
     2  * Copyright (c) 2016, 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 sun.security.provider;
       
    27 
       
    28 import javax.crypto.Mac;
       
    29 import javax.crypto.spec.SecretKeySpec;
       
    30 import java.io.IOException;
       
    31 import java.security.InvalidKeyException;
       
    32 import java.security.NoSuchAlgorithmException;
       
    33 import java.security.NoSuchProviderException;
       
    34 import java.security.SecureRandomParameters;
       
    35 import java.util.Arrays;
       
    36 
       
    37 public class HmacDrbg extends AbstractHashDrbg {
       
    38 
       
    39     private static final long serialVersionUID = 9L;
       
    40 
       
    41     private transient Mac mac;
       
    42 
       
    43     private String macAlg;
       
    44 
       
    45     private transient byte[] v;
       
    46     private transient byte[] k;
       
    47 
       
    48     public HmacDrbg(SecureRandomParameters params) {
       
    49         mechName = "HMAC_DRBG";
       
    50         configure(params);
       
    51     }
       
    52 
       
    53     private void status() {
       
    54         if (debug != null) {
       
    55             debug.println(this, "V = " + hex(v));
       
    56             debug.println(this, "Key = " + hex(k));
       
    57             debug.println(this, "reseed counter = " + reseedCounter);
       
    58         }
       
    59     }
       
    60 
       
    61     // 800-90Ar1 10.1.2.2: HMAC_DRBG Update Process
       
    62     private void update(byte[]... inputs) {
       
    63         try {
       
    64             // Step 1. K = HMAC (K, V || 0x00 || provided_data).
       
    65             mac.init(new SecretKeySpec(k, macAlg));
       
    66             mac.update(v);
       
    67             mac.update((byte) 0);
       
    68             for (byte[] input: inputs) {
       
    69                 mac.update(input);
       
    70             }
       
    71             k = mac.doFinal();
       
    72 
       
    73             // Step 2. V = HMAC (K, V).
       
    74             mac.init(new SecretKeySpec(k, macAlg));
       
    75             v = mac.doFinal(v);
       
    76 
       
    77             if (inputs.length != 0) {
       
    78                 // Step 4. K = HMAC (K, V || 0x01 || provided_data).
       
    79                 mac.update(v);
       
    80                 mac.update((byte) 1);
       
    81                 for (byte[] input: inputs) {
       
    82                     mac.update(input);
       
    83                 }
       
    84                 k = mac.doFinal();
       
    85 
       
    86                 // Step 5. V=HMAC(K,V).
       
    87                 mac.init(new SecretKeySpec(k, macAlg));
       
    88                 v = mac.doFinal(v);
       
    89             } // else Step 3
       
    90 
       
    91             // Step 6. Return
       
    92         } catch (InvalidKeyException e) {
       
    93             throw new InternalError(e);
       
    94         }
       
    95     }
       
    96 
       
    97     /**
       
    98      * This call, used by the constructors, instantiates the digest.
       
    99      */
       
   100     @Override
       
   101     protected void initEngine() {
       
   102         macAlg = "HmacSHA" + algorithm.substring(4);
       
   103         try {
       
   104             mac = Mac.getInstance(macAlg, "SunJCE");
       
   105         } catch (NoSuchProviderException | NoSuchAlgorithmException e) {
       
   106             // Fallback to any available.
       
   107             try {
       
   108                 mac = Mac.getInstance(macAlg);
       
   109             } catch (NoSuchAlgorithmException exc) {
       
   110                 throw new InternalError(
       
   111                     "internal error: " + macAlg + " not available.", exc);
       
   112             }
       
   113         }
       
   114     }
       
   115 
       
   116     // This method is used by both instantiation and reseeding.
       
   117     @Override
       
   118     protected final void hashReseedInternal(byte[] input) {
       
   119 
       
   120         // 800-90Ar1 10.1.2.3: Instantiate Process.
       
   121         // 800-90Ar1 10.1.2.4: Reseed Process.
       
   122         if (v == null) {
       
   123             k = new byte[outLen];
       
   124             v = new byte[outLen];
       
   125             Arrays.fill(v, (byte) 1);
       
   126         }
       
   127 
       
   128         // Step 2: HMAC_DRBG_Update
       
   129         update(input);
       
   130 
       
   131         // Step 3: reseed_counter = 1.
       
   132         reseedCounter = 1;
       
   133         //status();
       
   134 
       
   135         // Step 4: Return
       
   136     }
       
   137 
       
   138     /**
       
   139      * Generates a user-specified number of random bytes.
       
   140      *
       
   141      * @param result the array to be filled in with random bytes.
       
   142      */
       
   143     @Override
       
   144     public synchronized void generateAlgorithm(
       
   145             byte[] result, byte[] additionalInput) {
       
   146 
       
   147         if (debug != null) {
       
   148             debug.println(this, "generateAlgorithm");
       
   149         }
       
   150 
       
   151         // 800-90Ar1 10.1.2.5: HMAC_DRBG_Generate Process
       
   152 
       
   153         // Step 1: Check reseed_counter. Will not fail. Already checked in
       
   154         // AbstractDrbg#engineNextBytes.
       
   155 
       
   156         // Step 2. HMAC_DRBG_Update
       
   157         if (additionalInput != null) {
       
   158             update(additionalInput);
       
   159         }
       
   160 
       
   161         // Step 3. temp = Null.
       
   162         int pos = 0;
       
   163 
       
   164         // Step 4. Loop
       
   165         while (pos < result.length) {
       
   166             int tailLen = result.length - pos;
       
   167 
       
   168             // Step 4.1 V = HMAC (Key, V).
       
   169             try {
       
   170                 mac.init(new SecretKeySpec(k, macAlg));
       
   171             } catch (InvalidKeyException e) {
       
   172                 throw new InternalError(e);
       
   173             }
       
   174             v = mac.doFinal(v);
       
   175             // Step 4.2 temp = temp || V.
       
   176             System.arraycopy(v, 0, result, pos,
       
   177                     tailLen > outLen ? outLen : tailLen);
       
   178             pos += outLen;
       
   179         }
       
   180 
       
   181         // Step 5: No need to truncate
       
   182 
       
   183         // Step 6. HMAC_DRBG_Update (additional_input, Key, V).
       
   184         if (additionalInput != null) {
       
   185             update(additionalInput);
       
   186         } else {
       
   187             update();
       
   188         }
       
   189 
       
   190         // Step 7. reseed_counter = reseed_counter + 1.
       
   191         reseedCounter++;
       
   192 
       
   193         //status();
       
   194 
       
   195         // Step 8. Return
       
   196     }
       
   197 
       
   198     private void readObject(java.io.ObjectInputStream s)
       
   199             throws IOException, ClassNotFoundException {
       
   200         s.defaultReadObject ();
       
   201         initEngine();
       
   202     }
       
   203 }