From 415516ee0cac87dd0ee830cbcc646a9af0679e2d Mon Sep 17 00:00:00 2001 From: Mike Kazantsev Date: Mon, 29 Apr 2013 23:52:48 +0600 Subject: [PATCH 1/2] zerobinpaste: seed sjcl prng from /dev/(u)random --- tools/zerobinpaste.coffee | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/zerobinpaste.coffee b/tools/zerobinpaste.coffee index 85871ad..a4120c6 100644 --- a/tools/zerobinpaste.coffee +++ b/tools/zerobinpaste.coffee @@ -88,6 +88,22 @@ paste_file = (content, name) -> req.end() +# Seed sjcl prng from /dev/(u)random +do (bytes=64) -> + for src in ['/dev/urandom', '/dev/random', null] + break if not src or fs.existsSync(src) + if not src + console.error( 'ERROR: Failed to seed PRNG -'\ + + ' /dev/(u)random is unavailable, relying only on sjcl entropy sources' ) + return + fd = fs.openSync(src, 'r') + buff = new Buffer(bytes) + fs.readSync(fd, buff, 0, bytes) + fs.closeSync(fd) + sjcl.random.addEntropy( + (buff.readUInt32BE(n) for n in [0..bytes/4]), bytes * 8, src ) + + # Loop over file args or read stdin if not program.args or not program.args.length process.stdin.resume() From 118b0ce47dddb6e6a0a7ee78adf765d382672021 Mon Sep 17 00:00:00 2001 From: Mike Kazantsev Date: Mon, 29 Apr 2013 23:55:30 +0600 Subject: [PATCH 2/2] zerobinpaste: use 48b keys (only 6 chars) by default --- tools/zerobinpaste.coffee | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/zerobinpaste.coffee b/tools/zerobinpaste.coffee index a4120c6..068e940 100644 --- a/tools/zerobinpaste.coffee +++ b/tools/zerobinpaste.coffee @@ -5,7 +5,12 @@ program .option('-u, --url [url]', 'URL of a 0bin site.') .option('-e, --expire [period]', 'Expiration period - one of: 1_view, 1_day (default), 1_month, never.', '1_day') - .option('-c, --config [path]', 'Path to zerobin configuration file (default: ~/.zerobinpasterc).\n'\ + .option('-k, --entropy [bits]', + 'Encryption key entropy (and hence length) to use,'\ + + ' in bits, rounded up to multiple of 6 (default: 48).\n'\ + + ' That key will be processed by 1000 pbkdf2-sha256 iterations, not used as-is.', 48) + .option('-c, --config [path]', + 'Path to zerobin configuration file (default: ~/.zerobinpasterc).\n'\ + ' Should be json-file with the same keys as can be specified on the command line.\n'\ + ' Example contents: {"url": "http://some-0bin.com"}', '~/.zerobinpasterc') .parse(process.argv); @@ -40,6 +45,17 @@ if program.expire not in expire_opts + ' must be one of: ' + expire_opts.join(', ') + "." ) process.exit(1) +program.entropy = parseInt(program.entropy) + + +# Generated key will use base64 (6b per char) charset +# Key is not decoded for pbkdf2, so it's generated via base64 here just for convenience +generate_key = (entropy) -> + entropy = Math.ceil(entropy / 6) * 6 # non-6-multiple produces same-length base64 + key = sjcl.bitArray.clamp( + sjcl.random.randomWords(Math.ceil(entropy / 32), 0), entropy ) + return sjcl.codec.base64.fromBits(key, 0).replace(/\=+$/, '').replace(/\//, '-') + # Paste one dump and print URL, optionally prefixed with name paste_file = (content, name) -> @@ -48,7 +64,7 @@ paste_file = (content, name) -> content = sjcl.codec.base64.fromBits(content) # content = lzw.compress(content) - key = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0) + key = generate_key(program.entropy) content = sjcl.encrypt(key, content) content = qs.stringify content: content