osrng.cpp

00001 // osrng.cpp - written and placed in the public domain by Wei Dai
00002 
00003 // Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.
00004 
00005 #include "pch.h"
00006 
00007 #ifndef CRYPTOPP_IMPORTS
00008 
00009 #include "osrng.h"
00010 
00011 #ifdef OS_RNG_AVAILABLE
00012 
00013 #include "rng.h"
00014 
00015 #ifdef CRYPTOPP_WIN32_AVAILABLE
00016 #ifndef _WIN32_WINNT
00017 #define _WIN32_WINNT 0x0400
00018 #endif
00019 #include <windows.h>
00020 #include <wincrypt.h>
00021 #endif
00022 
00023 #ifdef CRYPTOPP_UNIX_AVAILABLE
00024 #include <errno.h>
00025 #include <fcntl.h>
00026 #include <unistd.h>
00027 #endif
00028 
00029 NAMESPACE_BEGIN(CryptoPP)
00030 
00031 #if defined(NONBLOCKING_RNG_AVAILABLE) || defined(BLOCKING_RNG_AVAILABLE)
00032 OS_RNG_Err::OS_RNG_Err(const std::string &operation)
00033         : Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " + 
00034 #ifdef CRYPTOPP_WIN32_AVAILABLE
00035                 "0x" + IntToString(GetLastError(), 16)
00036 #else
00037                 IntToString(errno)
00038 #endif
00039                 )
00040 {
00041 }
00042 #endif
00043 
00044 #ifdef NONBLOCKING_RNG_AVAILABLE
00045 
00046 #ifdef CRYPTOPP_WIN32_AVAILABLE
00047 
00048 MicrosoftCryptoProvider::MicrosoftCryptoProvider()
00049 {
00050         if(!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
00051                 throw OS_RNG_Err("CryptAcquireContext");
00052 }
00053 
00054 MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
00055 {
00056         CryptReleaseContext(m_hProvider, 0);
00057 }
00058 
00059 #endif
00060 
00061 NonblockingRng::NonblockingRng()
00062 {
00063 #ifndef CRYPTOPP_WIN32_AVAILABLE
00064         m_fd = open("/dev/urandom",O_RDONLY);
00065         if (m_fd == -1)
00066                 throw OS_RNG_Err("open /dev/urandom");
00067 #endif
00068 }
00069 
00070 NonblockingRng::~NonblockingRng()
00071 {
00072 #ifndef CRYPTOPP_WIN32_AVAILABLE
00073         close(m_fd);
00074 #endif
00075 }
00076 
00077 byte NonblockingRng::GenerateByte()
00078 {
00079         byte b;
00080         GenerateBlock(&b, 1);
00081         return b;
00082 }
00083 
00084 void NonblockingRng::GenerateBlock(byte *output, size_t size)
00085 {
00086 #ifdef CRYPTOPP_WIN32_AVAILABLE
00087 #       ifdef WORKAROUND_MS_BUG_Q258000
00088                 static MicrosoftCryptoProvider m_Provider;
00089 #       endif
00090         if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
00091                 throw OS_RNG_Err("CryptGenRandom");
00092 #else
00093         if (read(m_fd, output, size) != size)
00094                 throw OS_RNG_Err("read /dev/urandom");
00095 #endif
00096 }
00097 
00098 #endif
00099 
00100 // *************************************************************
00101 
00102 #ifdef BLOCKING_RNG_AVAILABLE
00103 
00104 #ifndef CRYPTOPP_BLOCKING_RNG_FILENAME
00105 #ifdef __OpenBSD__
00106 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/srandom"
00107 #else
00108 #define CRYPTOPP_BLOCKING_RNG_FILENAME "/dev/random"
00109 #endif
00110 #endif
00111 
00112 BlockingRng::BlockingRng()
00113 {
00114         m_fd = open(CRYPTOPP_BLOCKING_RNG_FILENAME,O_RDONLY);
00115         if (m_fd == -1)
00116                 throw OS_RNG_Err("open " CRYPTOPP_BLOCKING_RNG_FILENAME);
00117 }
00118 
00119 BlockingRng::~BlockingRng()
00120 {
00121         close(m_fd);
00122 }
00123 
00124 byte BlockingRng::GenerateByte()
00125 {
00126         byte b;
00127         GenerateBlock(&b, 1);
00128         return b;
00129 }
00130 
00131 void BlockingRng::GenerateBlock(byte *output, size_t size)
00132 {
00133         while (size)
00134         {
00135                 // on some systems /dev/random will block until all bytes
00136                 // are available, on others it will returns immediately
00137                 ssize_t len = read(m_fd, output, size);
00138                 if (len < 0)
00139                         throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
00140                 size -= len;
00141                 output += len;
00142                 if (size)
00143                         sleep(1);
00144         }
00145 }
00146 
00147 #endif
00148 
00149 // *************************************************************
00150 
00151 void OS_GenerateRandomBlock(bool blocking, byte *output, size_t size)
00152 {
00153 #ifdef NONBLOCKING_RNG_AVAILABLE
00154         if (blocking)
00155 #endif
00156         {
00157 #ifdef BLOCKING_RNG_AVAILABLE
00158                 BlockingRng rng;
00159                 rng.GenerateBlock(output, size);
00160 #endif
00161         }
00162 
00163 #ifdef BLOCKING_RNG_AVAILABLE
00164         if (!blocking)
00165 #endif
00166         {
00167 #ifdef NONBLOCKING_RNG_AVAILABLE
00168                 NonblockingRng rng;
00169                 rng.GenerateBlock(output, size);
00170 #endif
00171         }
00172 }
00173 
00174 void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
00175 {
00176         SecByteBlock seed(seedSize);
00177         OS_GenerateRandomBlock(blocking, seed, seedSize);
00178         Put(seed, seedSize);
00179 }
00180 
00181 NAMESPACE_END
00182 
00183 #endif
00184 
00185 #endif

Generated on Sat Dec 23 02:07:08 2006 for Crypto++ by  doxygen 1.5.1-p1