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  
26  /**
27   * <p>
28   * OpenSSL secure random using JNI. This implementation is thread-safe.
29   * </p>
30   *
31   * <p>
32   * If using an Intel chipset with RDRAND, the high-performance hardware random number generator will be used and it's much faster than SecureRandom. If RDRAND
33   * is unavailable, default OpenSSL secure random generator will be used. It's still faster and can generate strong random bytes.
34   * </p>
35   * <p>
36   * This class is not public/protected so does not appear in the main Javadoc Please ensure that property use is documented in the enum
37   * CryptoRandomFactory.RandomProvider
38   * </p>
39   *
40   * @see <a href="https://wiki.openssl.org/index.php/Random_Numbers"> https://wiki.openssl.org/index.php/Random_Numbers</a>
41   * @see <a href="http://en.wikipedia.org/wiki/RdRand"> http://en.wikipedia.org/wiki/RdRand</a>
42   */
43  final class OpenSslCryptoRandom implements CryptoRandom {
44  
45      private static final boolean nativeEnabled;
46  
47      private static final Throwable initException;
48  
49      static {
50          boolean opensslLoaded = false;
51          Throwable except = null;
52          if (Crypto.isNativeCodeLoaded()) {
53              try {
54                  OpenSslCryptoRandomNative.initSR();
55                  opensslLoaded = true;
56              } catch (final Exception | UnsatisfiedLinkError e) {
57                  except = e;
58              }
59          }
60          nativeEnabled = opensslLoaded;
61          initException = except;
62          //
63          // Check that nextRandBytes works (is this really needed?)
64          try {
65              checkNative();
66          } catch (final GeneralSecurityException e) {
67              throw new IllegalStateException(e);
68          }
69          if (!OpenSslCryptoRandomNative.nextRandBytes(new byte[1])) {
70              throw new IllegalStateException("Check of nextRandBytes failed");
71          }
72      }
73  
74      private static void checkNative() throws GeneralSecurityException {
75          if (!nativeEnabled) {
76              if (initException != null) {
77                  throw new GeneralSecurityException("Native library could not be initialized", initException);
78              }
79              throw new GeneralSecurityException("Native library is not loaded");
80          }
81      }
82  
83      /**
84       * Judges whether native library was successfully loaded and initialized.
85       *
86       * @return true if library was loaded and initialized
87       */
88      public static boolean isNativeCodeEnabled() {
89          return nativeEnabled;
90      }
91  
92      /**
93       * Constructs a {@link OpenSslCryptoRandom}.
94       *
95       * @param props the configuration properties - not used
96       * @throws GeneralSecurityException if the native library could not be initialized successfully
97       */
98      public OpenSslCryptoRandom(final Properties props) throws GeneralSecurityException { // NOPMD
99          checkNative();
100     }
101 
102     /**
103      * Overrides {@link java.lang.AutoCloseable#close()}.
104      * Does nothing.
105      */
106     @Override
107     public void close() {
108         // noop
109     }
110 
111     /**
112      * Generates a user-specified number of random bytes. It's thread-safe.
113      * Overrides {@link Random}.
114      *
115      * @param bytes the array to be filled in with random bytes.
116      */
117     @Override
118     public void nextBytes(final byte[] bytes) {
119         // Constructor ensures that native is enabled here
120         if (!OpenSslCryptoRandomNative.nextRandBytes(bytes)) {
121             // Assume it's a problem with the argument, rather than an internal issue
122             throw new IllegalArgumentException("The nextRandBytes method failed");
123         }
124     }
125 
126 }