OpenSslCryptoRandom.java

  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. import java.security.GeneralSecurityException;
  20. import java.util.Properties;
  21. import java.util.Random;

  22. import org.apache.commons.crypto.Crypto;

  23. /**
  24.  * <p>
  25.  * OpenSSL secure random using JNI. This implementation is thread-safe.
  26.  * </p>
  27.  *
  28.  * <p>
  29.  * 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
  30.  * is unavailable, default OpenSSL secure random generator will be used. It's still faster and can generate strong random bytes.
  31.  * </p>
  32.  * <p>
  33.  * This class is not public/protected so does not appear in the main Javadoc Please ensure that property use is documented in the enum
  34.  * CryptoRandomFactory.RandomProvider
  35.  * </p>
  36.  *
  37.  * @see <a href="https://wiki.openssl.org/index.php/Random_Numbers"> https://wiki.openssl.org/index.php/Random_Numbers</a>
  38.  * @see <a href="http://en.wikipedia.org/wiki/RdRand"> http://en.wikipedia.org/wiki/RdRand</a>
  39.  */
  40. final class OpenSslCryptoRandom implements CryptoRandom {

  41.     private static final boolean nativeEnabled;

  42.     private static final Throwable initException;

  43.     static {
  44.         boolean opensslLoaded = false;
  45.         Throwable except = null;
  46.         if (Crypto.isNativeCodeLoaded()) {
  47.             try {
  48.                 OpenSslCryptoRandomNative.initSR();
  49.                 opensslLoaded = true;
  50.             } catch (final Exception | UnsatisfiedLinkError e) {
  51.                 except = e;
  52.             }
  53.         }
  54.         nativeEnabled = opensslLoaded;
  55.         initException = except;
  56.         //
  57.         // Check that nextRandBytes works (is this really needed?)
  58.         try {
  59.             checkNative();
  60.         } catch (final GeneralSecurityException e) {
  61.             throw new IllegalStateException(e);
  62.         }
  63.         if (!OpenSslCryptoRandomNative.nextRandBytes(new byte[1])) {
  64.             throw new IllegalStateException("Check of nextRandBytes failed");
  65.         }
  66.     }

  67.     private static void checkNative() throws GeneralSecurityException {
  68.         if (!nativeEnabled) {
  69.             if (initException != null) {
  70.                 throw new GeneralSecurityException("Native library could not be initialized", initException);
  71.             }
  72.             throw new GeneralSecurityException("Native library is not loaded");
  73.         }
  74.     }

  75.     /**
  76.      * Judges whether native library was successfully loaded and initialized.
  77.      *
  78.      * @return true if library was loaded and initialized
  79.      */
  80.     public static boolean isNativeCodeEnabled() {
  81.         return nativeEnabled;
  82.     }

  83.     /**
  84.      * Constructs a {@link OpenSslCryptoRandom}.
  85.      *
  86.      * @param props the configuration properties - not used
  87.      * @throws GeneralSecurityException if the native library could not be initialized successfully
  88.      */
  89.     public OpenSslCryptoRandom(final Properties props) throws GeneralSecurityException { // NOPMD
  90.         checkNative();
  91.     }

  92.     /**
  93.      * Overrides {@link java.lang.AutoCloseable#close()}.
  94.      * Does nothing.
  95.      */
  96.     @Override
  97.     public void close() {
  98.         // noop
  99.     }

  100.     /**
  101.      * Generates a user-specified number of random bytes. It's thread-safe.
  102.      * Overrides {@link Random}.
  103.      *
  104.      * @param bytes the array to be filled in with random bytes.
  105.      */
  106.     @Override
  107.     public void nextBytes(final byte[] bytes) {
  108.         // Constructor ensures that native is enabled here
  109.         if (!OpenSslCryptoRandomNative.nextRandBytes(bytes)) {
  110.             // Assume it's a problem with the argument, rather than an internal issue
  111.             throw new IllegalArgumentException("The nextRandBytes method failed");
  112.         }
  113.     }

  114. }