commit
ad5e83f9ff
|
@ -3,12 +3,6 @@
|
|||
'node_shared_openssl%': 'true'
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'cryptox',
|
||||
'sources': [
|
||||
'src/pbkdf2_sha512.cc'
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'KeyModule',
|
||||
'sources': [
|
||||
|
|
|
@ -29,7 +29,6 @@ var modules = [
|
|||
'lib/HierarchicalKey',
|
||||
'lib/BIP39',
|
||||
'lib/BIP39WordlistEn',
|
||||
'lib/cryptox',
|
||||
'lib/Block',
|
||||
'lib/Bloom',
|
||||
'lib/Connection',
|
||||
|
@ -81,11 +80,21 @@ var createBitcore = function(opts) {
|
|||
exec('sh concat.sh', puts);
|
||||
process.chdir(cwd);
|
||||
|
||||
if (!opts.includeall && (!opts.submodules || opts.submodules.length === 0)) {
|
||||
if (!opts.stdout) console.log('Must use either -s or -a option. For more info use the --help option');
|
||||
if (!opts.includeall && !opts.includemain && (!opts.submodules || opts.submodules.length === 0)) {
|
||||
if (!opts.stdout) console.log('Must use either -s or -a or -m option. For more info use the --help option');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var submodules = opts.submodules;
|
||||
|
||||
if (opts.includemain) {
|
||||
submodules = JSON.parse(JSON.stringify(modules));
|
||||
submodules.splice(submodules.indexOf('lib/BIP39'), 1);
|
||||
submodules.splice(submodules.indexOf('lib/BIP39WordlistEn'), 1);
|
||||
var assert = require('assert');
|
||||
assert(submodules.length == modules.length - 2);
|
||||
}
|
||||
|
||||
if (opts.submodules) {
|
||||
for (var i = 0; i < opts.submodules.length; i++) {
|
||||
var sm = opts.submodules[i];
|
||||
|
@ -114,7 +123,7 @@ var createBitcore = function(opts) {
|
|||
expose: 'bitcore'
|
||||
});
|
||||
modules.forEach(function(m) {
|
||||
if (opts.includeall || opts.submodules.indexOf(m) > -1) {
|
||||
if (opts.includeall || submodules.indexOf(m) > -1) {
|
||||
if (!opts.stdout) console.log('Including ' + m + ' in the browser bundle');
|
||||
b.require('./' + opts.dir + m + '.js', {
|
||||
expose: './' + m
|
||||
|
@ -158,6 +167,7 @@ if (require.main === module) {
|
|||
program
|
||||
.version('0.0.1')
|
||||
.option('-a, --includeall', 'Include all submodules.')
|
||||
.option('-m, --includemain', 'Include main submodules.')
|
||||
.option('-d, --dontminify', 'Don\'t minify the code.')
|
||||
.option('-o, --stdout', 'Specify output as stdout')
|
||||
.option('-D, --dir <dir>', 'Specify a base directory')
|
||||
|
|
File diff suppressed because one or more lines are too long
46
lib/BIP39.js
46
lib/BIP39.js
|
@ -1,32 +1,46 @@
|
|||
var imports = require('soop').imports();
|
||||
var coinUtil = imports.coinUtil || require('../util');
|
||||
var cryptox = imports.cryptox || require('./cryptox');
|
||||
var crypto = require('crypto');
|
||||
var BIP39 = {};
|
||||
var sjcl = imports.sjcl || require('./sjcl');
|
||||
var SecureRandom = require('./SecureRandom');
|
||||
|
||||
var hmacSHA512 = function (key) {
|
||||
var hasher = new sjcl.misc.hmac(key, sjcl.hash.sha512);
|
||||
this.encrypt = function () {
|
||||
return hasher.encrypt.apply(hasher, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
var pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) {
|
||||
var derivedKey = sjcl.misc.pbkdf2(password, salt, iterations, 512, hmacSHA512);
|
||||
return sjcl.codec.hex.fromBits(derivedKey)
|
||||
};
|
||||
|
||||
var BIP39 = function() {
|
||||
};
|
||||
|
||||
BIP39.mnemonic = function(wordlist, bits) {
|
||||
if (!bits)
|
||||
bits = 128;
|
||||
if (bits % 32 != 0)
|
||||
throw new Error("bits must be multiple of 32");
|
||||
var bytes = crypto.randomBytes(bits / 8);
|
||||
return BIP39.to_mnemonic(wordlist, bytes);
|
||||
var buf = SecureRandom.getRandomBuffer(bits / 8);
|
||||
return BIP39.entropy2mnemonic(wordlist, buf);
|
||||
}
|
||||
|
||||
BIP39.to_mnemonic = function(wordlist, bytes) {
|
||||
var hash = coinUtil.sha256(new Buffer(bytes));
|
||||
BIP39.entropy2mnemonic = function(wordlist, buf) {
|
||||
var hash = coinUtil.sha256(buf);
|
||||
var bin = "";
|
||||
var bits = bytes.length * 8;
|
||||
for (var i = 0 ; i < bytes.length ; i++) {
|
||||
bin = bin + ("00000000" + bytes[i].toString(2)).slice(-8);
|
||||
var bits = buf.length * 8;
|
||||
for (var i = 0 ; i < buf.length ; i++) {
|
||||
bin = bin + ("00000000" + buf[i].toString(2)).slice(-8);
|
||||
}
|
||||
var hashbits = hash[0].toString(2);
|
||||
hashbits = ("00000000" + hashbits).slice(-8).slice(0, bits/32);
|
||||
bin = bin + hashbits;
|
||||
if (bin.length % 11 != 0)
|
||||
throw new Error("interal error - entropy not an even multiple of 11 bits - " + bin.length);
|
||||
throw new Error("internal error - entropy not an even multiple of 11 bits - " + bin.length);
|
||||
var mnemonic = "";
|
||||
for (var i = 0 ; i < bin.length / 11 ; i++) {
|
||||
for (var i = 0; i < bin.length / 11; i++) {
|
||||
if (mnemonic != "")
|
||||
mnemonic = mnemonic + " ";
|
||||
var wi = parseInt(bin.slice(i*11, (i+1)*11), 2);
|
||||
|
@ -35,8 +49,12 @@ BIP39.to_mnemonic = function(wordlist, bytes) {
|
|||
return mnemonic;
|
||||
}
|
||||
|
||||
BIP39.mnemonic_to_seed = function(mnemonic, passphrase) {
|
||||
return cryptox.pbkdf2Sync_sha512(mnemonic, "mnemonic" + passphrase, 2048, 64);
|
||||
BIP39.mnemonic2seed = function(mnemonic, passphrase) {
|
||||
if (!passphrase)
|
||||
passphrase = "";
|
||||
var hex = pbkdf2Sync_sha512(mnemonic, "mnemonic" + passphrase, 2048, 64);
|
||||
var buf = new Buffer(hex, 'hex');
|
||||
return buf;
|
||||
}
|
||||
|
||||
module.exports = require('soop')(BIP39);
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// Crypto extensions
|
||||
//
|
||||
// PBKDF2 with SHA512 - browser version
|
||||
|
||||
var sjcl = require('../sjcl');
|
||||
|
||||
var hmacSHA512 = function (key) {
|
||||
var hasher = new sjcl.misc.hmac( key, sjcl.hash.sha512 );
|
||||
this.encrypt = function () {
|
||||
return hasher.encrypt.apply( hasher, arguments );
|
||||
};
|
||||
};
|
||||
|
||||
exports.pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) {
|
||||
var derivedKey = sjcl.misc.pbkdf2( password, salt, iterations, 512, hmacSHA512 );
|
||||
return sjcl.codec.hex.fromBits( derivedKey )
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
if (process.versions) {
|
||||
module.exports = require('./node/cryptox');
|
||||
return;
|
||||
}
|
||||
module.exports = require('./browser/cryptox');
|
|
@ -1,49 +0,0 @@
|
|||
// Crypto extensions
|
||||
//
|
||||
// PBKDF2 with SHA512
|
||||
|
||||
var binding = require('bindings')('cryptox');
|
||||
|
||||
exports.pbkdf2_sha512 = function(password, salt, iterations, keylen, callback) {
|
||||
if (typeof callback !== 'function')
|
||||
throw new Error('No callback provided to pbkdf2');
|
||||
|
||||
return pbkdf2_sha512(password, salt, iterations, keylen, callback);
|
||||
};
|
||||
|
||||
|
||||
exports.pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) {
|
||||
return pbkdf2_sha512(password, salt, iterations, keylen);
|
||||
};
|
||||
|
||||
function toBuf(str, encoding) {
|
||||
encoding = encoding || 'binary';
|
||||
if (typeof str === 'string') {
|
||||
if (encoding === 'buffer')
|
||||
encoding = 'binary';
|
||||
str = new Buffer(str, encoding);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function pbkdf2_sha512(password, salt, iterations, keylen, callback) {
|
||||
password = toBuf(password);
|
||||
salt = toBuf(salt);
|
||||
|
||||
if (exports.DEFAULT_ENCODING === 'buffer')
|
||||
return binding.PBKDF2(password, salt, iterations, keylen, callback);
|
||||
|
||||
// at this point, we need to handle encodings.
|
||||
var encoding = exports.DEFAULT_ENCODING;
|
||||
if (callback) {
|
||||
binding.PBKDF2_sha512(password, salt, iterations, keylen, function(er, ret) {
|
||||
if (ret)
|
||||
ret = ret.toString(encoding);
|
||||
callback(er, ret);
|
||||
});
|
||||
} else {
|
||||
var ret = binding.PBKDF2_sha512(password, salt, iterations, keylen);
|
||||
//return ret.toString(encoding);
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -47,9 +47,9 @@
|
|||
},
|
||||
"scripts": {
|
||||
"install": "node-gyp rebuild",
|
||||
"test": "node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
|
||||
"test": "node browser/build.js -a && node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
|
||||
"coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- --reporter spec test",
|
||||
"prepublish": "node browser/build.js -a"
|
||||
"prepublish": "node browser/build.js -m"
|
||||
},
|
||||
"dependencies": {
|
||||
"grunt-browserify": "~2.0.0",
|
||||
|
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "node_crypto.h"
|
||||
#include "node_crypto_groups.h"
|
||||
#include "v8.h"
|
||||
|
||||
#include "node_internals.h"
|
||||
#include "node.h"
|
||||
#include "node_buffer.h"
|
||||
#include "string_bytes.h"
|
||||
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
# define OPENSSL_CONST const
|
||||
#else
|
||||
# define OPENSSL_CONST
|
||||
#endif
|
||||
|
||||
#define ASSERT_IS_STRING_OR_BUFFER(val) \
|
||||
if (!Buffer::HasInstance(val) && !val->IsString()) { \
|
||||
return ThrowException(Exception::TypeError(String::New( \
|
||||
"Not a string or buffer"))); \
|
||||
}
|
||||
|
||||
#define ASSERT_IS_BUFFER(val) \
|
||||
if (!Buffer::HasInstance(val)) { \
|
||||
return ThrowException(Exception::TypeError(String::New("Not a buffer"))); \
|
||||
}
|
||||
|
||||
namespace node {
|
||||
namespace cryptox {
|
||||
|
||||
using namespace v8;
|
||||
|
||||
struct pbkdf2_req {
|
||||
uv_work_t work_req;
|
||||
int err;
|
||||
char* pass;
|
||||
size_t passlen;
|
||||
char* salt;
|
||||
size_t saltlen;
|
||||
size_t iter;
|
||||
char* key;
|
||||
size_t keylen;
|
||||
Persistent<Object> obj;
|
||||
};
|
||||
|
||||
|
||||
void EIO_PBKDF2_SHA512(pbkdf2_req* req) {
|
||||
req->err = PKCS5_PBKDF2_HMAC(
|
||||
req->pass,
|
||||
req->passlen,
|
||||
(unsigned char*)req->salt,
|
||||
req->saltlen,
|
||||
req->iter,
|
||||
EVP_sha512(),
|
||||
req->keylen,
|
||||
(unsigned char*)req->key);
|
||||
memset(req->pass, 0, req->passlen);
|
||||
memset(req->salt, 0, req->saltlen);
|
||||
}
|
||||
|
||||
|
||||
void EIO_PBKDF2_SHA512(uv_work_t* work_req) {
|
||||
pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);
|
||||
EIO_PBKDF2_SHA512(req);
|
||||
}
|
||||
|
||||
|
||||
void EIO_PBKDF2After_SHA512(pbkdf2_req* req, Local<Value> argv[2]) {
|
||||
if (req->err) {
|
||||
argv[0] = Local<Value>::New(Undefined());
|
||||
argv[1] = Encode(req->key, req->keylen, BUFFER);
|
||||
memset(req->key, 0, req->keylen);
|
||||
} else {
|
||||
argv[0] = Exception::Error(String::New("PBKDF2 error"));
|
||||
argv[1] = Local<Value>::New(Undefined());
|
||||
}
|
||||
|
||||
delete[] req->pass;
|
||||
delete[] req->salt;
|
||||
delete[] req->key;
|
||||
delete req;
|
||||
}
|
||||
|
||||
|
||||
void EIO_PBKDF2After_SHA512(uv_work_t* work_req, int status) {
|
||||
assert(status == 0);
|
||||
pbkdf2_req* req = container_of(work_req, pbkdf2_req, work_req);
|
||||
HandleScope scope;
|
||||
Local<Value> argv[2];
|
||||
Persistent<Object> obj = req->obj;
|
||||
EIO_PBKDF2After_SHA512(req, argv);
|
||||
MakeCallback(obj, "ondone", ARRAY_SIZE(argv), argv);
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
|
||||
Handle<Value> PBKDF2_SHA512(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
const char* type_error = NULL;
|
||||
char* pass = NULL;
|
||||
char* salt = NULL;
|
||||
ssize_t passlen = -1;
|
||||
ssize_t saltlen = -1;
|
||||
ssize_t keylen = -1;
|
||||
ssize_t pass_written = -1;
|
||||
ssize_t salt_written = -1;
|
||||
ssize_t iter = -1;
|
||||
pbkdf2_req* req = NULL;
|
||||
|
||||
if (args.Length() != 4 && args.Length() != 5) {
|
||||
type_error = "Bad parameter";
|
||||
goto err;
|
||||
}
|
||||
|
||||
ASSERT_IS_BUFFER(args[0]);
|
||||
passlen = Buffer::Length(args[0]);
|
||||
if (passlen < 0) {
|
||||
type_error = "Bad password";
|
||||
goto err;
|
||||
}
|
||||
|
||||
pass = new char[passlen];
|
||||
pass_written = DecodeWrite(pass, passlen, args[0], BINARY);
|
||||
assert(pass_written == passlen);
|
||||
|
||||
ASSERT_IS_BUFFER(args[1]);
|
||||
saltlen = Buffer::Length(args[1]);
|
||||
if (saltlen < 0) {
|
||||
type_error = "Bad salt";
|
||||
goto err;
|
||||
}
|
||||
|
||||
salt = new char[saltlen];
|
||||
salt_written = DecodeWrite(salt, saltlen, args[1], BINARY);
|
||||
assert(salt_written == saltlen);
|
||||
|
||||
if (!args[2]->IsNumber()) {
|
||||
type_error = "Iterations not a number";
|
||||
goto err;
|
||||
}
|
||||
|
||||
iter = args[2]->Int32Value();
|
||||
if (iter < 0) {
|
||||
type_error = "Bad iterations";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!args[3]->IsNumber()) {
|
||||
type_error = "Key length not a number";
|
||||
goto err;
|
||||
}
|
||||
|
||||
keylen = args[3]->Int32Value();
|
||||
if (keylen < 0) {
|
||||
type_error = "Bad key length";
|
||||
goto err;
|
||||
}
|
||||
|
||||
req = new pbkdf2_req;
|
||||
req->err = 0;
|
||||
req->pass = pass;
|
||||
req->passlen = passlen;
|
||||
req->salt = salt;
|
||||
req->saltlen = saltlen;
|
||||
req->iter = iter;
|
||||
req->key = new char[keylen];
|
||||
req->keylen = keylen;
|
||||
|
||||
if (args[4]->IsFunction()) {
|
||||
req->obj = Persistent<Object>::New(Object::New());
|
||||
req->obj->Set(String::New("ondone"), args[4]);
|
||||
uv_queue_work(uv_default_loop(),
|
||||
&req->work_req,
|
||||
EIO_PBKDF2_SHA512,
|
||||
EIO_PBKDF2After_SHA512);
|
||||
return Undefined();
|
||||
} else {
|
||||
Local<Value> argv[2];
|
||||
EIO_PBKDF2_SHA512(req);
|
||||
EIO_PBKDF2After_SHA512(req, argv);
|
||||
if (argv[0]->IsObject()) return ThrowException(argv[0]);
|
||||
return scope.Close(argv[1]);
|
||||
}
|
||||
|
||||
err:
|
||||
delete[] salt;
|
||||
delete[] pass;
|
||||
return ThrowException(Exception::TypeError(String::New(type_error)));
|
||||
}
|
||||
|
||||
void InitCryptox(Handle<Object> target) {
|
||||
NODE_SET_METHOD(target, "PBKDF2_sha512", PBKDF2_SHA512);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
NODE_MODULE(cryptox, node::cryptox::InitCryptox)
|
||||
|
|
@ -151,8 +151,8 @@ describe('BIP39', function() {
|
|||
var code = vector[0];
|
||||
var mnemonic = vector[1];
|
||||
var seed = vector[2];
|
||||
var mnemonic1 = BIP39.to_mnemonic(BIP39WordlistEn, new Buffer(code, 'hex'));
|
||||
var seed1 = BIP39.mnemonic_to_seed(mnemonic, 'TREZOR');
|
||||
var mnemonic1 = BIP39.entropy2mnemonic(BIP39WordlistEn, new Buffer(code, 'hex'));
|
||||
var seed1 = BIP39.mnemonic2seed(mnemonic, 'TREZOR');
|
||||
mnemonic1.should.equal(mnemonic);
|
||||
seed1.toString('hex').should.equal(seed)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue