/* vi: set sw=4 ts=4: * * Copyright (C) 2015 Christian Hohnstaedt. * * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include "func.h" #include "xfile.h" #include "entropy.h" #include "openssl_compat.h" /* Entropy sources for XCA * * Entropy is a very important topic for key generation. * * XCA uses the following sources for entropy: * * 1) During startup * RAND_poll() * The OpenSSL seeding mechanism. * It uses /dev/urandom where possible and the * Screen content on Windows. * * If "/dev/random" exists, it will be used for additional * 256bit entropy. Same is true for "/dev/hwrng" * * 2) Before any key or parameter generation a "reseeding" * is done. Some say reseeding is not neccessary, but * all say it does not harm. * * Entropy by Mouse and keyboard events * main.cpp: bool XCA_application::eventFilter() * 256bit from /dev/urandom (unix/Mac) * * 3) A .rnd state file in the XCA application directory * is written on exit and read on startup. * After reading it, the file will be erased to avoid replays. * * 4) When managing a token that supports C_GenerateRandom * and C_SeedRandom, XCA will seed the token and in return * seed himself from the token. */ #undef DEBUG_ENTROPY #define pool_siz (sizeof(pool)/sizeof(pool[0])) unsigned char Entropy::pool[512]; unsigned Entropy::pool_pos = 0; QTime Entropy::timer; unsigned Entropy::seed_strength = 0; void Entropy::add(int rand) { unsigned char entropy = (rand ^ timer.elapsed()) & 0xff; pool[pool_pos++ % pool_siz] = entropy; } void Entropy::add_buf(const unsigned char *buf, int buflen) { RAND_seed(buf, buflen); seed_strength += buflen; } int Entropy::get(unsigned char *buf, int num) { seed_rng(); return RAND_bytes(buf, num); } void Entropy::seed_rng() { if (pool_pos > pool_siz) pool_pos = pool_siz; RAND_seed(pool, pool_pos); seed_strength += pool_pos; #if !defined(Q_OS_WIN32) random_from_file("/dev/urandom", 32); #endif #ifdef DEBUG_ENTROPY { QDebug dbg = qDebug(); dbg << QString("Seeding %1 bytes:").arg(pool_pos); for (unsigned i=0; i 0;) { int len = read(fd, buf, amount > sizeof buf ? sizeof buf : amount); if (len > 0) { RAND_seed(buf, len); seed_strength += len / weakness; amount -= len; sum += len; } if (len == -1) { if (errno != EWOULDBLOCK) qWarning("Error '%s' while reading '%s'\n", strerror(errno), CCHAR(fname)); len = 0; } if (len == 0) break; } close(fd); #ifdef DEBUG_ENTROPY qDebug("Entropy from file '%s' = %d bytes", CCHAR(fname), sum); #endif return sum; } unsigned Entropy::strength() { return seed_strength; } Entropy::Entropy() { timer.start(); rnd = getUserSettingsDir() + "/.rnd"; random_from_file(rnd, 1024, 128); QFile::remove(rnd); // don't use it again RAND_poll(); seed_strength += 8; #if !defined(Q_OS_WIN32) random_from_file("/dev/random", 32); random_from_file("/dev/hwrng", 32); #endif } Entropy::~Entropy() { #define RAND_BUF_SIZE 1024 unsigned char buf[RAND_BUF_SIZE]; if (RAND_bytes(buf, RAND_BUF_SIZE) == 1) { XFile file(rnd); try { file.open_key(); file.write((char*)buf, RAND_BUF_SIZE); } catch (errorEx &e) { qDebug() << "random_from_file" << rnd << e.getString(); } file.close(); } memset(buf, 0, RAND_BUF_SIZE); #ifdef DEBUG_ENTROPY qDebug("Seed strength: %d", seed_strength); #endif }