View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.commons.crypto.random;
19  
20  import java.security.GeneralSecurityException;
21  import java.util.Properties;
22  import java.util.Random;
23  
24  import org.apache.commons.crypto.Crypto;
25  import org.apache.commons.crypto.utils.Utils;
26  
27  /**
28   * <p>
29   * OpenSSL secure random using JNI. This implementation is thread-safe.
30   * </p>
31   *
32   * <p>
33   * If using an Intel chipset with RDRAND, the high-performance hardware random
34   * number generator will be used and it's much faster than SecureRandom. If
35   * RDRAND is unavailable, default OpenSSL secure random generator will be used.
36   * It's still faster and can generate strong random bytes.
37   * </p>
38   *
39   * @see <a href="https://wiki.openssl.org/index.php/Random_Numbers">
40   *      https://wiki.openssl.org/index.php/Random_Numbers</a>
41   * @see <a href="http://en.wikipedia.org/wiki/RdRand">
42   *      http://en.wikipedia.org/wiki/RdRand</a>;
43   */
44  class OpenSslCryptoRandom extends Random implements CryptoRandom {
45      private static final long serialVersionUID = -7828193502768789584L;
46  
47      private static final boolean nativeEnabled;
48  
49      private static final Throwable initException;
50  
51      static {
52          boolean opensslLoaded = false;
53          Throwable except = null;
54          if (Crypto.isNativeCodeLoaded()) {
55              try {
56                  OpenSslCryptoRandomNative.initSR();
57                  opensslLoaded = true;
58              } catch (Exception t) {
59                  except = t;
60              } catch (UnsatisfiedLinkError t) {
61                  except = t;
62              }
63          }
64          nativeEnabled = opensslLoaded;
65          initException = except;
66      }
67  
68      /**
69       * Judges whether native library was successfully loaded and initialised.
70       *
71       * @return true if library was loaded and initialised
72       */
73      public static boolean isNativeCodeEnabled() {
74          return nativeEnabled;
75      }
76  
77      /**
78       * Constructs a {@link OpenSslCryptoRandom}.
79       *
80       * @param props the configuration properties - not used
81       * @throws GeneralSecurityException if the native library could not be initialised successfully
82       */
83      // N.B. this class is not public/protected so does not appear in the main Javadoc
84      // Please ensure that property use is documented in the enum CryptoRandomFactory.RandomProvider
85      public OpenSslCryptoRandom(Properties props) throws GeneralSecurityException { // NOPMD
86          if (!nativeEnabled) {
87              if (initException != null) {
88                  throw new GeneralSecurityException("Native library could not be initialised", initException);
89              }
90              throw new GeneralSecurityException("Native library is not loaded");
91          }
92          // Check that nextRandBytes works (is this really needed?)
93          if (!OpenSslCryptoRandomNative.nextRandBytes(new byte[1])) {
94              throw new GeneralSecurityException("Check of nextRandBytes failed");
95          }
96      }
97  
98      /**
99       * Generates a user-specified number of random bytes. It's thread-safe.
100      *
101      * @param bytes the array to be filled in with random bytes.
102      */
103     @Override
104     public void nextBytes(byte[] bytes) {
105         // Constructor ensures that native is enabled here
106         if (!OpenSslCryptoRandomNative.nextRandBytes(bytes)) {
107             // Assume it's a problem with the argument, rather than an internal issue
108             throw new IllegalArgumentException("The nextRandBytes method failed");
109         }
110     }
111 
112     /**
113      * Overrides {@link OpenSslCryptoRandom}. For {@link OpenSslCryptoRandom},
114      * we don't need to set seed.
115      *
116      * @param seed the initial seed.
117      */
118     @Override
119     public void setSeed(long seed) {
120         // Self-seeding.
121     }
122 
123     /**
124      * Overrides Random#next(). Generates an integer containing the
125      * user-specified number of random bits(right justified, with leading
126      * zeros).
127      *
128      * @param numBits number of random bits to be generated, where 0
129      *        {@literal <=} <code>numBits</code> {@literal <=} 32.
130      * @return int an <code>int</code> containing the user-specified number of
131      *         random bits (right justified, with leading zeros).
132      */
133     @Override
134     final protected int next(int numBits) {
135         Utils.checkArgument(numBits >= 0 && numBits <= 32);
136         int numBytes = (numBits + 7) / 8;
137         byte b[] = new byte[numBytes];
138         int next = 0;
139 
140         nextBytes(b);
141         for (int i = 0; i < numBytes; i++) {
142             next = (next << 8) + (b[i] & 0xFF);
143         }
144 
145         return next >>> (numBytes * 8 - numBits);
146     }
147 
148     /**
149      * Overrides {@link java.lang.AutoCloseable#close()}.
150      * Does nothing.
151      */
152     @Override
153     public void close() {
154     }
155 }