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 }