jdk/src/solaris/classes/sun/security/provider/NativePRNG.java
author duke
Sat, 01 Dec 2007 00:00:00 +0000
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
permissions -rw-r--r--
Initial load
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 2003-2004 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package sun.security.provider;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.io.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.security.*;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.security.SecureRandom;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
 * Native PRNG implementation for Solaris/Linux. It interacts with
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
 * /dev/random and /dev/urandom, so it is only available if those
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
 * files are present. Otherwise, SHA1PRNG is used instead of this class.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
 * getSeed() and setSeed() directly read/write /dev/random. However,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
 * /dev/random is only writable by root in many configurations. Because
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 * we cannot just ignore bytes specified via setSeed(), we keep a
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 * SHA1PRNG around in parallel.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
 * nextBytes() reads the bytes directly from /dev/urandom (and then
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
 * mixes them with bytes from the SHA1PRNG for the reasons explained
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
 * above). Reading bytes from /dev/urandom means that constantly get
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
 * new entropy the operating system has collected. This is a notable
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
 * advantage over the SHA1PRNG model, which acquires entropy only
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
 * initially during startup although the VM may be running for months.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
 * Also note that we do not need any initial pure random seed from
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
 * /dev/random. This is an advantage because on some versions of Linux
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
 * it can be exhausted very quickly and could thus impact startup time.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
 * Finally, note that we use a singleton for the actual work (RandomIO)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
 * to avoid having to open and close /dev/[u]random constantly. However,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
 * there may me many NativePRNG instances created by the JCA framework.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
 * @since   1.5
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
 * @author  Andreas Sterbenz
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
public final class NativePRNG extends SecureRandomSpi {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    private static final long serialVersionUID = -6599091113397072932L;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
    // name of the pure random file (also used for setSeed())
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    private static final String NAME_RANDOM = "/dev/random";
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
    // name of the pseudo random file
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
    private static final String NAME_URANDOM = "/dev/urandom";
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
    // singleton instance or null if not available
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
    private static final RandomIO INSTANCE = initIO();
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    private static RandomIO initIO() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
        Object o = AccessController.doPrivileged(new PrivilegedAction() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
            public Object run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
                File randomFile = new File(NAME_RANDOM);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
                if (randomFile.exists() == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
                    return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
                File urandomFile = new File(NAME_URANDOM);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
                if (urandomFile.exists() == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
                    return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
                    return new RandomIO(randomFile, urandomFile);
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
                } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
                    return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
        });
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
        return (RandomIO)o;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
    // return whether the NativePRNG is available
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
    static boolean isAvailable() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
        return INSTANCE != null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
    // constructor, called by the JCA framework
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
    public NativePRNG() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
        super();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
        if (INSTANCE == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
            throw new AssertionError("NativePRNG not available");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
    // set the seed
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
    protected void engineSetSeed(byte[] seed) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
        INSTANCE.implSetSeed(seed);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
    // get pseudo random bytes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
    protected void engineNextBytes(byte[] bytes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
        INSTANCE.implNextBytes(bytes);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
    // get true random bytes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
    protected byte[] engineGenerateSeed(int numBytes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
        return INSTANCE.implGenerateSeed(numBytes);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
     * Nested class doing the actual work. Singleton, see INSTANCE above.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
    private static class RandomIO {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
        // we buffer data we read from /dev/urandom for efficiency,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
        // but we limit the lifetime to avoid using stale bits
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        // lifetime in ms, currently 100 ms (0.1 s)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
        private final static long MAX_BUFFER_TIME = 100;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
        // size of the /dev/urandom buffer
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
        private final static int BUFFER_SIZE = 32;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
        // In/OutputStream for /dev/random and /dev/urandom
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
        private final InputStream randomIn, urandomIn;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
        private OutputStream randomOut;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
        // flag indicating if we have tried to open randomOut yet
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
        private boolean randomOutInitialized;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        // SHA1PRNG instance for mixing
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
        // initialized lazily on demand to avoid problems during startup
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        private volatile sun.security.provider.SecureRandom mixRandom;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
        // buffer for /dev/urandom bits
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
        private final byte[] urandomBuffer;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
        // number of bytes left in urandomBuffer
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
        private int buffered;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
        // time we read the data into the urandomBuffer
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
        private long lastRead;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
        // mutex lock for nextBytes()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
        private final Object LOCK_GET_BYTES = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
        // mutex lock for getSeed()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
        private final Object LOCK_GET_SEED = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
        // mutex lock for setSeed()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        private final Object LOCK_SET_SEED = new Object();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
        // constructor, called only once from initIO()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
        private RandomIO(File randomFile, File urandomFile) throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
            randomIn = new FileInputStream(randomFile);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
            urandomIn = new FileInputStream(urandomFile);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
            urandomBuffer = new byte[BUFFER_SIZE];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
        // get the SHA1PRNG for mixing
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
        // initialize if not yet created
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
        private sun.security.provider.SecureRandom getMixRandom() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
            sun.security.provider.SecureRandom r = mixRandom;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
            if (r == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
                synchronized (LOCK_GET_BYTES) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
                    r = mixRandom;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
                    if (r == null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
                        r = new sun.security.provider.SecureRandom();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
                        try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
                            byte[] b = new byte[20];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
                            readFully(urandomIn, b);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
                            r.engineSetSeed(b);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
                        } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
                            throw new ProviderException("init failed", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
                        mixRandom = r;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
            return r;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
        // read data.length bytes from in
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
        // /dev/[u]random are not normal files, so we need to loop the read.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
        // just keep trying as long as we are making progress
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
        private static void readFully(InputStream in, byte[] data)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
                throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
            int len = data.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
            int ofs = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
            while (len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
                int k = in.read(data, ofs, len);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
                if (k <= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
                    throw new EOFException("/dev/[u]random closed?");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
                ofs += k;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
                len -= k;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
            if (len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
                throw new IOException("Could not read from /dev/[u]random");
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
        // get true random bytes, just read from /dev/random
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
        private byte[] implGenerateSeed(int numBytes) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
            synchronized (LOCK_GET_SEED) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
                    byte[] b = new byte[numBytes];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
                    readFully(randomIn, b);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
                    return b;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
                } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
                    throw new ProviderException("generateSeed() failed", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
        // supply random bytes to the OS
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
        // write to /dev/random if possible
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
        // always add the seed to our mixing random
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        private void implSetSeed(byte[] seed) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
            synchronized (LOCK_SET_SEED) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
                if (randomOutInitialized == false) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
                    randomOutInitialized = true;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
                    randomOut = AccessController.doPrivileged(
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
                            new PrivilegedAction<OutputStream>() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
                        public OutputStream run() {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
                            try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
                                return new FileOutputStream(NAME_RANDOM, true);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
                            } catch (Exception e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
                                return null;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
                            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
                    });
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
                if (randomOut != null) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
                    try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
                        randomOut.write(seed);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
                    } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
                        throw new ProviderException("setSeed() failed", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
                getMixRandom().engineSetSeed(seed);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
        // ensure that there is at least one valid byte in the buffer
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
        // if not, read new bytes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
        private void ensureBufferValid() throws IOException {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
            long time = System.currentTimeMillis();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
            if ((buffered > 0) && (time - lastRead < MAX_BUFFER_TIME)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
                return;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
            lastRead = time;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
            readFully(urandomIn, urandomBuffer);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
            buffered = urandomBuffer.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
        // get pseudo random bytes
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
        // read from /dev/urandom and XOR with bytes generated by the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
        // mixing SHA1PRNG
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
        private void implNextBytes(byte[] data) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
            synchronized (LOCK_GET_BYTES) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
                try {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
                    getMixRandom().engineNextBytes(data);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
                    int len = data.length;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
                    int ofs = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
                    while (len > 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
                        ensureBufferValid();
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
                        int bufferOfs = urandomBuffer.length - buffered;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
                        while ((len > 0) && (buffered > 0)) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
                            data[ofs++] ^= urandomBuffer[bufferOfs++];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
                            len--;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
                            buffered--;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
                        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
                    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                } catch (IOException e) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
                    throw new ProviderException("nextBytes() failed", e);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
}