| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.provider;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
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.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public final class DRBG extends SecureRandomSpi { | 
 | 
 | 
 | 
    private static final String PROP_NAME = "securerandom.drbg.config";  | 
 | 
 | 
 | 
    private static final long serialVersionUID = 9L;  | 
 | 
 | 
 | 
    private transient AbstractDrbg impl;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final MoreDrbgParameters mdp;  | 
 | 
 | 
 | 
    public DRBG(SecureRandomParameters params) { | 
 | 
 | 
 | 
        // All parameters at unset status (null or -1).  | 
 | 
 | 
 | 
          | 
 | 
        String mech = null;  | 
 | 
        Boolean usedf = null;  | 
 | 
        String algorithm = null;  | 
 | 
 | 
 | 
        // Default instantiate parameters also configurable with  | 
 | 
        // "securerandom.drbg.config", and can be changed with params  | 
 | 
          | 
 | 
        int strength = -1;  | 
 | 
        DrbgParameters.Capability cap = null;  | 
 | 
        byte[] ps = null;  | 
 | 
 | 
 | 
        // Not configurable with public interfaces, but is a part of  | 
 | 
          | 
 | 
        EntropySource es = null;  | 
 | 
        byte[] nonce = null;  | 
 | 
 | 
 | 
        // Can be configured with a security property  | 
 | 
 | 
 | 
        String config = AccessController.doPrivileged((PrivilegedAction<String>)  | 
 | 
                () -> Security.getProperty(PROP_NAME));  | 
 | 
 | 
 | 
        if (config != null && !config.isEmpty()) { | 
 | 
            for (String part : config.split(",")) { | 
 | 
                part = part.trim();  | 
 | 
                switch (part.toLowerCase(Locale.ROOT)) { | 
 | 
                    case "":  | 
 | 
                        throw new IllegalArgumentException(  | 
 | 
                                "aspect in " + PROP_NAME + " 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  | 
 | 
                          | 
 | 
                        try { | 
 | 
                            int tmp = Integer.parseInt(part);  | 
 | 
                            if (tmp < 0) { | 
 | 
                                throw new IllegalArgumentException(  | 
 | 
                                        "strength in " + PROP_NAME +  | 
 | 
                                                " cannot be negative: " + part);  | 
 | 
                            }  | 
 | 
                            checkTwice(strength >= 0, "strength");  | 
 | 
                            strength = tmp;  | 
 | 
                        } 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 = DrbgParameters.instantiation(m.strength,  | 
 | 
                        m.capability, m.personalizationString);  | 
 | 
 | 
 | 
                  | 
 | 
                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.Instantiation) { | 
 | 
                DrbgParameters.Instantiation dp =  | 
 | 
                        (DrbgParameters.Instantiation) params;  | 
 | 
 | 
 | 
                  | 
 | 
                ps = dp.getPersonalizationString();  | 
 | 
 | 
 | 
                int tmp = dp.getStrength();  | 
 | 
                if (tmp != -1) { | 
 | 
                    strength = tmp;  | 
 | 
                }  | 
 | 
                cap = dp.getCapability();  | 
 | 
            } else { | 
 | 
                throw new IllegalArgumentException("Unsupported params: " | 
 | 
                        + params.getClass());  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        // Hardcoded defaults.  | 
 | 
        // Remember to sync with "securerandom.drbg.config" in java.security.  | 
 | 
 | 
 | 
        if (cap == null) { | 
 | 
            cap = NONE;  | 
 | 
        }  | 
 | 
        if (mech == null) { | 
 | 
            mech = "Hash_DRBG";  | 
 | 
        }  | 
 | 
        if (usedf == null) { | 
 | 
            usedf = true;  | 
 | 
        }  | 
 | 
 | 
 | 
        mdp = new MoreDrbgParameters(  | 
 | 
                es, mech, algorithm, nonce, usedf,  | 
 | 
                DrbgParameters.instantiation(strength, cap, ps));  | 
 | 
 | 
 | 
        createImpl();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void createImpl() { | 
 | 
        switch (mdp.mech.toLowerCase(Locale.ROOT)) { | 
 | 
            case "hash_drbg":  | 
 | 
                impl = new HashDrbg(mdp);  | 
 | 
                break;  | 
 | 
            case "hmac_drbg":  | 
 | 
                impl = new HmacDrbg(mdp);  | 
 | 
                break;  | 
 | 
            case "ctr_drbg":  | 
 | 
                impl = new CtrDrbg(mdp);  | 
 | 
                break;  | 
 | 
            default:  | 
 | 
                throw new IllegalArgumentException("Unsupported mech: " + mdp.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();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static void checkTwice(boolean flag, String name) { | 
 | 
        if (flag) { | 
 | 
            throw new IllegalArgumentException(name  | 
 | 
                    + " cannot be provided more than once in " + PROP_NAME);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void readObject(java.io.ObjectInputStream s)  | 
 | 
            throws IOException, ClassNotFoundException { | 
 | 
        s.defaultReadObject();  | 
 | 
        if (mdp.mech == null) { | 
 | 
            throw new IllegalArgumentException("Input data is corrupted"); | 
 | 
        }  | 
 | 
        createImpl();  | 
 | 
    }  | 
 | 
}  |