/* * Copyright (c) 1998, 1999, 2000, 2001, 2002 Virtual Unlimited B.V. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /*!\file entropy.c * \author Bob Deblier * \ingroup ES_m ES_audio_m ES_dsp_m ES_random_m ES_urandom_m ES_tty_m */ #define BEECRYPT_DLL_EXPORT #include "system.h" #include "entropy.h" #include "endianness.h" #if WIN32 # include # include # include #else # if HAVE_SYS_IOCTL_H # include # endif # if HAVE_SYS_AUDIOIO_H # include # endif # if HAVE_SYS_SOUNDCARD_H # include # endif # if HAVE_TERMIOS_H # include # elif HAVE_TERMIO_H # include # endif # if HAVE_SYNCH_H # include # elif HAVE_PTHREAD_H # include # endif # if HAVE_AIO_H # include # if defined(__LCLINT__) /*@-declundef -exportheader -incondefs -constuse -warnmissingglobs @*/ extern int /*@unused@*/ nanosleep (const struct timespec *__requested_time, /*@out@*/ /*@null@*/ struct timespec *__remaining) /*@modifies *__remaining, errno @*/; extern void aio_init (const struct aioinit *__init) /*@*/; extern int aio_read (struct aiocb *__aiocbp) /*@modifies errno, fileSystem, systemState @*/; extern int aio_write (struct aiocb *__aiocbp) /*@modifies errno, fileSystem, systemState @*/; extern int lio_listio (int __mode, struct aiocb *const __list[], int __nent, struct sigevent *__sig) /*@modifies errno, fileSystem, systemState @*/; extern int aio_error (const struct aiocb *__aiocbp) /*@modifies errno @*/; extern __ssize_t aio_return (struct aiocb *__aiocbp) /*@modifies errno, systemState @*/; extern int aio_cancel (int __fildes, /*@null@*/ struct aiocb *__aiocbp) /*@modifies errno, systemState @*/; extern int aio_suspend (/*@out@*/ const struct aiocb *const __list[], int __nent, /*@out@*/ const struct timespec *__timeout) /*@modifies errno, systemState @*/; extern int aio_fsync (int __operation, struct aiocb *__aiocbp) /*@modifies errno, fileSystem, systemState @*/; /*@constant int AIO_CANCELED@*/ /*@constant int AIO_NOTCANCELED@*/ /*@constant int AIO_ALLDONE@*/ /*@constant int LIO_READ@*/ /*@constant int LIO_WRITE@*/ /*@constant int LIO_NOP@*/ /*@constant int LIO_WAIT@*/ /*@constant int LIO_NOWAIT@*/ /*@constant int SIGEV_SIGNAL@*/ /*@constant int SIGEV_NONE@*/ /*@constant int SIGEV_THREAD@*/ /*@=declundef =exportheader =incondefs =constuse =warnmissingglobs @*/ # endif # endif #endif #include "debug.h" #if WIN32 static HINSTANCE entropy_instance = (HINSTANCE) 0; static HANDLE entropy_wavein_lock; static HANDLE entropy_wavein_event; int entropy_provider_setup(HINSTANCE hInst) { if (!entropy_instance) { entropy_instance = hInst; if (!(entropy_wavein_lock = CreateMutex(NULL, FALSE, NULL))) return -1; if (!(entropy_wavein_event = CreateEvent(NULL, FALSE, FALSE, NULL))) return -1; } return 0; } int entropy_provider_cleanup() { if (entropy_wavein_lock) { CloseHandle(entropy_wavein_lock); entropy_wavein_lock = 0; } if (entropy_wavein_event) { CloseHandle(entropy_wavein_event); entropy_wavein_event = 0; } return 0; } #endif #if WIN32 || HAVE_DEV_AUDIO || HAVE_DEV_DSP /** \ingroup ES_audio_m ES_dsp_m * Mask the low-order bit of a bunch of sound samples, analyze them and * return an error in case they are all zeroes or ones. */ static int entropy_noise_filter(void* sampledata, unsigned samplecount, int samplesize, int channels, int swap) /*@globals errno @*/ /*@modifies sampledata, errno @*/ { register int rc = 0; register unsigned i; switch (samplesize) { case 1: { uint8_t* samples = (uint8_t*) sampledata; switch (channels) { case 1: { int zero_count = 0; int ones_count = 0; for (i = 0; i < samplecount; i++) { if ((samples[i] & 0x1) != 0) ones_count++; else zero_count++; } if ((zero_count == 0) || (ones_count == 0)) { #if HAVE_ERRNO_H errno = EIO; #endif rc = -1; } } /*@innerbreak@*/ break; case 2: { int zero_count_left = 0; int ones_count_left = 0; int zero_count_right = 0; int ones_count_right = 0; for (i = 0; i < samplecount; i++) { if (i & 1U) { if ((samples[i] & 0x1) != 0) ones_count_left++; else zero_count_left++; } else { if ((samples[i] & 0x1) != 0) ones_count_right++; else zero_count_right++; } } if ((zero_count_left == 0) || (ones_count_left == 0) || (zero_count_right == 0) || (ones_count_right == 0)) { #if HAVE_ERRNO_H errno = EIO; #endif rc = -1; } } /*@innerbreak@*/ break; default: #if HAVE_ERRNO_H errno = EINVAL; #endif rc = -1; } } break; case 2: { uint16_t* samples = (uint16_t*) sampledata; switch (channels) { case 1: { int zero_count = 0; int ones_count = 0; for (i = 0; i < samplecount; i++) { if (swap) samples[i] = swapu16(samples[i]); if ((samples[i] & 0x1) != 0) ones_count++; else zero_count++; } if ((zero_count == 0) || (ones_count == 0)) { #if HAVE_ERRNO_H errno = EIO; #endif rc = -1; } } /*@innerbreak@*/ break; case 2: { int zero_count_left = 0; int ones_count_left = 0; int zero_count_right = 0; int ones_count_right = 0; for (i = 0; i < samplecount; i++) { if (swap) samples[i] = swapu16(samples[i]); if (i & 1) { if ((samples[i] & 0x1) != 0) ones_count_left++; else zero_count_left++; } else { if ((samples[i] & 0x1) != 0) ones_count_right++; else zero_count_right++; } } if ((zero_count_left == 0) || (ones_count_left == 0) || (zero_count_right == 0) || (ones_count_right == 0)) { #if HAVE_ERRNO_H errno = EIO; #endif rc = -1; } } /*@innerbreak@*/ break; default: #if HAVE_ERRNO_H errno = EINVAL; #endif rc = -1; /*@innerbreak@*/ break; } } break; default: #if HAVE_ERRNO_H errno = EINVAL; #endif rc = -1; break; } return 0; } /** * Bit deskewing technique: the classical Von Neumann method. * - only use the lsb bit of every sample * - there is a chance of bias in 0 or 1 bits, so to deskew this: * - look at two successive sampled bits * - if they are the same, discard them * - if they are different, they're either 0-1 or 1-0; use the first bit of the pair as output */ #if WIN32 static int entropy_noise_gather(HWAVEIN wavein, int samplesize, int channels, int swap, int timeout, byte* data, size_t size) #else /*@-mustmod@*/ /* data is modified, annotations incorrect */ static int entropy_noise_gather(int fd, int samplesize, int channels, int swap, /*@unused@*/ int timeout, /*@out@*/ byte* data, size_t size) /*@globals errno, fileSystem @*/ /*@modifies *data, errno, fileSystem @*/ #endif { size_t randombits = size << 3; byte temp = 0; int rc, i; byte* sampledata = (byte*) malloc(1024 * samplesize * channels); #if WIN32 WAVEHDR header; /* first set up a wave header */ header.lpData = (LPSTR) sampledata; header.dwBufferLength = 1024 * samplesize * channels; header.dwFlags = 0; /* do error handling! */ waveInStart(wavein); /* the first event is the due to the opening of the wave */ ResetEvent(entropy_wavein_event); #else # if ENABLE_AIO struct aiocb my_aiocb; const struct aiocb* my_aiocb_list = &my_aiocb; # if HAVE_TIME_H struct timespec my_aiocb_timeout; # else # error # endif /*@-nullderef@*/ *sampledata = 0; /*@=nullderef@*/ memset(&my_aiocb, 0, sizeof(struct aiocb)); memset(&my_aiocb_timeout, 0, sizeof(struct timespec)); my_aiocb.aio_fildes = fd; my_aiocb.aio_sigevent.sigev_notify = SIGEV_NONE; # endif #endif if (sampledata == (byte*) 0) { #if HAVE_ERRNO_H errno = ENOMEM; #endif return -1; } /*@-infloops -infloopsuncon -branchstate @*/ while (randombits) { #if WIN32 /* pass the buffer to the wavein and wait for the event */ waveInPrepareHeader(wavein, &header, sizeof(WAVEHDR)); waveInAddBuffer(wavein, &header, sizeof(WAVEHDR)); /* in case we have to wait more than the specified timeout, bail out */ if (WaitForSingleObject(entropy_wavein_event, timeout) == WAIT_OBJECT_0) { rc = header.dwBytesRecorded; } else { waveInStop(wavein); waveInReset(wavein); free(sampledata); return -1; } #else # if ENABLE_AIO /*@-mustfree@*/ /* my_aiocb.aio_buf is OK */ my_aiocb.aio_buf = sampledata; /*@=mustfree@*/ my_aiocb.aio_nbytes = 1024 * samplesize * channels; rc = aio_read(&my_aiocb); # else rc = read(fd, sampledata, 1024 * samplesize * channels); # endif if (rc < 0) { /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; } # if ENABLE_AIO my_aiocb_timeout.tv_sec = (timeout / 1000); my_aiocb_timeout.tv_nsec = (timeout % 1000) * 1000000; rc = aio_suspend(&my_aiocb_list, 1, &my_aiocb_timeout); if (rc < 0) { #if HAVE_ERRNO_H if (errno == EAGAIN) { /* certain linux glibc versions are buggy and don't aio_suspend properly */ (void) nanosleep(&my_aiocb_timeout, (struct timespec*) 0); my_aiocb_timeout.tv_sec = (timeout / 1000); my_aiocb_timeout.tv_nsec = (timeout % 1000) * 1000000; /* and try again */ rc = aio_suspend(&my_aiocb_list, 1, &my_aiocb_timeout); } #endif } if (rc < 0) { /* cancel any remaining reads */ while (rc != AIO_ALLDONE) { rc = aio_cancel(fd, (struct aiocb*) 0); if (rc == AIO_NOTCANCELED) { my_aiocb_timeout.tv_sec = (timeout / 1000); my_aiocb_timeout.tv_nsec = (timeout % 1000) * 1000000; (void) nanosleep(&my_aiocb_timeout, (struct timespec*) 0); } if (rc < 0) /*@innerbreak@*/ break; } /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; } rc = aio_error(&my_aiocb); if (rc) { /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; } rc = aio_return(&my_aiocb); if (rc < 0) { /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; } # endif #endif /*@-type@*/ if (entropy_noise_filter(sampledata, rc / samplesize, samplesize, channels, swap) < 0) /*@=type@*/ { fprintf(stderr, "noise filter indicates too much bias in audio samples\n"); /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; } switch (samplesize) { case 1: { uint8_t* samples = (uint8_t*) sampledata; for (i = 0; randombits && (i < 1024); i += 2) { if ((samples[i] ^ samples[i+1]) != 0) { temp <<= 1; temp |= samples[i]; randombits--; if (!(randombits & 0x1f)) *(data++) = temp; } } } /*@switchbreak@*/ break; case 2: { uint16_t* samples = (uint16_t*) sampledata; for (i = 0; randombits && (i < 1024); i += 2) { if (samples[i] ^ samples[i+1]) { temp <<= 1; temp |= samples[i]; randombits--; if (!(randombits & 0x7)) *(data++) = temp; } } } /*@switchbreak@*/ break; default: /*@-kepttrans@*/ free(sampledata); /*@=kepttrans@*/ return -1; /*@notreached@*/ /*@switchbreak@*/ break; } } /*@=infloops =infloopsuncon =branchstate @*/ #if WIN32 waveInStop(wavein); waveInReset(wavein); #endif /*@-usereleased -kepttrans@*/ free(sampledata); /*@=usereleased =kepttrans@*/ return 0; } /*@=mustmod@*/ #endif #if WIN32 int entropy_wavein(byte* data, size_t size) { const char *timeout_env = getenv("BEECRYPT_ENTROPY_WAVEIN_TIMEOUT"); WAVEINCAPS waveincaps; WAVEFORMATEX waveformatex; HWAVEIN wavein; MMRESULT rc; rc = waveInGetDevCaps(WAVE_MAPPER, &waveincaps, sizeof(WAVEINCAPS)); if (rc != MMSYSERR_NOERROR) return -1; /* first go for the 16 bits samples -> more chance of noise bits */ switch (waveformatex.nChannels = waveincaps.wChannels) { case 1: /* mono */ if (waveincaps.dwFormats & WAVE_FORMAT_4M16) { waveformatex.nSamplesPerSec = 44100; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_2M16) { waveformatex.nSamplesPerSec = 22050; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_1M16) { waveformatex.nSamplesPerSec = 11025; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_4M08) { waveformatex.nSamplesPerSec = 44100; waveformatex.wBitsPerSample = 8; } else if (waveincaps.dwFormats & WAVE_FORMAT_2M08) { waveformatex.nSamplesPerSec = 22050; waveformatex.wBitsPerSample = 8; } else if (waveincaps.dwFormats & WAVE_FORMAT_1M08) { waveformatex.nSamplesPerSec = 11025; waveformatex.wBitsPerSample = 8; } else return -1; break; case 2: /* stereo */ if (waveincaps.dwFormats & WAVE_FORMAT_4S16) { waveformatex.nSamplesPerSec = 44100; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_2S16) { waveformatex.nSamplesPerSec = 22050; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_1S16) { waveformatex.nSamplesPerSec = 11025; waveformatex.wBitsPerSample = 16; } else if (waveincaps.dwFormats & WAVE_FORMAT_4S08) { waveformatex.nSamplesPerSec = 44100; waveformatex.wBitsPerSample = 8; } else if (waveincaps.dwFormats & WAVE_FORMAT_2S08) { waveformatex.nSamplesPerSec = 22050; waveformatex.wBitsPerSample = 8; } else if (waveincaps.dwFormats & WAVE_FORMAT_1S08) { waveformatex.nSamplesPerSec = 11025; waveformatex.wBitsPerSample = 8; } else return -1; break; } waveformatex.wFormatTag = WAVE_FORMAT_PCM; waveformatex.nAvgBytesPerSec = (waveformatex.nSamplesPerSec * waveformatex.nChannels * waveformatex.wBitsPerSample) / 8; waveformatex.nBlockAlign = (waveformatex.nChannels * waveformatex.wBitsPerSample) / 8; waveformatex.cbSize = 0; /* we now have the wavein's capabilities hammered out; from here on we need to lock */ if (WaitForSingleObject(entropy_wavein_lock, INFINITE) != WAIT_OBJECT_0) return -1; rc = waveInOpen(&wavein, WAVE_MAPPER, &waveformatex, (DWORD) entropy_wavein_event, (DWORD) 0, CALLBACK_EVENT); if (rc != MMSYSERR_NOERROR) { fprintf(stderr, "waveInOpen failed!\n"); (void) fflush(stderr); ReleaseMutex(entropy_wavein_lock); return -1; } rc = entropy_noise_gather(wavein, waveformatex.wBitsPerSample >> 3, waveformatex.nChannels, 0, timeout_env ? atoi(timeout_env) : 2000, data, size); waveInClose(wavein); ReleaseMutex(entropy_wavein_lock); return rc; } int entropy_console(byte* data, size_t size) { register size_t randombits = size << 3; HANDLE hStdin; DWORD inRet; INPUT_RECORD inEvent; LARGE_INTEGER hrtsample; hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) { fprintf(stderr, "GetStdHandle error %d\n", GetLastError()); return -1; } printf("please press random keys on your keyboard\n"); (void) fflush(stdout); while (randombits) { if (!ReadConsoleInput(hStdin, &inEvent, 1, &inRet)) { fprintf(stderr, "ReadConsoleInput failed\n"); (void) fflush(stderr); return -1; } if ((inRet == 1) && (inEvent.EventType == KEY_EVENT) && inEvent.Event.KeyEvent.bKeyDown) { printf("."); (void) fflush(stdout); if (!QueryPerformanceCounter(&hrtsample)) { fprintf(stderr, "QueryPerformanceCounter failed\n"); (void) fflush(stderr); return -1; } /* get 8 bits from the sample */ /* discard the 2 lowest bits */ *(data++) = (byte)(hrtsample.LowPart >> 2); randombits -= 8; } } printf("\nthanks\n"); Sleep(1000); if (!FlushConsoleInputBuffer(hStdin)) { fprintf(stderr, "FlushConsoleInputBuffer failed\n"); (void) fflush(stderr); return -1; } return 0; } int entropy_wincrypt(byte* data, size_t size) { HCRYPTPROV hCrypt; DWORD provType = PROV_RSA_FULL; BOOL rc; /* consider using getenv("BEECRYPT_ENTROPY_WINCRYPT_PROVTYPE") to set provType */ if (!CryptAcquireContext(&hCrypt, "BeeCrypt", NULL, provType, 0)) { #if defined(NTE_BAD_KEYSET) if (GetLastError() == NTE_BAD_KEYSET) { if (!CryptAcquireContext(&hCrypt, "BeeCrypt", NULL, provType, CRYPT_NEWKEYSET)) return -1; } else return -1; #else return -1; #endif } rc = CryptGenRandom(hCrypt, size, (BYTE*) data); CryptReleaseContext(hCrypt, 0); return rc ? 0 : -1; } #else #if HAVE_DEV_AUDIO /** \ingroup ES_audio_m */ /*@observer@*/ /*@unchecked@*/ static const char* name_dev_audio = "/dev/audio"; /** \ingroup ES_audio_m */ /*@unchecked@*/ static int dev_audio_fd = -1; /** \ingroup ES_audio_m */ # ifdef _REENTRANT # if HAVE_SYNCH_H /*@unchecked@*/ static mutex_t dev_audio_lock = DEFAULTMUTEX; # elif HAVE_PTHREAD_H /*@unchecked@*/ static pthread_mutex_t dev_audio_lock = PTHREAD_MUTEX_INITIALIZER; # else # error Need locking mechanism # endif # endif #endif #if HAVE_DEV_DSP /** \ingroup ES_dsp_m */ /*@observer@*/ /*@unchecked@*/ static const char* name_dev_dsp = "/dev/dsp"; /** \ingroup ES_dsp_m */ /*@unchecked@*/ static int dev_dsp_fd = -1; /** \ingroup ES_dsp_m */ # ifdef _REENTRANT # if HAVE_SYNCH_H /*@unchecked@*/ static mutex_t dev_dsp_lock = DEFAULTMUTEX; # elif HAVE_PTHREAD_H /*@-type@*/ /*@unchecked@*/ static pthread_mutex_t dev_dsp_lock = PTHREAD_MUTEX_INITIALIZER; /*@=type@*/ # else # error Need locking mechanism # endif # endif #endif #if HAVE_DEV_RANDOM /** \ingroup ES_random_m */ /*@observer@*/ /*@unchecked@*/ static const char* name_dev_random = "/dev/random"; /** \ingroup ES_random_m */ /*@unchecked@*/ static int dev_random_fd = -1; /** \ingroup ES_random_m */ # ifdef _REENTRANT # if HAVE_SYNCH_H /*@unchecked@*/ static mutex_t dev_random_lock = DEFAULTMUTEX; # elif HAVE_PTHREAD_H /*@-type@*/ /*@unchecked@*/ static pthread_mutex_t dev_random_lock = PTHREAD_MUTEX_INITIALIZER; /*@=type@*/ # else # error Need locking mechanism # endif # endif #endif #if HAVE_DEV_URANDOM /** \ingroup ES_urandom_m */ /*@observer@*/ /*@unchecked@*/ static const char* name_dev_urandom = "/dev/urandom"; /** \ingroup ES_urandom_m */ /*@unchecked@*/ static int dev_urandom_fd = -1; /** \ingroup ES_urandom_m */ # ifdef _REENTRANT # if HAVE_SYNCH_H /*@unchecked@*/ static mutex_t dev_urandom_lock = DEFAULTMUTEX; # elif HAVE_PTHREAD_H /*@-type@*/ /*@unchecked@*/ static pthread_mutex_t dev_urandom_lock = PTHREAD_MUTEX_INITIALIZER; /*@=type@*/ # else # error Need locking mechanism # endif # endif #endif #if HAVE_DEV_TTY /** \ingroup ES_tty_m */ /*@observer@*/ /*@unchecked@*/ static const char *dev_tty_name = "/dev/tty"; /** \ingroup ES_tty_m */ /*@unchecked@*/ static int dev_tty_fd = -1; /** \ingroup ES_tty_m * @todo hpux needs real locking mechanism. */ # if defined(_REENTRANT) && !defined(hpux) # if HAVE_SYNCH_H /*@unchecked@*/ static mutex_t dev_tty_lock = DEFAULTMUTEX; # elif HAVE_PTHREAD_H /*@-type@*/ /*@unchecked@*/ static pthread_mutex_t dev_tty_lock = PTHREAD_MUTEX_INITIALIZER; /*@=type@*/ # else # error Need locking mechanism # endif # endif #endif #if HAVE_SYS_STAT_H /** * @param device * @return */ static int statdevice(const char *device) /*@globals fileSystem @*/ /*@modifies fileSystem @*/ { struct stat s; if (stat(device, &s) < 0) { #if HAVE_ERRNO_H && HAVE_STRING_H fprintf(stderr, "cannot stat %s: %s\n", device, strerror(errno)); #endif return -1; } if (!S_ISCHR(s.st_mode)) { fprintf(stderr, "%s is not a device\n", device); return -1; } return 0; } #endif /** * @param device * @return */ static int opendevice(const char *device) /*@globals fileSystem @*/ /*@modifies fileSystem @*/ { register int fd; if ((fd = open(device, O_RDONLY)) < 0) { #if HAVE_ERRNO_H && HAVE_STRING_H fprintf(stderr, "open of %s failed: %s\n", device, strerror(errno)); #endif return fd; } return fd; } #if HAVE_DEV_RANDOM || HAVE_DEV_URANDOM /** \ingroup ES_random_m ES_urandom_m * @param fd * @param timeout in milliseconds * @retval data * @param size * @return */ static int entropy_randombits(int fd, /*@unused@*/ int timeout, /*@out@*/ byte* data, size_t size) /*@modifies *data @*/ { register int rc; #if ENABLE_AIO struct aiocb my_aiocb; const struct aiocb* my_aiocb_list = &my_aiocb; # if HAVE_TIME_H struct timespec my_aiocb_timeout; # else # error # endif memset(&my_aiocb, 0, sizeof(struct aiocb)); memset(&my_aiocb_timeout, 0, sizeof(struct timespec)); my_aiocb.aio_fildes = fd; my_aiocb.aio_sigevent.sigev_notify = SIGEV_NONE; #endif /*@-branchstate@*/ while (size) { #if ENABLE_AIO /*@-mustfree@*/ /* my_aiocb.aio_buf is OK */ my_aiocb.aio_buf = data; /*@=mustfree@*/ my_aiocb.aio_nbytes = size; rc = aio_read(&my_aiocb); #else rc = read(fd, data, size); #endif if (rc < 0) return -1; #if ENABLE_AIO my_aiocb_timeout.tv_sec = (timeout / 1000); my_aiocb_timeout.tv_nsec = (timeout % 1000) * 1000000; rc = aio_suspend(&my_aiocb_list, 1, &my_aiocb_timeout); if (rc < 0) { #if HAVE_ERRNO_H if (errno == EAGAIN) { /* certain linux glibc versions are buggy and don't aio_suspend properly */ (void) nanosleep(&my_aiocb_timeout, (struct timespec*) 0); my_aiocb_timeout.tv_sec = 0; my_aiocb_timeout.tv_nsec = 0; /* and try again */ rc = aio_suspend(&my_aiocb_list, 1, &my_aiocb_timeout); } #endif } if (rc < 0) { /* cancel any remaining reads */ while (rc != AIO_ALLDONE) { rc = aio_cancel(fd, (struct aiocb*) 0); if (rc == AIO_NOTCANCELED) { my_aiocb_timeout.tv_sec = (timeout / 1000); my_aiocb_timeout.tv_nsec = (timeout % 1000) * 1000000; (void) nanosleep(&my_aiocb_timeout, (struct timespec*) 0); } if (rc < 0) /*@innerbreak@*/ break; } return -1; } rc = aio_error(&my_aiocb); if (rc < 0) return -1; rc = aio_return(&my_aiocb); if (rc < 0) return -1; #endif data += rc; size -= rc; } /*@=branchstate@*/ return 0; } #endif #if HAVE_DEV_TTY /** \ingroup ES_tty_m * @param fd * @retval data * @param size * @return */ static int entropy_ttybits(int fd, /*@out@*/ byte* data, size_t size) /*@globals fileSystem @*/ /*@modifies fileSystem @*/ { byte dummy; #if HAVE_TERMIOS_H struct termios tio_save, tio_set; #elif HAVE_TERMIO_H struct termio tio_save, tio_set; #else # error need alternative #endif #if HAVE_GETHRTIME hrtime_t hrtsample; #elif HAVE_GETTIMEOFDAY struct timeval tvsample; #else # error need alternative high-precision timer #endif printf("please press random keys on your keyboard\n"); #if HAVE_TERMIOS_H if (tcgetattr(fd, &tio_save) < 0) { #if HAVE_ERRNO_H perror("tcgetattr failed"); #endif return -1; } tio_set = tio_save; /*@-noeffect -type @*/ /* LCL: dunno @*/ tio_set.c_cc[VMIN] = 1; /* read 1 tty character at a time */ tio_set.c_cc[VTIME] = 0; /* don't timeout the read */ /*@=noeffect =type @*/ /*@-bitwisesigned@*/ tio_set.c_iflag |= IGNBRK; /* ignore -c */ tio_set.c_lflag &= ~(ECHO|ICANON); /* don't echo characters */ /*@=bitwisesigned@*/ /* change the tty settings, and flush input characters */ if (tcsetattr(fd, TCSAFLUSH, &tio_set) < 0) { #if HAVE_ERRNO_H perror("tcsetattr failed"); #endif return -1; } #elif HAVE_TERMIO_H if (ioctl(fd, TCGETA, &tio_save) < 0) { #if HAVE_ERRNO_H perror("ioctl TCGETA failed"); #endif return -1; } tio_set = tio_save; tio_set.c_cc[VMIN] = 1; /* read 1 tty character at a time */ tio_set.c_cc[VTIME] = 0; /* don't timeout the read */ tio_set.c_iflag |= IGNBRK; /* ignore -c */ tio_set.c_lflag &= ~(ECHO|ICANON); /* don't echo characters */ /* change the tty settings, and flush input characters */ if (ioctl(fd, TCSETAF, &tio_set) < 0) { #if HAVE_ERRNO_H perror("ioctl TCSETAF failed"); #endif return -1; } #else # error Need alternative tty control library #endif while (size) { if (read(fd, &dummy, 1) < 0) { #if HAVE_ERRNO_H perror("tty read failed"); #endif return -1; } printf("."); (void) fflush(stdout); #if HAVE_GETHRTIME hrtsample = gethrtime(); /* discard the 10 lowest bits i.e. 1024 nanoseconds of a sample */ temp |= (uint16_t)(hrtsample >> 10); *(data++) = (byte)(hrtsample >> 10); size--; #elif HAVE_GETTIMEOFDAY /* discard the 4 lowest bits i.e. 4 microseconds */ (void) gettimeofday(&tvsample, 0); /* get 8 bits from the sample */ *(data++) = (byte)(((unsigned)tvsample.tv_usec) >> 2); size--; #else # error Need alternative high-precision timer sample #endif } printf("\nthanks\n"); /* give the user 1 second to stop typing */ (void) sleep(1U); #if HAVE_TERMIOS_H /* change the tty settings, and flush input characters */ if (tcsetattr(fd, TCSAFLUSH, &tio_save) < 0) { #if HAVE_ERRNO_H perror("tcsetattr failed"); #endif return -1; } #elif HAVE_TERMIO_H /* restore the tty settings, and flush input characters */ if (ioctl(fd, TCSETAF, &tio_save) < 0) { #if HAVE_ERRNO_H perror("ioctl TCSETAF failed"); #endif return -1; } #else # error Need alternative tty control library #endif return 0; } #endif #if HAVE_DEV_AUDIO int entropy_dev_audio(uint32 *data, int size) { const char* timeout_env = getenv("BEECRYPT_ENTROPY_AUDIO_TIMEOUT"); register int rc; #ifdef _REENTRANT # if HAVE_SYNCH_H if (mutex_lock(&dev_audio_lock)) return -1; # elif HAVE_PTHREAD_H if (pthread_mutex_lock(&dev_audio_lock)) return -1; # endif #endif #if HAVE_SYS_STAT_H if (statdevice(name_dev_audio) < 0) goto dev_audio_end; #endif if ((rc = dev_audio_fd = opendevice(name_dev_audio)) < 0) goto dev_audio_end; #if HAVE_SYS_AUDIOIO_H /* i.e. Solaris */ { struct audio_info info; AUDIO_INITINFO(&info); info.record.sample_rate = 48000; info.record.channels = 2; info.record.precision = 16; info.record.encoding = AUDIO_ENCODING_LINEAR; info.record.gain = AUDIO_MAX_GAIN; info.record.pause = 0; info.record.buffer_size = 4096; info.record.samples = 0; if ((rc = ioctl(dev_audio_fd, AUDIO_SETINFO, &info)) < 0) { if (errno == EINVAL) { /* use a conservative setting this time */ info.record.sample_rate = 22050; info.record.channels = 1; info.record.precision = 8; if ((rc = ioctl(dev_audio_fd, AUDIO_SETINFO, &info)) < 0) { #if HAVE_ERRNO_H perror("ioctl AUDIO_SETINFO failed"); #endif (void) close(dev_audio_fd); goto dev_audio_end; } } else { #if HAVE_ERRNO_H perror("ioctl AUDIO_SETINFO failed"); #endif (void) close(dev_audio_fd); goto dev_audio_end; } } rc = entropy_noise_gather(dev_audio_fd, info.record.precision >> 3, info.record.channels, 0, timeout_env ? atoi(timeout_env) : 1000, data, size); } #else # error Unknown type of /dev/audio interface #endif (void) close(dev_audio_fd); dev_audio_end: #ifdef _REENTRANT # if HAVE_SYNCH_H mutex_unlock(&dev_audio_lock); # elif HAVE_PTHREAD_H pthread_mutex_unlock(&dev_audio_lock); # endif #endif return rc; } #endif #if HAVE_DEV_DSP int entropy_dev_dsp(byte *data, size_t size) /*@globals dev_dsp_fd @*/ /*@modifies dev_dsp_fd @*/ { const char* timeout_env = getenv("BEECRYPT_ENTROPY_DSP_TIMEOUT"); register int rc; #ifdef _REENTRANT # if HAVE_SYNCH_H if (mutex_lock(&dev_dsp_lock)) return -1; # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ if (pthread_mutex_lock(&dev_dsp_lock)) return -1; /*@=moduncon =noeffectuncon @*/ # endif #endif #if HAVE_SYS_STAT_H if ((rc = statdevice(name_dev_dsp)) < 0) goto dev_dsp_end; #endif if ((rc = dev_dsp_fd = opendevice(name_dev_dsp)) < 0) goto dev_dsp_end; #if HAVE_SYS_SOUNDCARD_H /* i.e. Linux audio */ { int mask, format, samplesize, stereo, speed, swap; mask = 0; /*@-bitwisesigned -shiftimplementation -sizeoftype -type @*/ if ((rc = ioctl(dev_dsp_fd, SNDCTL_DSP_GETFMTS, &mask)) < 0) /*@=bitwisesigned =shiftimplementation =sizeoftype =type @*/ { #if HAVE_ERRNO_H perror("ioctl SNDCTL_DSP_GETFMTS failed"); #endif (void) close (dev_dsp_fd); goto dev_dsp_end; } /*@-bitwisesigned@*/ #if WORDS_BIGENDIAN if (mask & AFMT_S16_BE) { format = AFMT_S16_BE; samplesize = 2; swap = 0; } else if (mask & AFMT_S16_LE) { format = AFMT_S16_LE; samplesize = 2; swap = 1; } #else if (mask & AFMT_S16_LE) { format = AFMT_S16_LE; samplesize = 2; swap = 0; } else if (mask & AFMT_S16_BE) { format = AFMT_S16_BE; samplesize = 2; swap = 1; } #endif else if (mask & AFMT_S8) { format = AFMT_S8; samplesize = 1; swap = 0; } else { /* No linear audio format available */ rc = -1; (void) close(dev_dsp_fd); goto dev_dsp_end; } /*@=bitwisesigned@*/ /*@-bitwisesigned -shiftimplementation -sizeoftype -type @*/ if ((rc = ioctl(dev_dsp_fd, SNDCTL_DSP_SETFMT, &format)) < 0) /*@=bitwisesigned =shiftimplementation =sizeoftype =type @*/ { #if HAVE_ERRNO_H perror("ioctl SNDCTL_DSP_SETFMT failed"); #endif (void) close(dev_dsp_fd); goto dev_dsp_end; } /* the next two commands are not critical */ stereo = 1; /*@-bitwisesigned -shiftimplementation -sizeoftype -type @*/ (void) ioctl(dev_dsp_fd, SNDCTL_DSP_STEREO, &stereo); /*@=bitwisesigned =shiftimplementation =sizeoftype =type @*/ speed = 44100; /*@-bitwisesigned -shiftimplementation -sizeoftype -type @*/ (void) ioctl(dev_dsp_fd, SNDCTL_DSP_SPEED, &speed); /*@=bitwisesigned =shiftimplementation =sizeoftype =type @*/ rc = entropy_noise_gather(dev_dsp_fd, samplesize, 2, swap, timeout_env ? atoi(timeout_env) : 1000, data, size); } #else # error Unknown type of /dev/dsp interface #endif (void) close(dev_dsp_fd); dev_dsp_end: #ifdef _REENTRANT # if HAVE_SYNCH_H mutex_unlock(&dev_dsp_lock); # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ (void) pthread_mutex_unlock(&dev_dsp_lock); /*@=moduncon =noeffectuncon @*/ # endif #endif return rc; } #endif #if HAVE_DEV_RANDOM int entropy_dev_random(byte* data, size_t size) /*@globals dev_random_fd @*/ /*@modifies dev_random_fd @*/ { const char* timeout_env = getenv("BEECRYPT_ENTROPY_RANDOM_TIMEOUT"); int rc; #ifdef _REENTRANT # if HAVE_SYNCH_H if (mutex_lock(&dev_random_lock)) return -1; # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ if (pthread_mutex_lock(&dev_random_lock)) return -1; /*@=moduncon =noeffectuncon @*/ # endif #endif #if HAVE_SYS_STAT_H if ((rc = statdevice(name_dev_random)) < 0) goto dev_random_end; #endif if ((rc = dev_random_fd = opendevice(name_dev_random)) < 0) goto dev_random_end; /* collect entropy, with timeout */ rc = entropy_randombits(dev_random_fd, timeout_env ? atoi(timeout_env) : 1000, data, size); (void) close(dev_random_fd); dev_random_end: #ifdef _REENTRANT # if HAVE_SYNCH_H mutex_unlock(&dev_random_lock); # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ (void) pthread_mutex_unlock(&dev_random_lock); /*@=moduncon =noeffectuncon @*/ # endif #endif return rc; } #endif #if HAVE_DEV_URANDOM int entropy_dev_urandom(byte* data, size_t size) /*@globals dev_urandom_fd @*/ /*@modifies dev_urandom_fd @*/ { const char* timeout_env = getenv("BEECRYPT_ENTROPY_URANDOM_TIMEOUT"); register int rc; #ifdef _REENTRANT # if HAVE_SYNCH_H if (mutex_lock(&dev_urandom_lock)) return -1; # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ if (pthread_mutex_lock(&dev_urandom_lock)) return -1; /*@=moduncon =noeffectuncon @*/ # endif #endif #if HAVE_SYS_STAT_H if ((rc = statdevice(name_dev_urandom)) < 0) goto dev_urandom_end; #endif if ((rc = dev_urandom_fd = opendevice(name_dev_urandom)) < 0) goto dev_urandom_end; /* collect entropy, with timeout */ rc = entropy_randombits(dev_urandom_fd, timeout_env ? atoi(timeout_env) : 1000, data, size); (void) close(dev_urandom_fd); dev_urandom_end: #ifdef _REENTRANT # if HAVE_SYNCH_H mutex_unlock(&dev_urandom_lock); # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ (void) pthread_mutex_unlock(&dev_urandom_lock); /*@=moduncon =noeffectuncon @*/ # endif #endif return rc; } #endif #if HAVE_DEV_TTY int entropy_dev_tty(byte* data, size_t size) /*@globals dev_tty_fd @*/ /*@modifies dev_tty_fd @*/ { register int rc; /** @todo hpux needs real locking mechanism. */ #if defined(_REENTRANT) && !defined(hpux) # if HAVE_SYNCH_H if (mutex_lock(&dev_tty_lock)) return -1; # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ if (pthread_mutex_lock(&dev_tty_lock)) return -1; /*@=moduncon =noeffectuncon @*/ # endif #endif #if HAVE_SYS_STAT_H if ((rc = statdevice(dev_tty_name)) < 0) goto dev_tty_end; #endif if ((rc = dev_tty_fd = opendevice(dev_tty_name)) < 0) goto dev_tty_end; rc = entropy_ttybits(dev_tty_fd, data, size); (void) close(dev_tty_fd); dev_tty_end: /** @todo hpux needs real locking mechanism. */ #if defined(_REENTRANT) && !defined(hpux) # if HAVE_SYNCH_H mutex_unlock(&dev_tty_lock); # elif HAVE_PTHREAD_H /*@-moduncon -noeffectuncon @*/ /* FIX: annotate */ (void) pthread_mutex_unlock(&dev_tty_lock); /*@=moduncon =noeffectuncon @*/ # endif #endif return rc; } #endif #endif