remove unbuilding c code, and ...
* Remove c code that didn't compile on my machine * Replace with sjcl code * Minor modifications to mnemonic interface more bitcoreish
This commit is contained in:
parent
b523eee812
commit
54c8e04738
|
@ -3,12 +3,6 @@
|
||||||
'node_shared_openssl%': 'true'
|
'node_shared_openssl%': 'true'
|
||||||
},
|
},
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
|
||||||
'target_name': 'cryptox',
|
|
||||||
'sources': [
|
|
||||||
'src/pbkdf2_sha512.cc'
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'target_name': 'KeyModule',
|
'target_name': 'KeyModule',
|
||||||
'sources': [
|
'sources': [
|
||||||
|
|
|
@ -29,7 +29,6 @@ var modules = [
|
||||||
'lib/HierarchicalKey',
|
'lib/HierarchicalKey',
|
||||||
'lib/BIP39',
|
'lib/BIP39',
|
||||||
'lib/BIP39WordlistEn',
|
'lib/BIP39WordlistEn',
|
||||||
'lib/cryptox',
|
|
||||||
'lib/Block',
|
'lib/Block',
|
||||||
'lib/Bloom',
|
'lib/Bloom',
|
||||||
'lib/Connection',
|
'lib/Connection',
|
||||||
|
|
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 imports = require('soop').imports();
|
||||||
var coinUtil = imports.coinUtil || require('../util');
|
var coinUtil = imports.coinUtil || require('../util');
|
||||||
var cryptox = imports.cryptox || require('./cryptox');
|
var sjcl = imports.sjcl || require('./sjcl');
|
||||||
var crypto = require('crypto');
|
var SecureRandom = require('./SecureRandom');
|
||||||
var BIP39 = {};
|
|
||||||
|
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) {
|
BIP39.mnemonic = function(wordlist, bits) {
|
||||||
if (!bits)
|
if (!bits)
|
||||||
bits = 128;
|
bits = 128;
|
||||||
if (bits % 32 != 0)
|
if (bits % 32 != 0)
|
||||||
throw new Error("bits must be multiple of 32");
|
throw new Error("bits must be multiple of 32");
|
||||||
var bytes = crypto.randomBytes(bits / 8);
|
var buf = SecureRandom.getRandomBuffer(bits / 8);
|
||||||
return BIP39.to_mnemonic(wordlist, bytes);
|
return BIP39.entropy2mnemonic(wordlist, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
BIP39.to_mnemonic = function(wordlist, bytes) {
|
BIP39.entropy2mnemonic = function(wordlist, buf) {
|
||||||
var hash = coinUtil.sha256(new Buffer(bytes));
|
var hash = coinUtil.sha256(buf);
|
||||||
var bin = "";
|
var bin = "";
|
||||||
var bits = bytes.length * 8;
|
var bits = buf.length * 8;
|
||||||
for (var i = 0 ; i < bytes.length ; i++) {
|
for (var i = 0 ; i < buf.length ; i++) {
|
||||||
bin = bin + ("00000000" + bytes[i].toString(2)).slice(-8);
|
bin = bin + ("00000000" + buf[i].toString(2)).slice(-8);
|
||||||
}
|
}
|
||||||
var hashbits = hash[0].toString(2);
|
var hashbits = hash[0].toString(2);
|
||||||
hashbits = ("00000000" + hashbits).slice(-8).slice(0, bits/32);
|
hashbits = ("00000000" + hashbits).slice(-8).slice(0, bits/32);
|
||||||
bin = bin + hashbits;
|
bin = bin + hashbits;
|
||||||
if (bin.length % 11 != 0)
|
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 = "";
|
var mnemonic = "";
|
||||||
for (var i = 0 ; i < bin.length / 11 ; i++) {
|
for (var i = 0; i < bin.length / 11; i++) {
|
||||||
if (mnemonic != "")
|
if (mnemonic != "")
|
||||||
mnemonic = mnemonic + " ";
|
mnemonic = mnemonic + " ";
|
||||||
var wi = parseInt(bin.slice(i*11, (i+1)*11), 2);
|
var wi = parseInt(bin.slice(i*11, (i+1)*11), 2);
|
||||||
|
@ -35,8 +49,12 @@ BIP39.to_mnemonic = function(wordlist, bytes) {
|
||||||
return mnemonic;
|
return mnemonic;
|
||||||
}
|
}
|
||||||
|
|
||||||
BIP39.mnemonic_to_seed = function(mnemonic, passphrase) {
|
BIP39.mnemonic2seed = function(mnemonic, passphrase) {
|
||||||
return cryptox.pbkdf2Sync_sha512(mnemonic, "mnemonic" + passphrase, 2048, 64);
|
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);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 code = vector[0];
|
||||||
var mnemonic = vector[1];
|
var mnemonic = vector[1];
|
||||||
var seed = vector[2];
|
var seed = vector[2];
|
||||||
var mnemonic1 = BIP39.to_mnemonic(BIP39WordlistEn, new Buffer(code, 'hex'));
|
var mnemonic1 = BIP39.entropy2mnemonic(BIP39WordlistEn, new Buffer(code, 'hex'));
|
||||||
var seed1 = BIP39.mnemonic_to_seed(mnemonic, 'TREZOR');
|
var seed1 = BIP39.mnemonic2seed(mnemonic, 'TREZOR');
|
||||||
mnemonic1.should.equal(mnemonic);
|
mnemonic1.should.equal(mnemonic);
|
||||||
seed1.toString('hex').should.equal(seed)
|
seed1.toString('hex').should.equal(seed)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue