408 lines
8.7 KiB
C++
408 lines
8.7 KiB
C++
/*
|
|
* \brief Device Random filesystem
|
|
* \author Josef Soentgen
|
|
* \date 2012-07-31
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
#ifndef _NOUX__RANDOM_FILE_SYSTEM_H_
|
|
#define _NOUX__RANDOM_FILE_SYSTEM_H_
|
|
|
|
/* Genode includes */
|
|
#include <base/printf.h>
|
|
#include <base/stdint.h>
|
|
#include <util/string.h>
|
|
|
|
/* Noux includes */
|
|
#include <noux_session/sysio.h>
|
|
#include "file_system.h"
|
|
|
|
/*-
|
|
* Copyright (c) 2010, 2012
|
|
* Thorsten Glaser <tg@mirbsd.org>
|
|
* Copyright (c) 2012
|
|
* Josef Soentgen <cnuke@mirbsd.org>
|
|
*
|
|
* Provided that these terms and disclaimer and all copyright notices
|
|
* are retained or reproduced in an accompanying document, permission
|
|
* is granted to deal in this work without restriction, including un-
|
|
* limited rights to use, publicly perform, distribute, sell, modify,
|
|
* merge, give away, or sublicence.
|
|
*
|
|
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
|
|
* the utmost extent permitted by applicable law, neither express nor
|
|
* implied; without malicious intent or gross negligence. In no event
|
|
* may a licensor, author or contributor be held liable for indirect,
|
|
* direct, other damage, loss, or other issues arising in any way out
|
|
* of dealing in the work, even if advised of the possibility of such
|
|
* damage or existence of a defect, except proven that it results out
|
|
* of said person's immediate fault when using the work as intended.
|
|
*-
|
|
* arc4random for use as NOUX random device.
|
|
*
|
|
* From:
|
|
* MirOS: src/kern/c/arcfour_base.c,v 1.1 2010/09/12 17:10:49 tg Exp
|
|
* MirOS: src/kern/c/arcfour_ksa.c,v 1.1 2010/09/12 17:10:50 tg Exp
|
|
* MirOS: src/lib/libc/crypt/arc4random_base.c,v 1.4 2011/07/06 22:22:09 tg Exp
|
|
* MirOS: src/lib/libc/crypt/arc4random_buf.c,v 1.1 2010/09/12 17:10:53 tg Exp
|
|
*/
|
|
|
|
|
|
namespace Noux {
|
|
|
|
using namespace Genode;
|
|
|
|
/**
|
|
* Arcfour cipher re-implementation from (alledged) spec description.
|
|
*/
|
|
|
|
class Arc4random
|
|
{
|
|
private:
|
|
|
|
uint8_t S[256];
|
|
uint8_t i;
|
|
uint8_t j;
|
|
uint16_t num;
|
|
uint8_t initialised;
|
|
|
|
/*
|
|
* Base cipher operation: initialise state
|
|
*/
|
|
void init(void)
|
|
{
|
|
register uint8_t n = 0;
|
|
|
|
do {
|
|
S[n] = n;
|
|
} while (++n);
|
|
|
|
i = j = 0;
|
|
}
|
|
|
|
/*
|
|
* Base cipher operation: get byte of keystream.
|
|
*/
|
|
uint8_t byte(void)
|
|
{
|
|
register uint8_t si, sj;
|
|
|
|
si = S[++i];
|
|
j += si;
|
|
sj = S[j];
|
|
S[i] = sj;
|
|
S[j] = si;
|
|
return (S[(uint8_t)(si + sj)]);
|
|
}
|
|
|
|
/*
|
|
* Normal key scheduling algorithm.
|
|
*/
|
|
void ksa(const uint8_t *key, size_t keylen)
|
|
{
|
|
register uint8_t si, n = 0;
|
|
|
|
--i;
|
|
do {
|
|
++i;
|
|
si = S[i];
|
|
j = (uint8_t)(j + si + key[n++ % keylen]);
|
|
S[i] = S[j];
|
|
S[j] = si;
|
|
} while (n);
|
|
j = ++i;
|
|
}
|
|
|
|
/*
|
|
* arc4random implementation
|
|
*/
|
|
void stir_unlocked(void)
|
|
{
|
|
register unsigned int m;
|
|
uint8_t n;
|
|
struct {
|
|
// struct timeval tv;
|
|
// pid_t mypid;
|
|
uint32_t mypid;
|
|
const void *stkptr, *bssptr, *txtptr;
|
|
uint16_t num;
|
|
uint8_t initialised;
|
|
// FIXME sizeof (sb) should be as close to 256 as possible
|
|
} sb;
|
|
|
|
/* save some state; while not a secret, helps through variety */
|
|
//sb.mypid = getpid();
|
|
sb.mypid = 42;
|
|
sb.stkptr = &sb;
|
|
sb.bssptr = &i;
|
|
//sb.txtptr = &byte;
|
|
sb.txtptr = (const void *)0xDEADBEEF;;
|
|
sb.num = num;
|
|
sb.initialised = initialised;
|
|
|
|
/* initialise i, j and the S-box if not done yet */
|
|
if (!initialised) {
|
|
init();
|
|
initialised = 1;
|
|
}
|
|
|
|
// FIXME initialize more sb member
|
|
|
|
/* dance around by some bytes for added protection */
|
|
n = byte();
|
|
/* and carry some over to below */
|
|
m = byte();
|
|
while (n--)
|
|
(void)byte();
|
|
m += byte();
|
|
|
|
/* while time is not a secret, it helps through variety */
|
|
//gettimeofday(&sb.tv, NULL);
|
|
|
|
/* actually add the hopefully random-containing seed */
|
|
ksa((const uint8_t *)&sb, sizeof(sb));
|
|
|
|
/* throw away the first part of the arcfour keystream */
|
|
/* with some bytes varied for added protection */
|
|
m += 256 * 4 + (byte() & 0x1F);
|
|
while (m--)
|
|
(void)byte();
|
|
/* state is now good for so many bytes: (not so much in NOUX) */
|
|
num = 2000;
|
|
}
|
|
|
|
void buf(void *buf_, size_t len)
|
|
{
|
|
size_t chunk;
|
|
uint8_t *buf = (uint8_t *)buf_;
|
|
uint8_t m, n;
|
|
|
|
/* operate in chunks of at most 256 bytes */
|
|
while ((chunk = len > 256 ? 256 : len) > 0) {
|
|
/* adjust len */
|
|
len -= chunk;
|
|
|
|
/* is the state good for this? (or even initialised, yet?) */
|
|
if (num < chunk)
|
|
stir_unlocked();
|
|
|
|
/* dance around a few bytes for added protection */
|
|
m = byte() & 3;
|
|
/* and carry some down below */
|
|
n = byte() & 3;
|
|
while (m--)
|
|
(void)byte();
|
|
|
|
/* actually read out the keystream into buf */
|
|
while (chunk--) {
|
|
*buf++ = byte();
|
|
}
|
|
|
|
/* dance around the bytes read from above, for protection */
|
|
while (n--)
|
|
(void)byte();
|
|
}
|
|
}
|
|
|
|
public:
|
|
|
|
Arc4random(void* bytes, size_t nbytes)
|
|
:
|
|
i(0),
|
|
j(0),
|
|
num(0),
|
|
initialised(0)
|
|
{
|
|
memset(S, 0, 256);
|
|
}
|
|
|
|
void get(void *_buf, size_t len)
|
|
{
|
|
buf(_buf, len);
|
|
}
|
|
};
|
|
|
|
|
|
class Random_file_system : public File_system
|
|
{
|
|
private:
|
|
|
|
Arc4random *_arc4random;
|
|
|
|
const char *_filename() { return "urandom"; }
|
|
|
|
bool _is_root(const char *path)
|
|
{
|
|
return (strcmp(path, "") == 0) || (strcmp(path, "/") == 0);
|
|
}
|
|
|
|
bool _is_device_random_file(const char *path)
|
|
{
|
|
return (strlen(path) == (strlen(_filename()) + 1)) &&
|
|
(strcmp(&path[1], _filename()) == 0);
|
|
}
|
|
|
|
public:
|
|
|
|
Random_file_system(void *bytes, size_t nbytes)
|
|
{
|
|
_arc4random = new (env()->heap()) Arc4random(bytes, nbytes);
|
|
}
|
|
|
|
~Random_file_system()
|
|
{
|
|
destroy(env()->heap(), _arc4random);
|
|
}
|
|
|
|
|
|
/*********************************
|
|
** Directory-service interface **
|
|
*********************************/
|
|
|
|
Dataspace_capability dataspace(char const *path)
|
|
{
|
|
/* not supported */
|
|
return Dataspace_capability();
|
|
}
|
|
|
|
void release(char const *path, Dataspace_capability ds_cap)
|
|
{
|
|
/* not supported */
|
|
}
|
|
|
|
bool stat(Sysio *sysio, char const *path)
|
|
{
|
|
Sysio::Stat st = { 0, 0, 0, 0, 0, 0 };
|
|
|
|
if (_is_root(path))
|
|
st.mode = Sysio::STAT_MODE_DIRECTORY;
|
|
else if (_is_device_random_file(path)) {
|
|
st.mode = Sysio::STAT_MODE_CHARDEV;
|
|
} else {
|
|
sysio->error.stat = Sysio::STAT_ERR_NO_ENTRY;
|
|
return false;
|
|
}
|
|
|
|
sysio->stat_out.st = st;
|
|
return true;
|
|
}
|
|
|
|
bool dirent(Sysio *sysio, char const *path, off_t index)
|
|
{
|
|
if (_is_root(path)) {
|
|
if (index == 0) {
|
|
sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_CHARDEV;
|
|
strncpy(sysio->dirent_out.entry.name,
|
|
_filename(),
|
|
sizeof(sysio->dirent_out.entry.name));
|
|
} else {
|
|
sysio->dirent_out.entry.type = Sysio::DIRENT_TYPE_END;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t num_dirent(char const *path)
|
|
{
|
|
if (_is_root(path))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
bool is_directory(char const *path)
|
|
{
|
|
if (_is_root(path))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
char const *leaf_path(char const *path)
|
|
{
|
|
return path;
|
|
}
|
|
|
|
Vfs_handle *open(Sysio *sysio, char const *path)
|
|
{
|
|
if (!_is_device_random_file(path)) {
|
|
sysio->error.open = Sysio::OPEN_ERR_UNACCESSIBLE;
|
|
return 0;
|
|
}
|
|
|
|
return new (env()->heap()) Vfs_handle(this, this, 0);
|
|
}
|
|
|
|
bool unlink(Sysio *sysio, char const *path)
|
|
{
|
|
/* not supported */
|
|
return false;
|
|
}
|
|
|
|
bool readlink(Sysio *sysio, char const *path)
|
|
{
|
|
/* not supported */
|
|
return false;
|
|
}
|
|
|
|
bool rename(Sysio *sysio, char const *from_path, char const *to_path)
|
|
{
|
|
/* not supported */
|
|
return false;
|
|
}
|
|
|
|
bool mkdir(Sysio *sysio, char const *path)
|
|
{
|
|
/* not supported */
|
|
return false;
|
|
}
|
|
|
|
bool symlink(Sysio *sysio, char const *path)
|
|
{
|
|
/* not supported */
|
|
return false;
|
|
}
|
|
|
|
/***************************
|
|
** File_system interface **
|
|
***************************/
|
|
|
|
char const *name() const { return "random"; }
|
|
|
|
|
|
/********************************
|
|
** File I/O service interface **
|
|
********************************/
|
|
|
|
bool write(Sysio *sysio, Vfs_handle *handle)
|
|
{
|
|
sysio->write_out.count = sysio->write_in.count;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool read(Sysio *sysio, Vfs_handle *vfs_handle)
|
|
{
|
|
size_t nbytes = sysio->read_in.count;
|
|
|
|
_arc4random->get(sysio->read_out.chunk, nbytes);
|
|
sysio->read_out.count = nbytes;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ftruncate(Sysio *sysio, Vfs_handle *vfs_handle) { return true; }
|
|
};
|
|
}
|
|
|
|
#endif /* _NOUX__RANDOM_H_ */
|