src/java.base/share/classes/sun/security/provider/DRBG.java
changeset 47216 71c04702a3d5
parent 38853 971a7101da5b
child 57950 4612a3cfb927
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 java.io.IOException;
       
    29 import java.security.AccessController;
       
    30 import java.security.DrbgParameters;
       
    31 import java.security.PrivilegedAction;
       
    32 import java.security.SecureRandomParameters;
       
    33 import java.security.SecureRandomSpi;
       
    34 import java.security.Security;
       
    35 import java.util.Locale;
       
    36 import static java.security.DrbgParameters.Capability.*;
       
    37 
       
    38 /**
       
    39  * Implement the "SecureRandom.DRBG" algorithm.
       
    40  *
       
    41  * About the default "securerandom.drbg.config" value:
       
    42  *
       
    43  * The default value in java.security is set to "". This is because
       
    44  * the default values of different aspects are dependent (For example,
       
    45  * strength depends on algorithm) and if we write a full string there
       
    46  * it will be difficult to modify one and keep all others legal.
       
    47  *
       
    48  * When changing default values, touch all places including:
       
    49  *
       
    50  * 1. comments of the security property in java.security
       
    51  * 2. Default mech, cap, usedf set in this class
       
    52  * 3. Default algorithm set in final implementation of each mech
       
    53  * 4. Default strength set in AbstractDrbg, but the effective
       
    54  *    value can be smaller if an algorithm does not support it.
       
    55  *
       
    56  * The default value is also mentioned in the @implNote part of
       
    57  * {@link DrbgParameters} class.
       
    58  */
       
    59 public final class DRBG extends SecureRandomSpi {
       
    60 
       
    61     private static final String PROP_NAME = "securerandom.drbg.config";
       
    62 
       
    63     private static final long serialVersionUID = 9L;
       
    64 
       
    65     private transient AbstractDrbg impl;
       
    66 
       
    67     /**
       
    68      * @serial
       
    69      */
       
    70     private final MoreDrbgParameters mdp;
       
    71 
       
    72     public DRBG(SecureRandomParameters params) {
       
    73 
       
    74         // All parameters at unset status (null or -1).
       
    75 
       
    76         // Configurable with the "securerandom.drbg.config" security property
       
    77         String mech = null;
       
    78         Boolean usedf = null;
       
    79         String algorithm = null;
       
    80 
       
    81         // Default instantiate parameters also configurable with
       
    82         // "securerandom.drbg.config", and can be changed with params
       
    83         // in getInstance("drbg", params)
       
    84         int strength = -1;
       
    85         DrbgParameters.Capability cap = null;
       
    86         byte[] ps = null;
       
    87 
       
    88         // Not configurable with public interfaces, but is a part of
       
    89         // MoreDrbgParameters
       
    90         EntropySource es = null;
       
    91         byte[] nonce = null;
       
    92 
       
    93         // Can be configured with a security property
       
    94 
       
    95         String config = AccessController.doPrivileged((PrivilegedAction<String>)
       
    96                 () -> Security.getProperty(PROP_NAME));
       
    97 
       
    98         if (config != null && !config.isEmpty()) {
       
    99             for (String part : config.split(",")) {
       
   100                 part = part.trim();
       
   101                 switch (part.toLowerCase(Locale.ROOT)) {
       
   102                     case "":
       
   103                         throw new IllegalArgumentException(
       
   104                                 "aspect in " + PROP_NAME + " cannot be empty");
       
   105                     case "pr_and_reseed":
       
   106                         checkTwice(cap != null, "capability");
       
   107                         cap = PR_AND_RESEED;
       
   108                         break;
       
   109                     case "reseed_only":
       
   110                         checkTwice(cap != null, "capability");
       
   111                         cap = RESEED_ONLY;
       
   112                         break;
       
   113                     case "none":
       
   114                         checkTwice(cap != null, "capability");
       
   115                         cap = NONE;
       
   116                         break;
       
   117                     case "hash_drbg":
       
   118                     case "hmac_drbg":
       
   119                     case "ctr_drbg":
       
   120                         checkTwice(mech != null, "mechanism name");
       
   121                         mech = part;
       
   122                         break;
       
   123                     case "no_df":
       
   124                         checkTwice(usedf != null, "usedf flag");
       
   125                         usedf = false;
       
   126                         break;
       
   127                     case "use_df":
       
   128                         checkTwice(usedf != null, "usedf flag");
       
   129                         usedf = true;
       
   130                         break;
       
   131                     default:
       
   132                         // For all other parts of the property, it is
       
   133                         // either an algorithm name or a strength
       
   134                         try {
       
   135                             int tmp = Integer.parseInt(part);
       
   136                             if (tmp < 0) {
       
   137                                 throw new IllegalArgumentException(
       
   138                                         "strength in " + PROP_NAME +
       
   139                                                 " cannot be negative: " + part);
       
   140                             }
       
   141                             checkTwice(strength >= 0, "strength");
       
   142                             strength = tmp;
       
   143                         } catch (NumberFormatException e) {
       
   144                             checkTwice(algorithm != null, "algorithm name");
       
   145                             algorithm = part;
       
   146                         }
       
   147                 }
       
   148             }
       
   149         }
       
   150 
       
   151         // Can be updated by params
       
   152 
       
   153         if (params != null) {
       
   154             // MoreDrbgParameters is used for testing.
       
   155             if (params instanceof MoreDrbgParameters) {
       
   156                 MoreDrbgParameters m = (MoreDrbgParameters) params;
       
   157                 params = DrbgParameters.instantiation(m.strength,
       
   158                         m.capability, m.personalizationString);
       
   159 
       
   160                 // No need to check null for es and nonce, they are still null
       
   161                 es = m.es;
       
   162                 nonce = m.nonce;
       
   163 
       
   164                 if (m.mech != null) {
       
   165                     mech = m.mech;
       
   166                 }
       
   167                 if (m.algorithm != null) {
       
   168                     algorithm = m.algorithm;
       
   169                 }
       
   170                 usedf = m.usedf;
       
   171             }
       
   172             if (params instanceof DrbgParameters.Instantiation) {
       
   173                 DrbgParameters.Instantiation dp =
       
   174                         (DrbgParameters.Instantiation) params;
       
   175 
       
   176                 // ps is still null by now
       
   177                 ps = dp.getPersonalizationString();
       
   178 
       
   179                 int tmp = dp.getStrength();
       
   180                 if (tmp != -1) {
       
   181                     strength = tmp;
       
   182                 }
       
   183                 cap = dp.getCapability();
       
   184             } else {
       
   185                 throw new IllegalArgumentException("Unsupported params: "
       
   186                         + params.getClass());
       
   187             }
       
   188         }
       
   189 
       
   190         // Hardcoded defaults.
       
   191         // Remember to sync with "securerandom.drbg.config" in java.security.
       
   192 
       
   193         if (cap == null) {
       
   194             cap = NONE;
       
   195         }
       
   196         if (mech == null) {
       
   197             mech = "Hash_DRBG";
       
   198         }
       
   199         if (usedf == null) {
       
   200             usedf = true;
       
   201         }
       
   202 
       
   203         mdp = new MoreDrbgParameters(
       
   204                 es, mech, algorithm, nonce, usedf,
       
   205                 DrbgParameters.instantiation(strength, cap, ps));
       
   206 
       
   207         createImpl();
       
   208     }
       
   209 
       
   210     private void createImpl() {
       
   211         switch (mdp.mech.toLowerCase(Locale.ROOT)) {
       
   212             case "hash_drbg":
       
   213                 impl = new HashDrbg(mdp);
       
   214                 break;
       
   215             case "hmac_drbg":
       
   216                 impl = new HmacDrbg(mdp);
       
   217                 break;
       
   218             case "ctr_drbg":
       
   219                 impl = new CtrDrbg(mdp);
       
   220                 break;
       
   221             default:
       
   222                 throw new IllegalArgumentException("Unsupported mech: " + mdp.mech);
       
   223         }
       
   224     }
       
   225 
       
   226     @Override
       
   227     protected void engineSetSeed(byte[] seed) {
       
   228         impl.engineSetSeed(seed);
       
   229     }
       
   230 
       
   231     @Override
       
   232     protected void engineNextBytes(byte[] bytes) {
       
   233         impl.engineNextBytes(bytes);
       
   234     }
       
   235 
       
   236     @Override
       
   237     protected byte[] engineGenerateSeed(int numBytes) {
       
   238         return impl.engineGenerateSeed(numBytes);
       
   239     }
       
   240 
       
   241     @Override
       
   242     protected void engineNextBytes(
       
   243             byte[] bytes, SecureRandomParameters params) {
       
   244         impl.engineNextBytes(bytes, params);
       
   245     }
       
   246 
       
   247     @Override
       
   248     protected void engineReseed(SecureRandomParameters params) {
       
   249         impl.engineReseed(params);
       
   250     }
       
   251 
       
   252     @Override
       
   253     protected SecureRandomParameters engineGetParameters() {
       
   254         return impl.engineGetParameters();
       
   255     }
       
   256 
       
   257     @Override
       
   258     public String toString() {
       
   259         return impl.toString();
       
   260     }
       
   261 
       
   262     /**
       
   263      * Ensures an aspect is not set more than once.
       
   264      *
       
   265      * @param flag true if set more than once
       
   266      * @param name the name of aspect shown in IAE
       
   267      * @throws IllegalArgumentException if it happens
       
   268      */
       
   269     private static void checkTwice(boolean flag, String name) {
       
   270         if (flag) {
       
   271             throw new IllegalArgumentException(name
       
   272                     + " cannot be provided more than once in " + PROP_NAME);
       
   273         }
       
   274     }
       
   275 
       
   276     private void readObject(java.io.ObjectInputStream s)
       
   277             throws IOException, ClassNotFoundException {
       
   278         s.defaultReadObject();
       
   279         if (mdp.mech == null) {
       
   280             throw new IllegalArgumentException("Input data is corrupted");
       
   281         }
       
   282         createImpl();
       
   283     }
       
   284 }