All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.crypto.jna.OpenSslJnaCryptoRandom Maven / Gradle / Ivy

 /*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.crypto.jna;

import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;

import org.apache.commons.crypto.random.CryptoRandom;

import com.sun.jna.NativeLong;
import com.sun.jna.ptr.PointerByReference;

/**
 * 

* OpenSSL secure random using JNA. This implementation is thread-safe. *

* *

* 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 is unavailable, default OpenSSL secure random generator will be used. * It's still faster and can generate strong random bytes. *

* * @see * https://wiki.openssl.org/index.php/Random_Numbers * @see * http://en.wikipedia.org/wiki/RdRand */ final class OpenSslJnaCryptoRandom implements CryptoRandom { private static final int ENGINE_METHOD_RAND = 0x0008; private final boolean rdrandEnabled; private final transient PointerByReference rdrandEngine; /** * Constructs a {@link OpenSslJnaCryptoRandom}. * * @param props the configuration properties (not used) * @throws GeneralSecurityException if could not enable JNA access */ public OpenSslJnaCryptoRandom(final Properties props) //NOPMD throws GeneralSecurityException { if (!OpenSslJna.isEnabled()) { throw new GeneralSecurityException("Could not enable JNA access", OpenSslJna.initialisationError()); } boolean rdrandLoaded = false; try { OpenSslNativeJna.ENGINE_load_rdrand(); rdrandEngine = OpenSslNativeJna.ENGINE_by_id("rdrand"); if (rdrandEngine != null) { final int rc = OpenSslNativeJna.ENGINE_init(rdrandEngine); if (rc != 0) { final int rc2 = OpenSslNativeJna.ENGINE_set_default(rdrandEngine, ENGINE_METHOD_RAND); if (rc2 != 0) { rdrandLoaded = true; } } } } catch (final Exception e) { throw new NoSuchAlgorithmException(); } rdrandEnabled = rdrandLoaded; if (!rdrandLoaded) { closeRdrandEngine(false); } } /** * Overrides {@link java.lang.AutoCloseable#close()}. Closes OpenSSL context * if native enabled. */ @Override public void close() { closeRdrandEngine(true); OpenSslNativeJna.ENGINE_cleanup(); //cleanup locks //OpenSslNativeJna.CRYPTO_set_locking_callback(null); //LOCK.unlock(); } /** * Closes the rdrand engine. * @param closing true when called while closing. */ private void closeRdrandEngine(final boolean closing) { if (rdrandEngine != null) { throwOnError(OpenSslNativeJna.ENGINE_finish(rdrandEngine), closing); throwOnError(OpenSslNativeJna.ENGINE_free(rdrandEngine), closing); } } /** * Checks if rdrand engine is used to retrieve random bytes * * @return true if rdrand is used, false if default engine is used */ public boolean isRdrandEnabled() { return rdrandEnabled; } /** * Generates a user-specified number of random bytes. It's thread-safe. * * @param bytes the array to be filled in with random bytes. */ @Override public void nextBytes(final byte[] bytes) { synchronized (OpenSslJnaCryptoRandom.class) { // this method is synchronized for now // to support multithreading https://wiki.openssl.org/index.php/Manual:Threads(3) needs to be done if (rdrandEnabled && OpenSslNativeJna.RAND_get_rand_method().equals(OpenSslNativeJna.RAND_SSLeay())) { close(); throw new IllegalStateException("rdrand should be used but default is detected"); } final int byteLength = bytes.length; final ByteBuffer buf = ByteBuffer.allocateDirect(byteLength); throwOnError(OpenSslNativeJna.RAND_bytes(buf, byteLength), false); buf.rewind(); buf.get(bytes, 0, byteLength); } } /** * @param retVal the result value of error. * @param closing true when called while closing. */ private void throwOnError(final int retVal, final boolean closing) { if (retVal != 1) { final NativeLong err = OpenSslNativeJna.ERR_peek_error(); final String errdesc = OpenSslNativeJna.ERR_error_string(err, null); if (!closing) { close(); } throw new IllegalStateException("return code " + retVal + " from OpenSSL. Err code is " + err + ": " + errdesc); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy