Browse Source

initial checkin

master
Georg Hopp 14 years ago
parent
commit
11a6d63570
  1. 30
      .gitignore
  2. 14
      Makefile.am
  3. 264
      mod_entropy.c

30
.gitignore

@ -0,0 +1,30 @@
.*.swp
*.o
*.a
*.gcda
*.gcno
.dirstamp
.deps/
Makefile
Makefile.in
/config*
m4/
/docs/
/INSTALL
coverage.base
coverage.run
coverage.info
coveragereport/
*.m4
/autom4te.cache/
/compile
/depcomp
/docs/
/install-sh
/libtool
/ltmain.sh
/missing
stamp-h1
src/taskrambler
/tests/*Test
gmon.out

14
Makefile.am

@ -0,0 +1,14 @@
## This is the shared library to be built
lib_LTLIBRARIES = libmodentropy.la
## Define the source file for the module
libmodentropy_la_SOURCES = mod_entropy.c mod_entropy_get_entropy_bits.c \
mod_entropy_add_entropy.c
libmodentropy_la_LDFLAGS = -lrt -lm
install: libmodentropy.la
apxs -i -a -n entropy libmodentropy.la
## Define that an include directory is required.
#INCLUDES = -I@apache_dir@/include -I/usr/include/apr-1

264
mod_entropy.c

@ -0,0 +1,264 @@
/**
* this filter generates a sha1 from the current microtime and request
* useses this to fill the linux random source.
*
* inspired by timed_entropyd.
*
* ATTENTION: This module is not portable right now as i don't know
* howto fill the random source for other systems. It is linux only.
*
* Most time was spend in figuring out how to write apache modules.
*
* \author Georg Hopp <georg@steffers.org>
*/
#define _POSIX_C_SOURCE 199309L
#include <apache2/httpd.h>
#include <apache2/http_core.h>
#include <apr-1/apu.h>
#include <apr-1/apr_general.h>
#include <apr-1/apr_sha1.h>
#include <time.h>
#include <math.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/random.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define min(x, y) ((x)<(y)?(x):(y))
module AP_MODULE_DECLARE_DATA entropy_module;
char * getData(const char *, size_t);
/**
* This is taken from timer_entropyd and modified so
* that the constant 1/log(2.0) is not calculated but
* set directly.
*
* As far as i can say this correlates to the shannon
* entropy algorithm with equal probabilities
* for entropy where the entropy units are bits.
*
* But actually i am no mathemacian and my analysis capabilities
* are limited. Additionally i have not analysed the linux random
* character device code, so i trusted the code in timer_entropyd.
*/
static
int
get_entropy(const unsigned char * data, size_t ndata)
{
size_t byte_count[256];
size_t iterator;
static double log2inv = 1.442695; //!< 1 / log(2.0): the entropy unit size
double entropy = 0.0;
memset(byte_count, 0, sizeof(byte_count));
/**
* first get the amount each byte occurs in the array
*/
for (iterator = 0; iterator < ndata; iterator++) {
byte_count[data[iterator]]++;
}
for (iterator = 0; iterator < 256; iterator++) {
double probability = (double)byte_count[iterator] / (double)ndata;
if (0.0 < probability) {
entropy += probability * log2inv * (log(1.0 / probability));
}
}
entropy *= (double)ndata;
entropy = (entropy < 0.0)? 0.0 : entropy;
entropy = min((double)(ndata * 8), entropy);
return entropy;
}
static
int
header_do_print(void * rec, const char * key, const char * value)
{
apr_sha1_ctx_t * sha1_ctx = rec;
apr_sha1_update(sha1_ctx, value, strlen(value));
return 1;
}
static
apr_status_t
entropy_filter_in(
ap_filter_t * filter,
apr_bucket_brigade * brigade,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes)
{
apr_bucket * bucket;
apr_status_t status;
request_rec * request = filter->r;
conn_rec * connection = filter->c;
apr_sha1_ctx_t sha1_ctx;
unsigned char digest[APR_SHA1_DIGESTSIZE];
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
apr_sha1_init(&sha1_ctx);
/**
* add current microtime to sha1
*/
apr_sha1_update_binary(
&sha1_ctx,
(const unsigned char *)&ts,
sizeof(ts));
/**
* add client ip to sha1
*/
apr_sha1_update(
&sha1_ctx,
connection->client_ip,
strlen(connection->client_ip));
/**
* add request line to sha1
*/
apr_sha1_update(
&sha1_ctx,
request->the_request,
strlen(request->the_request));
/**
* add all header values to sha1
*/
apr_table_do(header_do_print, &sha1_ctx, request->headers_in, NULL);
/**
* get the request body and add it to the sha1
*/
status = ap_get_brigade(filter->next, brigade, mode, block, readbytes);
if (status == APR_SUCCESS) {
for (
bucket = APR_BRIGADE_FIRST(brigade);
bucket != APR_BRIGADE_SENTINEL(brigade);
bucket = APR_BUCKET_NEXT(bucket)) {
if (!(APR_BUCKET_IS_METADATA(bucket))) {
const char * buffer;
apr_size_t nbuffer;
status = apr_bucket_read(
bucket,
&buffer,
&nbuffer,
APR_BLOCK_READ);
if (status == APR_SUCCESS) {
apr_sha1_update(&sha1_ctx, buffer, nbuffer);
}
}
}
}
/**
* get the sha1 digest
*/
apr_sha1_final(digest, &sha1_ctx);
/**
* fill /dev/random with sha1 from current request
*/
{
int i;
int entropy = get_entropy(digest, APR_SHA1_DIGESTSIZE);
int fd = open("/dev/random", O_WRONLY|O_NONBLOCK);
struct rand_pool_info * output;
output = (struct rand_pool_info *)malloc(
sizeof(struct rand_pool_info) + APR_SHA1_DIGESTSIZE);
output->entropy_count = entropy;
output->buf_size = APR_SHA1_DIGESTSIZE;
memcpy(output->buf, digest, APR_SHA1_DIGESTSIZE);
fprintf(stderr, "sha1 so far: ");
for (i=0; i<APR_SHA1_DIGESTSIZE; i++) {
fprintf(stderr, "%02x", digest[i]);
}
fprintf(stderr, "\n");
fprintf(stderr, "entropy bits: %d\n", entropy);
if (ioctl(fd, RNDADDENTROPY, output) == -1) {
switch(errno) {
case EBADF:
fprintf(stderr, "ioctl failed: no valid file descriptor %d\n", fd);
break;
case EFAULT:
fprintf(stderr, "ioctl failed: invalid argument: %p\n", output);
break;
case EINVAL:
fprintf(stderr, "ioctl failed: invalid request\n", errno);
break;
case ENOTTY:
fprintf(stderr, "ioctl failed: discriptor not associated to character device\n", errno);
break;
case EPERM:
fprintf(stderr, "ioctl failed: invalid permissions\n", errno);
break;
default:
fprintf(stderr, "ioctl(RNDADDENTROPY) failed: %d\n", errno);
break;
}
}
free(output);
close(fd);
}
fflush(stderr);
ap_remove_input_filter(filter);
return status;
}
/**
* apache module initialization
*/
static
void
entropy_register_hook(apr_pool_t *p)
{
ap_register_input_filter(
"ENTROPY",
entropy_filter_in,
NULL,
AP_FTYPE_CONTENT_SET);
}
module AP_MODULE_DECLARE_DATA entropy_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
entropy_register_hook /* register hooks */
};
// vim: set ts=4 sw=4:
Loading…
Cancel
Save