--- /dev/null 2016-04-05 10:17:01.000000000 +0800 +++ new/src/java.base/share/classes/sun/security/provider/DRBG.java 2016-04-05 10:17:01.000000000 +0800 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2016, 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 sun.security.provider; + +import java.security.AccessController; +import java.security.DrbgParameters; +import java.security.PrivilegedAction; +import java.security.SecureRandomParameters; +import java.security.SecureRandomSpi; +import java.security.Security; +import java.util.Locale; +import static java.security.DrbgParameters.Capability.*; + +/** + * Implement the "SecureRandom.DRBG" algorithm. + */ +public final class DRBG extends SecureRandomSpi { + + private static final long serialVersionUID = 9L; + + private final AbstractDrbg impl; + + public DRBG(SecureRandomParameters params) { + + // All parameters at unset status (null or -1). + + // Configurable with security property "drbg" + String mech = null; + Boolean usedf = null; + String algorithm = null; + + // Default instantiate parameters configurable with "drbg", + // and can be changed with params in getInstance("drbg", params) + int strength = -1; + DrbgParameters.Capability cap = null; + byte[] ps = null; + + // Not configurable with public interfaces, but is a part of + // MoreDrbgParameters + EntropySource es = null; + byte[] nonce = null; + + // Can be configured with a security property + + String config = AccessController.doPrivileged((PrivilegedAction) + () -> Security.getProperty("drbg")); + + if (config != null && !config.isEmpty()) { + for (String part: config.split(",")) { + part = part.trim(); + switch (part.toLowerCase(Locale.ROOT)) { + case "": + throw new IllegalArgumentException( + "aspect in drbg cannot be empty"); + case "pr_and_reseed": + checkTwice(cap != null, "capability"); + cap = PR_AND_RESEED; + break; + case "reseed_only": + checkTwice(cap != null, "capability"); + cap = RESEED_ONLY; + break; + case "none": + checkTwice(cap != null, "capability"); + cap = NONE; + break; + case "hash_drbg": + case "hmac_drbg": + case "ctr_drbg": + checkTwice(mech != null, "mechanism name"); + mech = part; + break; + case "no_df": + checkTwice(usedf != null, "usedf flag"); + usedf = false; + break; + case "use_df": + checkTwice(usedf != null, "usedf flag"); + usedf = true; + break; + default: + // For all other parts of the property, it is + // either an algorithm name or a strength + try { + checkTwice(strength >= 0, "strength"); + strength = Integer.parseInt(part); + if (strength < 0) { + throw new IllegalArgumentException( + "strength in drbg cannot be negative"); + } + } catch (NumberFormatException e) { + checkTwice(algorithm != null, "algorithm name"); + algorithm = part; + } + } + } + } + + // Can be updated by params + + if (params != null) { + if (params instanceof MoreDrbgParameters) { + MoreDrbgParameters m = (MoreDrbgParameters)params; + params = m.config; + + // No need to check null for es and nonce, they are still null + es = m.es; + nonce = m.nonce; + + if (m.mech != null) { + mech = m.mech; + } + if (m.algorithm != null) { + algorithm = m.algorithm; + } + usedf = m.usedf; + } + if (params instanceof DrbgParameters.Instantiate) { + DrbgParameters.Instantiate dp = + (DrbgParameters.Instantiate) params; + + // ps is still null by now + ps = dp.getPersonalizationString(); + + if (dp.getStrength() != -1) { + strength = dp.getStrength(); + } + cap = dp.getCapability(); + } else { + throw new IllegalArgumentException("Unsupported params"); + } + } + + // Hardcoded defaults. The info below is duplicated in comments + // of the "drbg" security property in java.security. + + if (cap == null) { + cap = NONE; + } + if (mech == null) { + mech = "Hash_DRBG"; + } + if (usedf == null) { + usedf = true; + } + + MoreDrbgParameters m = new MoreDrbgParameters( + es, mech, algorithm, nonce, usedf, + DrbgParameters.instantiate(strength, cap, ps)); + + switch (mech.toLowerCase(Locale.ROOT)) { + case "hash_drbg": + impl = new HashDrbg(m); + break; + case "hmac_drbg": + impl = new HmacDrbg(m); + break; + case "ctr_drbg": + impl = new CtrDrbg(m); + break; + default: + throw new IllegalArgumentException("Unsupported mech"); + } + } + + @Override + protected void engineSetSeed(byte[] seed) { + impl.engineSetSeed(seed); + } + + @Override + protected void engineNextBytes(byte[] bytes) { + impl.engineNextBytes(bytes); + } + + @Override + protected byte[] engineGenerateSeed(int numBytes) { + return impl.engineGenerateSeed(numBytes); + } + + @Override + protected void engineNextBytes( + byte[] bytes, SecureRandomParameters params) { + impl.engineNextBytes(bytes, params); + } + + @Override + protected void engineReseed(SecureRandomParameters params) { + impl.engineReseed(params); + } + + @Override + protected SecureRandomParameters engineGetParameters() { + return impl.engineGetParameters(); + } + + @Override + public String toString() { + return impl.toString(); + } + + /** + * Ensures an aspect is not set more than once. + * + * @param flag true if set more than once + * @param name the name of aspect shown in IAE + * @throws IllegalArgumentException if it happens + */ + private static void checkTwice(boolean flag, String name) { + if (flag) { + throw new IllegalArgumentException(name + + " cannot be provided more than once in drbg"); + } + } +}