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 }