rpm/beecrypt/entropy.c

1614 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*@-sizeoftype -type@*/
/** \ingroup ES_m
* \file entropy.c
*
* Entropy gathering routine(s) for pseudo-random generator initialization.
*/
/*
* Copyright (c) 1998, 1999, 2000, 2001 Virtual Unlimited B.V.
*
* Author: Bob Deblier <bob@virtualunlimited.com>
*
* 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
*
*/
#define BEECRYPT_DLL_EXPORT
#include "entropy.h"
#include "endianness.h"
#if WIN32
# include <mmsystem.h>
# include <wincrypt.h>
# include <winerror.h>
#else
# if HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
# endif
# if HAVE_SYS_STAT_H
# include <sys/types.h>
# include <sys/stat.h>
# endif
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# if HAVE_SYS_AUDIOIO_H
# include <sys/audioio.h>
# endif
# if HAVE_SYS_SOUNDCARD_H
# include <sys/soundcard.h>
# endif
# if HAVE_TERMIOS_H
# include <termios.h>
# elif HAVE_TERMIO_H
# include <termio.h>
# endif
# if HAVE_SYNCH_H
# include <synch.h>
# elif HAVE_PTHREAD_H
# include <pthread.h>
# endif
# if HAVE_AIO_H
# include <aio.h>
# if defined(__LCLINT__)
/*@-declundef -exportheader -incondefs -constuse -warnmissingglobs @*/
extern int
nanosleep (const struct timespec *__requested_time,
/*@out@*/ /*@null@*/ struct timespec *__remaining)
/*@modifies 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
#if HAVE_STDLIB_H
# include <stdlib.h>
#endif
#if HAVE_FCNTL_H
# include <fcntl.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if HAVE_STRING_H
# include <string.h>
#endif
#if HAVE_ERRNO_H
# include <errno.h>
#endif
#include <stdio.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, int samplecount, int samplesize, int channels, int swap)
/*@globals errno @*/
/*@modifies sampledata, errno @*/
{
register int rc = 0, i;
switch (samplesize)
{
case 1:
{
uint8* samples = (uint8*) 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 & 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;
}
}
break;
case 2:
{
uint16* samples = (uint16*) 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, uint32 *data, int size)
#else
/*@-mustmod@*/ /* data is modified, annotations incorrect */
static int entropy_noise_gather(int fd, int samplesize, int channels, int swap, int timeout, /*@out@*/ uint32 *data, int size)
/*@globals errno, fileSystem @*/
/*@modifies data, errno, fileSystem @*/
#endif
{
uint32 randombits = ((unsigned)size) << 5;
uint32 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
if (entropy_noise_filter(sampledata, rc / samplesize, samplesize, channels, swap) < 0)
{
fprintf(stderr, "noise filter indicates too much bias in audio samples\n");
/*@-kepttrans@*/
free(sampledata);
/*@=kepttrans@*/
return -1;
}
switch (samplesize)
{
case 1:
{
uint8* samples = (uint8*) 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* samples = (uint16*) sampledata;
for (i = 0; randombits && (i < 1024); i += 2)
{
if (samples[i] ^ samples[i+1])
{
temp <<= 1;
temp |= samples[i];
randombits--;
if (!(randombits & 0x1f))
*(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(uint32* data, int 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(uint32* data, int size)
{
register uint32 randombits = size << 5;
register uint32 temp = 0;
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 */
temp <<= 8;
/* discard the 2 lowest bits */
temp |= (uint32)(hrtsample.LowPart >> 2);
randombits -= 8;
if (!(randombits & 0x1f))
*(data++) = temp;
}
}
printf("\nthanks\n");
Sleep(1000);
if (!FlushConsoleInputBuffer(hStdin))
{
fprintf(stderr, "FlushConsoleInputBuffer failed\n"); (void) fflush(stderr);
return -1;
}
return 0;
}
int entropy_wincrypt(uint32* data, int 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 << 2, (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
/*@unchecked@*/
static pthread_mutex_t dev_dsp_lock = PTHREAD_MUTEX_INITIALIZER;
# 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
/*@unchecked@*/
static pthread_mutex_t dev_random_lock = PTHREAD_MUTEX_INITIALIZER;
# 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
/*@unchecked@*/
static pthread_mutex_t dev_urandom_lock = PTHREAD_MUTEX_INITIALIZER;
# 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
*/
# ifdef _REENTRANT
# if HAVE_SYNCH_H
/*@unchecked@*/
static mutex_t dev_tty_lock = DEFAULTMUTEX;
# elif HAVE_PTHREAD_H
/*@unchecked@*/
static pthread_mutex_t dev_tty_lock = PTHREAD_MUTEX_INITIALIZER;
# 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, int timeout, uint32* data, int size)
/*@*/
{
register byte* bytedata = (byte*) data;
register int bytesize = (((unsigned)size) << 2);
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 (bytesize)
{
#if ENABLE_AIO
/*@-mustfree@*/ /* my_aiocb.aio_buf is OK */
my_aiocb.aio_buf = bytedata;
/*@=mustfree@*/
my_aiocb.aio_nbytes = bytesize;
rc = aio_read(&my_aiocb);
#else
rc = read(fd, bytedata, bytesize);
#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
bytedata += rc;
bytesize -= 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, uint32* data, int size)
/*@globals fileSystem @*/
/*@modifies fileSystem @*/
{
uint32 randombits = ((unsigned)size) << 5;
uint32 temp = 0;
byte dummy;
#if HAVE_TERMIOS_H
struct termios tio_save, tio_set;
#elif HAVE_TERMIO_H
struct termio tio_save, tio_set;
#else
# 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@*/ /* 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@*/
tio_set.c_iflag |= IGNBRK; /* ignore <ctrl>-c */
tio_set.c_lflag &= ~(ECHO|ICANON); /* don't echo characters */
/* 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 <ctrl>-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 (randombits)
{
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();
/* get 16 bits from the sample */
temp <<= 16;
/* discard the 10 lowest bits i.e. 1024 nanoseconds */
temp |= (uint16)(hrtsample >> 10);
randombits -= 16;
#elif HAVE_GETTIMEOFDAY
/* discard the 4 lowest bits i.e. 4 microseconds */
(void) gettimeofday(&tvsample, 0);
/* get 8 bits from the sample */
temp <<= 8;
temp |= (uint8)(((unsigned)tvsample.tv_usec) >> 2);
randombits -= 8;
#else
# error Need alternative high-precision timer sample
#endif
if (!(randombits & 0x1f))
*(data++) = temp;
}
printf("\nthanks\n");
/* give the user 1 second to stop typing */
(void) sleep(1);
#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(uint32 *data, int 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;
/*@-shiftsigned@*/
if ((rc = ioctl(dev_dsp_fd, SNDCTL_DSP_GETFMTS, &mask)) < 0)
/*@=shiftsigned@*/
{
#if HAVE_ERRNO_H
perror("ioctl SNDCTL_DSP_GETFMTS failed");
#endif
(void) close (dev_dsp_fd);
goto dev_dsp_end;
}
#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;
}
/*@-shiftsigned@*/
if ((rc = ioctl(dev_dsp_fd, SNDCTL_DSP_SETFMT, &format)) < 0)
/*@=shiftsigned@*/
{
#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;
/*@-shiftsigned@*/
(void) ioctl(dev_dsp_fd, SNDCTL_DSP_STEREO, &stereo);
/*@=shiftsigned@*/
speed = 44100;
/*@-shiftsigned@*/
(void) ioctl(dev_dsp_fd, SNDCTL_DSP_SPEED, &speed);
/*@=shiftsigned@*/
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(uint32* data, int 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(uint32* data, int 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(uint32* data, int size)
/*@globals dev_tty_fd @*/
/*@modifies dev_tty_fd @*/
{
register int rc;
#ifdef _REENTRANT
# 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:
#ifdef _REENTRANT
# 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
/*@=sizeoftype =type@*/