diff --git a/ports/src/noux/dir_file_system.h b/ports/src/noux/dir_file_system.h index 7699c242c5..8b1722018e 100644 --- a/ports/src/noux/dir_file_system.h +++ b/ports/src/noux/dir_file_system.h @@ -26,6 +26,8 @@ #include #include #include +#include + namespace Noux { @@ -116,6 +118,11 @@ namespace Noux { continue; } + if (sub_node.has_type("random")) { + _append_file_system(new Random_file_system(0, 0)); + continue; + } + { char type_name[64]; sub_node.type_name(type_name, sizeof(type_name)); diff --git a/ports/src/noux/random_file_system.h b/ports/src/noux/random_file_system.h new file mode 100644 index 0000000000..f023d18940 --- /dev/null +++ b/ports/src/noux/random_file_system.h @@ -0,0 +1,407 @@ +/* + * \brief Device Random filesystem + * \author Josef Soentgen + * \date 2012-07-31 + */ + +/* + * Copyright (C) 2012 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 +#include +#include + +/* Noux includes */ +#include +#include "file_system.h" + +/*- + * Copyright (c) 2010, 2012 + * Thorsten Glaser + * Copyright (c) 2012 + * Josef Soentgen + * + * 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_ */