8157308: Make AbstractDrbg non-Serializable
authorweijun
Tue, 07 Jun 2016 10:10:59 +0800
changeset 38853 971a7101da5b
parent 38852 21057752f324
child 38854 346e5e8aeb45
8157308: Make AbstractDrbg non-Serializable Reviewed-by: mullan
jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java
jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java
jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java
jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java
jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java
jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java
jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/SpecTest.java
jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/java.base/sun/security/provider/S.java
jdk/test/sun/security/provider/SecureRandom/AbstractDrbgSpec.java
jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java
--- a/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractDrbg.java	Tue Jun 07 10:10:59 2016 +0800
@@ -33,12 +33,13 @@
 import static java.security.DrbgParameters.Capability.*;
 
 /**
- * The abstract base class for all DRBGs.
+ * The abstract base class for all DRBGs. It is used as {@link DRBG#impl}.
  * <p>
- * This class creates 5 new abstract methods. 3 are defined by the SP800-90A:
+ * This class has 5 abstract methods. 3 are defined by SP800-90A:
  * <ol>
  *  <li>{@link #generateAlgorithm(byte[], byte[])}
- *  <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported)
+ *  <li>{@link #reseedAlgorithm(byte[], byte[])} (In fact this is not an
+ *      abstract method, but any DRBG supporting reseeding must override it.)
  *  <li>{@link #instantiateAlgorithm(byte[])}
  * </ol>
  * and 2 for implementation purpose:
@@ -46,18 +47,19 @@
  *  <li>{@link #initEngine()}
  *  <li>{@link #chooseAlgorithmAndStrength}
  * </ol>
- * All existing {@link SecureRandomSpi} methods are implemented based on the
- * methods above as final. The initialization process is divided into 2 phases:
- * configuration is eagerly called to set up parameters, and instantiation
- * is lazily called only when nextBytes or reseed is called.
+ * Although this class is not a child class of {@link SecureRandomSpi}, it
+ * implements all abstract methods there as final.
+ * <p>
+ * The initialization process of a DRBG is divided into 2 phases:
+ * {@link #configure configuration} is eagerly called to set up parameters,
+ * and {@link #instantiateIfNecessary instantiation} is lazily called only
+ * when nextBytes or reseed is called.
  * <p>
  * SecureRandom methods like reseed and nextBytes are not thread-safe.
  * An implementation is required to protect shared access to instantiate states
- * (instantiated, nonce) and DRBG states (v, c, key, reseedCounter).
+ * (instantiated, nonce) and DRBG states (v, c, key, reseedCounter, etc).
  */
-public abstract class AbstractDrbg extends SecureRandomSpi {
-
-    private static final long serialVersionUID = 9L;
+public abstract class AbstractDrbg {
 
     /**
      * This field is not null if {@code -Djava.security.debug=securerandom} is
@@ -69,7 +71,7 @@
 
     // Common working status
 
-    private transient boolean instantiated = false;
+    private boolean instantiated = false;
 
     /**
      * Reseed counter of a DRBG instance. A mechanism should increment it
@@ -78,7 +80,7 @@
      *
      * Volatile, will be used in a double checked locking.
      */
-    protected transient volatile int reseedCounter = 0;
+    protected volatile int reseedCounter = 0;
 
     // Mech features. If not same as below, must be redefined in constructor.
 
@@ -170,7 +172,7 @@
     /**
      * Algorithm used by this instance (SHA-512 or AES-256). Must be assigned
      * in {@link #chooseAlgorithmAndStrength}. This field is used in
-     * {@link #toString()} and {@link DRBG#algorithmName}.
+     * {@link #toString()}.
      */
     protected String algorithm;
 
@@ -217,7 +219,7 @@
      * After instantiation, this field is not null. Do not modify it
      * in a mechanism.
      */
-    protected transient byte[] nonce;
+    protected byte[] nonce;
 
     /**
      * Requested nonce in {@link MoreDrbgParameters}. If set to null,
@@ -237,7 +239,7 @@
      * {@link #configure(SecureRandomParameters)}. This field
      * can be null. {@link #getEntropyInput} will take care of null check.
      */
-    private transient EntropySource es;
+    private EntropySource es;
 
     // Five abstract methods for SP 800-90A DRBG
 
@@ -286,10 +288,7 @@
 
     /**
      * Initiates security engines ({@code MessageDigest}, {@code Mac},
-     * or {@code Cipher}). Must be called in deserialization. Please note
-     * that before instantiation the algorithm might not be available yet.
-     * In this case, just return and this method will be called
-     * automatically at instantiation.
+     * or {@code Cipher}). This method is called during instantiation.
      */
     protected abstract void initEngine();
 
@@ -331,13 +330,11 @@
 
     // SecureRandomSpi methods taken care of here. All final.
 
-    @Override
     protected final void engineNextBytes(byte[] result) {
         engineNextBytes(result, DrbgParameters.nextBytes(
                 -1, predictionResistanceFlag, null));
     }
 
-    @Override
     protected final void engineNextBytes(
             byte[] result, SecureRandomParameters params) {
 
@@ -402,7 +399,6 @@
         }
     }
 
-    @Override
     public final void engineReseed(SecureRandomParameters params) {
         if (debug != null) {
             debug.println(this, "reseed with params");
@@ -454,7 +450,6 @@
      * @param numBytes the number of seed bytes to generate.
      * @return the seed bytes.
      */
-    @Override
     public final byte[] engineGenerateSeed(int numBytes) {
         byte[] b = new byte[numBytes];
         SeedGenerator.generateSeed(b);
@@ -469,7 +464,6 @@
      *
      * @param input the seed
      */
-    @Override
     public final synchronized void engineSetSeed(byte[] input) {
         if (debug != null) {
             debug.println(this, "setSeed");
@@ -598,7 +592,6 @@
      *
      * @return the curent configuration
      */
-    @Override
     protected SecureRandomParameters engineGetParameters() {
         // Or read from variable.
         return DrbgParameters.instantiation(
@@ -631,7 +624,8 @@
             this.es = m.es;
             this.requestedAlgorithm = m.algorithm;
             this.usedf = m.usedf;
-            params = m.config;
+            params = DrbgParameters.instantiation(m.strength,
+                    m.capability, m.personalizationString);
         }
         if (params != null) {
             if (params instanceof DrbgParameters.Instantiation) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/AbstractHashDrbg.java	Tue Jun 07 10:10:59 2016 +0800
@@ -32,8 +32,6 @@
 
 public abstract class AbstractHashDrbg extends AbstractDrbg {
 
-    private static final long serialVersionUID = 9L;
-
     protected int outLen;
     protected int seedLen;
 
--- a/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/CtrDrbg.java	Tue Jun 07 10:10:59 2016 +0800
@@ -28,14 +28,12 @@
 import javax.crypto.Cipher;
 import javax.crypto.NoSuchPaddingException;
 import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
 import java.security.*;
 import java.util.Arrays;
 import java.util.Locale;
 
 public class CtrDrbg extends AbstractDrbg {
 
-    private static final long serialVersionUID = 9L;
     private static final int AES_LIMIT;
 
     static {
@@ -47,7 +45,7 @@
         }
     }
 
-    private transient Cipher cipher;
+    private Cipher cipher;
 
     private String cipherAlg;
     private String keyAlg;
@@ -57,8 +55,8 @@
     private int keyLen;
     private int seedLen;
 
-    private transient byte[] v;
-    private transient byte[] k;
+    private byte[] v;
+    private byte[] k;
 
     public CtrDrbg(SecureRandomParameters params) {
         mechName = "CTR_DRBG";
@@ -165,7 +163,7 @@
     protected void initEngine() {
         try {
             /*
-             * Use the local SUN implementation to avoid native
+             * Use the local SunJCE implementation to avoid native
              * performance overhead.
              */
             cipher = Cipher.getInstance(cipherAlg, "SunJCE");
@@ -463,12 +461,6 @@
         // Step 8. Return
     }
 
-    private void readObject(java.io.ObjectInputStream s)
-            throws IOException, ClassNotFoundException {
-        s.defaultReadObject ();
-        initEngine();
-    }
-
     @Override
     public String toString() {
         return super.toString() + ","
--- a/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DRBG.java	Tue Jun 07 10:10:59 2016 +0800
@@ -25,6 +25,7 @@
 
 package sun.security.provider;
 
+import java.io.IOException;
 import java.security.AccessController;
 import java.security.DrbgParameters;
 import java.security.PrivilegedAction;
@@ -61,11 +62,12 @@
 
     private static final long serialVersionUID = 9L;
 
-    private final AbstractDrbg impl;
+    private transient AbstractDrbg impl;
 
-    private final String mechName;
-
-    private final String algorithmName;
+    /**
+     * @serial
+     */
+    private final MoreDrbgParameters mdp;
 
     public DRBG(SecureRandomParameters params) {
 
@@ -91,7 +93,7 @@
         // Can be configured with a security property
 
         String config = AccessController.doPrivileged((PrivilegedAction<String>)
-                    () -> Security.getProperty(PROP_NAME));
+                () -> Security.getProperty(PROP_NAME));
 
         if (config != null && !config.isEmpty()) {
             for (String part : config.split(",")) {
@@ -151,8 +153,9 @@
         if (params != null) {
             // MoreDrbgParameters is used for testing.
             if (params instanceof MoreDrbgParameters) {
-                MoreDrbgParameters m = (MoreDrbgParameters)params;
-                params = m.config;
+                MoreDrbgParameters m = (MoreDrbgParameters) params;
+                params = DrbgParameters.instantiation(m.strength,
+                        m.capability, m.personalizationString);
 
                 // No need to check null for es and nonce, they are still null
                 es = m.es;
@@ -197,26 +200,27 @@
             usedf = true;
         }
 
-        MoreDrbgParameters m = new MoreDrbgParameters(
+        mdp = new MoreDrbgParameters(
                 es, mech, algorithm, nonce, usedf,
                 DrbgParameters.instantiation(strength, cap, ps));
 
-        switch (mech.toLowerCase(Locale.ROOT)) {
+        createImpl();
+    }
+
+    private void createImpl() {
+        switch (mdp.mech.toLowerCase(Locale.ROOT)) {
             case "hash_drbg":
-                impl = new HashDrbg(m);
+                impl = new HashDrbg(mdp);
                 break;
             case "hmac_drbg":
-                impl = new HmacDrbg(m);
+                impl = new HmacDrbg(mdp);
                 break;
             case "ctr_drbg":
-                impl = new CtrDrbg(m);
+                impl = new CtrDrbg(mdp);
                 break;
             default:
-                throw new IllegalArgumentException("Unsupported mech: " + mech);
+                throw new IllegalArgumentException("Unsupported mech: " + mdp.mech);
         }
-
-        mechName = mech;
-        algorithmName = impl.algorithm;
     }
 
     @Override
@@ -268,4 +272,13 @@
                     + " 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();
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/HashDrbg.java	Tue Jun 07 10:10:59 2016 +0800
@@ -25,7 +25,6 @@
 
 package sun.security.provider;
 
-import java.io.IOException;
 import java.math.BigInteger;
 import java.security.DigestException;
 import java.security.MessageDigest;
@@ -36,15 +35,13 @@
 
 public class HashDrbg extends AbstractHashDrbg {
 
-    private static final long serialVersionUID = 9L;
-
     private static final byte[] ZERO = new byte[1];
     private static final byte[] ONE = new byte[]{1};
 
-    private transient MessageDigest digest;
+    private MessageDigest digest;
 
-    private transient byte[] v;
-    private transient byte[] c;
+    private byte[] v;
+    private byte[] c;
 
     public HashDrbg(SecureRandomParameters params) {
         mechName = "Hash_DRBG";
@@ -267,10 +264,4 @@
         // Step 5: No need to truncate
         // Step 6: Return
     }
-
-    private void readObject(java.io.ObjectInputStream s)
-            throws IOException, ClassNotFoundException {
-        s.defaultReadObject ();
-        initEngine();
-    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/HmacDrbg.java	Tue Jun 07 10:10:59 2016 +0800
@@ -27,7 +27,6 @@
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
@@ -36,14 +35,12 @@
 
 public class HmacDrbg extends AbstractHashDrbg {
 
-    private static final long serialVersionUID = 9L;
-
-    private transient Mac mac;
+    private Mac mac;
 
     private String macAlg;
 
-    private transient byte[] v;
-    private transient byte[] k;
+    private byte[] v;
+    private byte[] k;
 
     public HmacDrbg(SecureRandomParameters params) {
         mechName = "HMAC_DRBG";
@@ -101,6 +98,10 @@
     protected void initEngine() {
         macAlg = "HmacSHA" + algorithm.substring(4);
         try {
+            /*
+             * Use the local SunJCE implementation to avoid native
+             * performance overhead.
+             */
             mac = Mac.getInstance(macAlg, "SunJCE");
         } catch (NoSuchProviderException | NoSuchAlgorithmException e) {
             // Fallback to any available.
@@ -194,10 +195,4 @@
 
         // Step 8. Return
     }
-
-    private void readObject(java.io.ObjectInputStream s)
-            throws IOException, ClassNotFoundException {
-        s.defaultReadObject ();
-        initEngine();
-    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java	Mon Jun 06 16:46:54 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/MoreDrbgParameters.java	Tue Jun 07 10:10:59 2016 +0800
@@ -25,20 +25,30 @@
 
 package sun.security.provider;
 
+import java.io.IOException;
+import java.io.Serializable;
 import java.security.DrbgParameters;
 import java.security.SecureRandomParameters;
 
 /**
- * Extra non-standard parameters that can be used by DRBGs.
+ * Exported and non-exported parameters that can be used by DRBGs.
  */
-public class MoreDrbgParameters implements SecureRandomParameters {
+public class MoreDrbgParameters implements SecureRandomParameters, Serializable {
+
+    private static final long serialVersionUID = 9L;
+
+    final transient EntropySource es;
 
     final String mech;
     final String algorithm;
-    final EntropySource es;
-    final byte[] nonce;
     final boolean usedf;
-    final DrbgParameters.Instantiation config;
+    final int strength;
+    final DrbgParameters.Capability capability;
+
+    // The following 2 fields will be reassigned in readObject and
+    // thus cannot be final
+    byte[] nonce;
+    byte[] personalizationString;
 
     /**
      * Creates a new {@code MoreDrbgParameters} object.
@@ -61,13 +71,31 @@
         this.mech = mech;
         this.algorithm = algorithm;
         this.es = es;
-        this.nonce = nonce;
+        this.nonce = (nonce == null) ? null : nonce.clone();
         this.usedf = usedf;
-        this.config = config;
+
+        this.strength = config.getStrength();
+        this.capability = config.getCapability();
+        this.personalizationString = config.getPersonalizationString();
     }
 
     @Override
     public String toString() {
-        return mech + "," + algorithm + "," + usedf + "," + config;
+        return mech + "," + algorithm + "," + usedf + "," + strength
+                + "," + capability + "," + personalizationString;
+    }
+
+    private void readObject(java.io.ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        if (nonce != null) {
+            nonce = nonce.clone();
+        }
+        if (personalizationString != null) {
+            personalizationString = personalizationString.clone();
+        }
+        if (capability == null) {
+            throw new IllegalArgumentException("Input data is corrupted");
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/SpecTest.java	Tue Jun 07 10:10:59 2016 +0800
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 8051408 8157308
+ * @modules java.base/sun.security.provider
+ * @build java.base/sun.security.provider.S
+ * @run main SpecTest
+ * @summary check the AbstractDrbg API etc
+ */
+
+import java.security.*;
+import sun.security.provider.S;
+import static java.security.DrbgParameters.Capability.*;
+
+/**
+ * This test makes sure the AbstractDrbg API works as specified. It also
+ * checks the SecureRandom API.
+ *
+ * The implementations must be patched into java.base/sun.security.provider
+ * because AbstractDrbg is not a public interface.
+ */
+public class SpecTest {
+
+    public static void main(String args[]) throws Exception {
+
+        // getInstance from a provider.
+
+        Provider p = new All("A", 0, "");
+        byte[] bytes = new byte[100];
+
+        // A non-DRBG
+        iae(() -> SecureRandom.getInstance("S1", null, p));
+        nsae(() -> SecureRandom.getInstance("S1",
+                new SecureRandomParameters() {}, p));
+
+        SecureRandom s1 = SecureRandom.getInstance("S1", p);
+        if (s1.getParameters() != null) {
+            throw new Exception();
+        }
+
+        iae(() -> s1.nextBytes(bytes, null));
+        uoe(() -> s1.nextBytes(bytes, new SecureRandomParameters() {}));
+        uoe(() -> s1.reseed());
+        iae(() -> s1.reseed(null));
+        uoe(() -> s1.reseed(new SecureRandomParameters() {}));
+
+        // A weak DRBG
+        iae(() -> SecureRandom.getInstance("S2", null, p));
+        nsae(() -> SecureRandom.getInstance("S2",
+                new SecureRandomParameters() {}, p));
+        nsae(() -> SecureRandom.getInstance("S2",
+                DrbgParameters.instantiation(256, NONE, null), p));
+        nsae(() -> SecureRandom.getInstance("S2",
+                DrbgParameters.instantiation(-1, PR_AND_RESEED, null), p));
+        nsae(() -> SecureRandom.getInstance("S2",
+                DrbgParameters.instantiation(-1, RESEED_ONLY, null), p));
+
+        SecureRandom s2 = SecureRandom.getInstance("S2",
+                DrbgParameters.instantiation(-1, NONE, null), p);
+        equals(s2, "S2,SQUEEZE,128,none");
+        equals(s2.getParameters(), "128,none,null");
+
+        npe(() -> s2.nextBytes(null));
+        iae(() -> s2.nextBytes(bytes, null));
+        iae(() -> s2.nextBytes(bytes, new SecureRandomParameters() {}));
+        uoe(() -> s2.reseed());
+        iae(() -> s2.reseed(null));
+
+        iae(() -> s2.nextBytes(bytes,
+                DrbgParameters.nextBytes(-1, false, new byte[101])));
+        s2.nextBytes(new byte[101],
+                DrbgParameters.nextBytes(-1, false, new byte[100]));
+        s2.nextBytes(bytes,
+                DrbgParameters.nextBytes(-1, false, new byte[100]));
+
+        // A strong DRBG
+        iae(() -> SecureRandom.getInstance("S3", null, p));
+        nsae(() -> SecureRandom.getInstance("S3",
+                new SecureRandomParameters() {}, p));
+        SecureRandom.getInstance("S3",
+                DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
+
+        SecureRandom s3 = SecureRandom.getInstance("S3", p);
+        equals(s3, "S3,SQUEEZE,128,reseed_only");
+        equals(s3.getParameters(), "128,reseed_only,null");
+
+        iae(() -> s3.nextBytes(bytes,
+                DrbgParameters.nextBytes(192, false, null)));
+        iae(() -> s3.nextBytes(bytes,
+                DrbgParameters.nextBytes(112, true, null)));
+        iae(() -> s3.reseed(new SecureRandomParameters() {}));
+
+        SecureRandom s32 = SecureRandom.getInstance(
+                "S3", DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
+        equals(s32, "S3,SQUEEZE,192,pr_and_reseed");
+        equals(s32.getParameters(), "192,pr_and_reseed,null");
+
+        s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null));
+        s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null));
+        s32.reseed();
+        s32.reseed(DrbgParameters.reseed(true, new byte[100]));
+
+        // getInstance from competitive providers.
+
+        Provider l = new Legacy("L", 0, "");
+        Provider w = new Weak("W", 0, "");
+        Provider s = new Strong("S", 0, "");
+
+        Security.addProvider(l);
+        Security.addProvider(w);
+        Security.addProvider(s);
+
+        SecureRandom s4;
+
+        try {
+            s4 = SecureRandom.getInstance("S");
+            if (s4.getProvider() != l) {
+                throw new Exception();
+            }
+
+            nsae(() -> SecureRandom.getInstance(
+                    "S", DrbgParameters.instantiation(256, NONE, null)));
+
+            s4 = SecureRandom.getInstance(
+                    "S", DrbgParameters.instantiation(192, NONE, null));
+            if (s4.getProvider() != s) {
+                throw new Exception();
+            }
+
+            s4 = SecureRandom.getInstance(
+                    "S", DrbgParameters.instantiation(128, PR_AND_RESEED, null));
+            if (s4.getProvider() != s) {
+                throw new Exception();
+            }
+
+            s4 = SecureRandom.getInstance(
+                    "S", DrbgParameters.instantiation(128, RESEED_ONLY, null));
+            if (s4.getProvider() != s) {
+                throw new Exception();
+            }
+
+            s4 = SecureRandom.getInstance(
+                    "S", DrbgParameters.instantiation(128, NONE, null));
+            if (s4.getProvider() != w) {
+                throw new Exception();
+            }
+        } finally {
+            Security.removeProvider("L");
+            Security.removeProvider("W");
+            Security.removeProvider("S");
+        }
+    }
+
+    public static class All extends Provider {
+        protected All(String name, double version, String info) {
+            super(name, version, info);
+            put("SecureRandom.S1", S.S1.class.getName());
+            put("SecureRandom.S2", S.S2.class.getName());
+            put("SecureRandom.S3", S.S3.class.getName());
+        }
+    }
+
+    // Providing S with no params support
+    public static class Legacy extends Provider {
+        protected Legacy(String name, double version, String info) {
+            super(name, version, info);
+            put("SecureRandom.S", S.S1.class.getName());
+        }
+    }
+
+    public static class Weak extends Provider {
+        protected Weak(String name, double version, String info) {
+            super(name, version, info);
+            put("SecureRandom.S", S.S2.class.getName());
+        }
+    }
+
+    public static class Strong extends Provider {
+        protected Strong(String name, double version, String info) {
+            super(name, version, info);
+            put("SecureRandom.S", S.S3.class.getName());
+        }
+    }
+
+    static void nsae(RunnableWithException r) throws Exception {
+        checkException(r, NoSuchAlgorithmException.class);
+    }
+
+    static void iae(RunnableWithException r) throws Exception {
+        checkException(r, IllegalArgumentException.class);
+    }
+
+    static void uoe(RunnableWithException r) throws Exception {
+        checkException(r, UnsupportedOperationException.class);
+    }
+
+    static void npe(RunnableWithException r) throws Exception {
+        checkException(r, NullPointerException.class);
+    }
+
+    interface RunnableWithException {
+        void run() throws Exception;
+    }
+
+    static void checkException(RunnableWithException r, Class ex)
+            throws Exception {
+        try {
+            r.run();
+        } catch (Exception e) {
+            if (ex.isAssignableFrom(e.getClass())) {
+                return;
+            }
+            throw e;
+        }
+        throw new Exception("No exception thrown");
+    }
+
+    static void equals(Object o, String s) throws Exception {
+        if (!o.toString().equals(s)) {
+            throw new Exception(o.toString() + " is not " + s);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/provider/SecureRandom/AbstractDrbg/java.base/sun/security/provider/S.java	Tue Jun 07 10:10:59 2016 +0800
@@ -0,0 +1,155 @@
+/*
+ * 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.
+ *
+ * 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.SecureRandomParameters;
+import java.security.SecureRandomSpi;
+
+/**
+ * Read ../../../../SpecTest.java for details.
+ */
+public class S extends SecureRandomSpi {
+
+    protected AbstractDrbg impl;
+
+    // This is not a DRBG.
+    public static class S1 extends SecureRandomSpi {
+        @Override
+        protected void engineSetSeed(byte[] seed) {
+        }
+
+        @Override
+        protected void engineNextBytes(byte[] bytes) {
+        }
+
+        @Override
+        protected byte[] engineGenerateSeed(int numBytes) {
+            return new byte[numBytes];
+        }
+    }
+
+    // This is a weak DRBG. maximum strength is 128 and does
+    // not support prediction resistance or reseed.
+    public static class S2 extends S {
+        public S2(SecureRandomParameters params) {
+            impl = new Impl2(params);
+        }
+    }
+
+    // This is a strong DRBG.
+    public static class S3 extends S {
+        public S3(SecureRandomParameters params) {
+            impl = new Impl3(params);
+        }
+    }
+
+    // AbstractDrbg Implementations
+
+    static class Impl3 extends AbstractDrbg {
+
+        public Impl3(SecureRandomParameters params) {
+            supportPredictionResistance = true;
+            supportReseeding = true;
+            highestSupportedSecurityStrength = 192;
+            mechName = "S3";
+            algorithm = "SQUEEZE";
+            configure(params);
+        }
+
+        protected void chooseAlgorithmAndStrength() {
+            if (requestedInstantiationSecurityStrength < 0) {
+                securityStrength = DEFAULT_STRENGTH;
+            } else {
+                securityStrength = requestedInstantiationSecurityStrength;
+            }
+            minLength = securityStrength / 8;
+            maxAdditionalInputLength = maxPersonalizationStringLength = 100;
+        }
+
+        @Override
+        protected void initEngine() {
+        }
+
+        @Override
+        protected void instantiateAlgorithm(byte[] ei) {
+        }
+
+        @Override
+        protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
+        }
+
+        @Override
+        protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
+        }
+    }
+
+    static class Impl2 extends Impl3 {
+        public Impl2(SecureRandomParameters params) {
+            super(null);
+            mechName = "S2";
+            highestSupportedSecurityStrength = 128;
+            supportPredictionResistance = false;
+            supportReseeding = false;
+            configure(params);
+        }
+    }
+
+    // Overridden SecureRandomSpi methods
+
+    @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();
+    }
+}
--- a/jdk/test/sun/security/provider/SecureRandom/AbstractDrbgSpec.java	Mon Jun 06 16:46:54 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/*
- * 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.
- *
- * 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.
- */
-
-/* @test
- * @bug 8051408
- * @modules java.base/sun.security.provider
- * @summary check the AbstractDrbg API etc
- */
-
-import java.security.*;
-import sun.security.provider.AbstractDrbg;
-import static java.security.DrbgParameters.Capability.*;
-
-/**
- * This test makes sure the AbstractDrbg API works as specified. It also
- * checks the SecureRandom API.
- */
-public class AbstractDrbgSpec {
-
-    public static void main(String args[]) throws Exception {
-
-        // getInstance from a provider.
-
-        Provider p = new All("A", 0, "");
-        byte[] bytes = new byte[100];
-
-        // A non-DRBG
-        iae(() -> SecureRandom.getInstance("S1", null, p));
-        nsae(() -> SecureRandom.getInstance("S1",
-                new SecureRandomParameters() {}, p));
-
-        SecureRandom s1 = SecureRandom.getInstance("S1", p);
-        if (s1.getParameters() != null) {
-            throw new Exception();
-        }
-
-        iae(() -> s1.nextBytes(bytes, null));
-        uoe(() -> s1.nextBytes(bytes, new SecureRandomParameters() {}));
-        uoe(() -> s1.reseed());
-        iae(() -> s1.reseed(null));
-        uoe(() -> s1.reseed(new SecureRandomParameters() {}));
-
-        // A weak DRBG
-        iae(() -> SecureRandom.getInstance("S2", null, p));
-        nsae(() -> SecureRandom.getInstance("S2",
-                new SecureRandomParameters() {}, p));
-        nsae(() -> SecureRandom.getInstance("S2",
-                DrbgParameters.instantiation(256, NONE, null), p));
-        nsae(() -> SecureRandom.getInstance("S2",
-                DrbgParameters.instantiation(-1, PR_AND_RESEED, null), p));
-        nsae(() -> SecureRandom.getInstance("S2",
-                DrbgParameters.instantiation(-1, RESEED_ONLY, null), p));
-
-        SecureRandom s2 = SecureRandom.getInstance("S2",
-                DrbgParameters.instantiation(-1, NONE, null), p);
-        equals(s2, "S2,SQUEEZE,128,none");
-        equals(s2.getParameters(), "128,none,null");
-
-        npe(() -> s2.nextBytes(null));
-        iae(() -> s2.nextBytes(bytes, null));
-        iae(() -> s2.nextBytes(bytes, new SecureRandomParameters() {}));
-        uoe(() -> s2.reseed());
-        iae(() -> s2.reseed(null));
-
-        iae(() -> s2.nextBytes(bytes,
-                DrbgParameters.nextBytes(-1, false, new byte[101])));
-        s2.nextBytes(new byte[101],
-                DrbgParameters.nextBytes(-1, false, new byte[100]));
-        s2.nextBytes(bytes,
-                DrbgParameters.nextBytes(-1, false, new byte[100]));
-
-        // A strong DRBG
-        iae(() -> SecureRandom.getInstance("S3", null, p));
-        nsae(() -> SecureRandom.getInstance("S3",
-                new SecureRandomParameters() {}, p));
-        SecureRandom.getInstance("S3",
-                DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
-
-        SecureRandom s3 = SecureRandom.getInstance("S3", p);
-        equals(s3, "S3,SQUEEZE,128,reseed_only");
-        equals(s3.getParameters(), "128,reseed_only,null");
-
-        iae(() -> s3.nextBytes(bytes,
-                DrbgParameters.nextBytes(192, false, null)));
-        iae(() -> s3.nextBytes(bytes,
-                DrbgParameters.nextBytes(112, true, null)));
-        iae(() -> s3.reseed(new SecureRandomParameters() {}));
-
-        SecureRandom s32 = SecureRandom.getInstance(
-                "S3", DrbgParameters.instantiation(192, PR_AND_RESEED, null), p);
-        equals(s32, "S3,SQUEEZE,192,pr_and_reseed");
-        equals(s32.getParameters(), "192,pr_and_reseed,null");
-
-        s32.nextBytes(bytes, DrbgParameters.nextBytes(192, false, null));
-        s32.nextBytes(bytes, DrbgParameters.nextBytes(112, true, null));
-        s32.reseed();
-        s32.reseed(DrbgParameters.reseed(true, new byte[100]));
-
-        // getInstance from competitive providers.
-
-        Provider l = new Legacy("L", 0, "");
-        Provider w = new Weak("W", 0, "");
-        Provider s = new Strong("S", 0, "");
-
-        Security.addProvider(l);
-        Security.addProvider(w);
-        Security.addProvider(s);
-
-        SecureRandom s4;
-
-        try {
-            s4 = SecureRandom.getInstance("S");
-            if (s4.getProvider() != l) {
-                throw new Exception();
-            }
-
-            nsae(() -> SecureRandom.getInstance(
-                    "S", DrbgParameters.instantiation(256, NONE, null)));
-
-            s4 = SecureRandom.getInstance(
-                    "S", DrbgParameters.instantiation(192, NONE, null));
-            if (s4.getProvider() != s) {
-                throw new Exception();
-            }
-
-            s4 = SecureRandom.getInstance(
-                    "S", DrbgParameters.instantiation(128, PR_AND_RESEED, null));
-            if (s4.getProvider() != s) {
-                throw new Exception();
-            }
-
-            s4 = SecureRandom.getInstance(
-                    "S", DrbgParameters.instantiation(128, RESEED_ONLY, null));
-            if (s4.getProvider() != s) {
-                throw new Exception();
-            }
-
-            s4 = SecureRandom.getInstance(
-                    "S", DrbgParameters.instantiation(128, NONE, null));
-            if (s4.getProvider() != w) {
-                throw new Exception();
-            }
-        } finally {
-            Security.removeProvider("L");
-            Security.removeProvider("W");
-            Security.removeProvider("S");
-        }
-    }
-
-    public static class All extends Provider {
-        protected All(String name, double version, String info) {
-            super(name, version, info);
-            put("SecureRandom.S1", S1.class.getName());
-            put("SecureRandom.S2", S2.class.getName());
-            put("SecureRandom.S3", S3.class.getName());
-        }
-    }
-
-    // Providing S with no params support
-    public static class Legacy extends Provider {
-        protected Legacy(String name, double version, String info) {
-            super(name, version, info);
-            put("SecureRandom.S", S1.class.getName());
-        }
-    }
-
-    public static class Weak extends Provider {
-        protected Weak(String name, double version, String info) {
-            super(name, version, info);
-            put("SecureRandom.S", S2.class.getName());
-        }
-    }
-
-    public static class Strong extends Provider {
-        protected Strong(String name, double version, String info) {
-            super(name, version, info);
-            put("SecureRandom.S", S3.class.getName());
-        }
-    }
-
-    // This is not a DRBG.
-    public static class S1 extends SecureRandomSpi {
-        @Override
-        protected void engineSetSeed(byte[] seed) {
-        }
-
-        @Override
-        protected void engineNextBytes(byte[] bytes) {
-        }
-
-        @Override
-        protected byte[] engineGenerateSeed(int numBytes) {
-            return new byte[numBytes];
-        }
-    }
-
-    // This is a strong DRBG.
-    public static class S3 extends AbstractDrbg {
-
-        public S3(SecureRandomParameters params) {
-            supportPredictionResistance = true;
-            supportReseeding = true;
-            highestSupportedSecurityStrength = 192;
-            mechName = "S3";
-            algorithm = "SQUEEZE";
-            configure(params);
-        }
-        protected void chooseAlgorithmAndStrength() {
-            if (requestedInstantiationSecurityStrength < 0) {
-                securityStrength = DEFAULT_STRENGTH;
-            } else {
-                securityStrength = requestedInstantiationSecurityStrength;
-            }
-            minLength = securityStrength / 8;
-            maxAdditionalInputLength = maxPersonalizationStringLength = 100;
-        }
-
-        @Override
-        protected void initEngine() {
-
-        }
-
-        @Override
-        protected void instantiateAlgorithm(byte[] ei) {
-
-        }
-
-        @Override
-        protected void generateAlgorithm(byte[] result, byte[] additionalInput) {
-
-        }
-
-        @Override
-        protected void reseedAlgorithm(byte[] ei, byte[] additionalInput) {
-
-        }
-    }
-
-    // This is a weak DRBG. maximum strength is 128 and does
-    // not support prediction resistance or reseed.
-    public static class S2 extends S3 {
-        public S2(SecureRandomParameters params) {
-            super(null);
-            mechName = "S2";
-            highestSupportedSecurityStrength = 128;
-            supportPredictionResistance = false;
-            supportReseeding = false;
-            configure(params);
-        }
-    }
-
-    static void nsae(RunnableWithException r) throws Exception {
-        checkException(r, NoSuchAlgorithmException.class);
-    }
-
-    static void iae(RunnableWithException r) throws Exception {
-        checkException(r, IllegalArgumentException.class);
-    }
-
-    static void uoe(RunnableWithException r) throws Exception {
-        checkException(r, UnsupportedOperationException.class);
-    }
-
-    static void npe(RunnableWithException r) throws Exception {
-        checkException(r, NullPointerException.class);
-    }
-
-    interface RunnableWithException {
-        void run() throws Exception;
-    }
-
-    static void checkException(RunnableWithException r, Class ex)
-            throws Exception {
-        try {
-            r.run();
-        } catch (Exception e) {
-            if (ex.isAssignableFrom(e.getClass())) {
-                return;
-            }
-            throw e;
-        }
-        throw new Exception("No exception thrown");
-    }
-
-    static void equals(Object o, String s) throws Exception {
-        if (!o.toString().equals(s)) {
-            throw new Exception(o.toString() + " is not " + s);
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java	Tue Jun 07 10:10:59 2016 +0800
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+import sun.security.provider.DRBG;
+import sun.security.provider.MoreDrbgParameters;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+
+/**
+ * @test
+ * @bug 8157308
+ * @modules java.base/sun.security.provider
+ * @summary Make AbstractDrbg non-Serializable
+ * @run main DRBGS11n mech
+ * @run main DRBGS11n capability
+ */
+public class DRBGS11n {
+
+    public static void main(String[] args) throws Exception {
+
+        DRBG d = new DRBG(null);
+        Field f = DRBG.class.getDeclaredField("mdp");
+        f.setAccessible(true);
+        MoreDrbgParameters mdp = (MoreDrbgParameters)f.get(d);
+
+        // Corrupt the mech or capability fields inside DRBG#mdp.
+        f = MoreDrbgParameters.class.getDeclaredField(args[0]);
+        f.setAccessible(true);
+        f.set(mdp, null);
+
+        try {
+            revive(d);
+        } catch (IllegalArgumentException iae) {
+            // Expected
+            return;
+        }
+
+        throw new Exception("revive should fail");
+    }
+
+    static <T> T revive(T in) throws Exception {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        new ObjectOutputStream(bout).writeObject(in);
+        return (T) new ObjectInputStream(
+                new ByteArrayInputStream(bout.toByteArray())).readObject();
+    }
+}