| /* |
| * 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. |
| */ |
| |
| #include "SecureRandomImpl.h" |
| |
| #include <decaf/lang/Exception.h> |
| #include <decaf/lang/exceptions/RuntimeException.h> |
| #include <decaf/lang/exceptions/NullPointerException.h> |
| #include <decaf/lang/exceptions/IllegalArgumentException.h> |
| #include <decaf/util/Random.h> |
| |
| #include <decaf/internal/AprPool.h> |
| |
| #include <memory> |
| #include <apr_file_io.h> |
| |
| using namespace decaf; |
| using namespace decaf::lang; |
| using namespace decaf::lang::exceptions; |
| using namespace decaf::util; |
| using namespace decaf::security; |
| using namespace decaf::internal; |
| using namespace decaf::internal::security; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| namespace decaf { |
| namespace internal { |
| namespace security { |
| |
| class SRNGData { |
| private: |
| |
| SRNGData( const SRNGData& ); |
| SRNGData operator= ( const SRNGData& ); |
| |
| public: |
| |
| AprPool pool; |
| apr_file_t* randFile; |
| std::auto_ptr<Random> random; |
| |
| SRNGData() : pool(), randFile( NULL ), random() { |
| } |
| |
| }; |
| |
| }}} |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| SecureRandomImpl::SecureRandomImpl() : config( new SRNGData() ) { |
| |
| try{ |
| |
| const char* files[] = { "/dev/urandom", "/dev/random" }; |
| int index = 0; |
| apr_status_t result = APR_SUCCESS; |
| |
| do { |
| // Attempt to find an OS source for secure random bytes. |
| result = apr_file_open( &config->randFile, files[index++], |
| APR_READ, APR_OS_DEFAULT, |
| config->pool.getAprPool() ); |
| } while( index < 2 && result != APR_SUCCESS ); |
| |
| // Defaults to the Decaf version. |
| if( result != APR_SUCCESS ) { |
| this->config->random.reset( new Random() ); |
| } |
| } |
| DECAF_CATCH_RETHROW( Exception ) |
| DECAF_CATCHALL_THROW( Exception ) |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| SecureRandomImpl::~SecureRandomImpl() { |
| try{ |
| delete this->config; |
| } |
| DECAF_CATCH_NOTHROW( Exception ) |
| DECAF_CATCHALL_NOTHROW() |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SecureRandomImpl::providerSetSeed( const unsigned char* seed, int size ) { |
| |
| // Only seed the default random, the other sources don't need a seed. |
| if( this->config->random.get() != NULL ) { |
| |
| for( int i = 0; i < size; i++ ) { |
| this->config->random->setSeed( (long long)seed[i] ); |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void SecureRandomImpl::providerNextBytes( unsigned char* bytes, int numBytes ) { |
| |
| if( bytes == NULL ) { |
| throw NullPointerException( |
| __FILE__, __LINE__, "Byte Buffer passed cannot be NULL." ); |
| } |
| |
| if( numBytes < 0 ) { |
| throw IllegalArgumentException( |
| __FILE__, __LINE__, "Number of bytes to read was negative: %d", numBytes ); |
| } |
| |
| if( this->config->randFile != NULL ) { |
| |
| apr_status_t result = APR_EOF; |
| apr_size_t bytesRead = 0; |
| |
| // Instruct APR to read it all. |
| result = apr_file_read_full( this->config->randFile, (void*)bytes, numBytes, &bytesRead ); |
| |
| // Since the dev random files are special OS random sources we should never get |
| // an EOF or other error, if so its bad. |
| if( result != APR_SUCCESS ) { |
| throw RuntimeException( |
| __FILE__, __LINE__, |
| "Unexpected error while reading random bytes from system resources." ); |
| } |
| |
| } else { |
| this->config->random->nextBytes( bytes, numBytes ); |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| unsigned char* SecureRandomImpl::providerGenerateSeed( int numBytes ) { |
| |
| if( numBytes == 0 ) { |
| return NULL; |
| } |
| |
| unsigned char* buffer = new unsigned char[numBytes]; |
| providerNextBytes( buffer, numBytes ); |
| return buffer; |
| } |