mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-20 14:05:27 +01:00
fixed bip38
This commit is contained in:
parent
e8660a0424
commit
f2c1aa0f59
15 changed files with 905 additions and 6 deletions
21
App.test.js
21
App.test.js
|
@ -1,4 +1,4 @@
|
|||
/* global describe, it, expect, jest */
|
||||
/* global describe, it, expect, jest, jasmine */
|
||||
import React from 'react';
|
||||
import { LegacyWallet, SegwitP2SHWallet, AppStorage } from './class';
|
||||
import renderer from 'react-test-renderer';
|
||||
|
@ -183,7 +183,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
|||
});
|
||||
|
||||
it('bip38 decodes', async () => {
|
||||
const bip38 = require('bip38');
|
||||
const bip38 = require('./bip38');
|
||||
const wif = require('wif');
|
||||
|
||||
let encryptedKey =
|
||||
|
@ -201,6 +201,23 @@ it('bip38 decodes', async () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('bip38 decodes slow', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
|
||||
const bip38 = require('bip38');
|
||||
const wif = require('wif');
|
||||
|
||||
let encryptedKey =
|
||||
'6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
|
||||
let decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', status =>
|
||||
process.stdout.write(parseInt(status.percent) + '%\r'),
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
|
||||
'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc',
|
||||
);
|
||||
});
|
||||
|
||||
it('Wallet can fetch UTXO', async () => {
|
||||
let w = new SegwitP2SHWallet();
|
||||
w._address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
||||
|
|
8
app.json
8
app.json
|
@ -5,9 +5,13 @@
|
|||
"privacy": "public",
|
||||
"platforms": ["ios"],
|
||||
"ios": {
|
||||
"buildNumber": "1.0.5",
|
||||
"buildNumber": "11",
|
||||
"isRemoteJSEnabled":false,
|
||||
"bundleIdentifier": "com.igorkorsakov.bluewallet"
|
||||
"bundleIdentifier": "io.bluewallet.bluewallet",
|
||||
"infoPlist": {
|
||||
"NSLocationWhenInUseUsageDescription": "Discover local stores nearby that accept Bitcoin",
|
||||
"NSCameraUsageDescription": "Allow BlueWallet to scan QR codes"
|
||||
}
|
||||
},
|
||||
"name":"Blue Wallet",
|
||||
"description":"Bitcoin wallet app. Alpha version (iOS only)",
|
||||
|
|
4
bip38/.npmignore
Normal file
4
bip38/.npmignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
test/
|
||||
.min-wd
|
||||
.gitignore
|
||||
.travis.yml
|
52
bip38/CHANGELOG.md
Normal file
52
bip38/CHANGELOG.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
2.0.0 / 2016-12-20
|
||||
------------------
|
||||
- removed class instantiation. Removed `coinstring` dep.
|
||||
|
||||
1.4.0 / 2015-11-03
|
||||
------------------
|
||||
- added `progressCallback`. See: https://github.com/bitcoinjs/bip38/pull/16
|
||||
|
||||
1.3.0 / 2015-06-04
|
||||
------------------
|
||||
- use `createHash` and `aes` directly. https://github.com/cryptocoinjs/bip38
|
||||
- JavaScript Standard Style
|
||||
|
||||
1.2.0 / 2015-01-05
|
||||
------------------
|
||||
- removed dependency upon `aes` package since Browserify now supports aes [Daniel Cousens](https://github.com/cryptocoinjs/bip38/pull/6)
|
||||
- removed `crypto-browserify` devDep and removed `browser` field from `package.json`; no longer necessary
|
||||
- added method `verify()` [Daniel Cousens](https://github.com/cryptocoinjs/bip38/pull/7)
|
||||
|
||||
1.1.1 / 2014-09-19
|
||||
------------------
|
||||
- bugfix: enforce zero padding [Daniel Cousens](https://github.com/cryptocoinjs/bip38/commit/e73598d0fc1d1b3c04c132c34053e96bec6bd201)
|
||||
- add MIT license to package.json
|
||||
|
||||
1.1.0 / 2014-07-11
|
||||
------------------
|
||||
- added methods `encryptRaw` and `decryptRaw` [Daniel Cousens](https://github.com/cryptocoinjs/bip38/pull/4)
|
||||
|
||||
1.0.0 / 2014-06-10
|
||||
------------------
|
||||
- upgraded `"scryptsy": "~0.2.0"` to `"scryptsy": "^1.0.0"`
|
||||
- upgraded `"bigi": "~0.2.0"` to `"bigi": "^1.2.0"`
|
||||
- removed `ecurve-names` dep
|
||||
- upgraded `"ecurve": "~0.3.0"` to `"ecurve": "^0.8.0"`
|
||||
- removed semicolons per http://cryptocoinjs.com/about/contributing/#semicolons
|
||||
- removed `crypto-hashing` dep
|
||||
- removed `bs58` dep, added `coinstring` dep
|
||||
- removed `terst` for `assert`
|
||||
- added TravisCI
|
||||
- added Coveralls
|
||||
- added testling
|
||||
- removed static level methods, must call `new`
|
||||
|
||||
0.1.0 / 2014-03-05
|
||||
------------------
|
||||
- added support to decrypt ECMultiplied keys, #1
|
||||
- made constructor work without `new`
|
||||
- upgraded deps `ecurve`, `ecurve-names`, and `scryptsy`
|
||||
|
||||
0.0.1 / 2014-02-28
|
||||
------------------
|
||||
- initial release
|
21
bip38/LICENSE
Normal file
21
bip38/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2014 Cryptocoinjs 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.
|
70
bip38/README.md
Normal file
70
bip38/README.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
# bip38
|
||||
|
||||
[](http://travis-ci.org/bitcoinjs/bip38)
|
||||
[](https://coveralls.io/r/cryptocoinjs/bip38)
|
||||
[](https://www.npmjs.org/package/bip38)
|
||||
|
||||
[](https://github.com/feross/standard)
|
||||
|
||||
A JavaScript component that adheres to the [BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) standard to secure your crypto currency private keys. Fully compliant with Node.js and the browser (via Browserify).
|
||||
|
||||
|
||||
## Why?
|
||||
BIP38 is a standard process to encrypt Bitcoin and crypto currency private keys that is imprevious to brute force attacks thus protecting the user.
|
||||
|
||||
|
||||
## Package Info
|
||||
- homepage: [http://cryptocoinjs.com/modules/currency/bip38/](http://cryptocoinjs.com/modules/currency/bip38/)
|
||||
- github: [https://github.com/cryptocoinjs/bip38](https://github.com/cryptocoinjs/bip38)
|
||||
- tests: [https://github.com/cryptocoinjs/bip38/tree/master/test](https://github.com/cryptocoinjs/bip38/tree/master/test)
|
||||
- issues: [https://github.com/cryptocoinjs/bip38/issues](https://github.com/cryptocoinjs/bip38/issues)
|
||||
- license: **MIT**
|
||||
- versioning: [http://semver-ftw.org](http://semver-ftw.org)
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Installation
|
||||
|
||||
npm install --save bip38
|
||||
|
||||
|
||||
### API
|
||||
### encrypt(buffer, compressed, passphrase[, progressCallback, scryptParams])
|
||||
|
||||
``` javascript
|
||||
var bip38 = require('bip38')
|
||||
var wif = require('wif')
|
||||
|
||||
var myWifString = '5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR'
|
||||
var decoded = wif.decode(myWifString)
|
||||
|
||||
var encryptedKey = bip38.encrypt(decoded.privateKey, decoded.compressed, 'TestingOneTwoThree')
|
||||
console.log(encryptedKey)
|
||||
// => '6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg'
|
||||
```
|
||||
|
||||
|
||||
### decrypt(encryptedKey, passhprase[, progressCallback, scryptParams])
|
||||
|
||||
``` javascript
|
||||
var bip38 = require('bip38')
|
||||
var wif = require('wif')
|
||||
|
||||
var encryptedKey = '6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg'
|
||||
var decryptedKey = bip38.decrypt(encryptedKey, 'TestingOneTwoThree', function (status) {
|
||||
console.log(status.percent) // will print the precent every time current increases by 1000
|
||||
})
|
||||
|
||||
console.log(wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed))
|
||||
// => '5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR'
|
||||
```
|
||||
|
||||
|
||||
# References
|
||||
- https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki
|
||||
- https://github.com/pointbiz/bitaddress.org/issues/56 (Safari 6.05 issue)
|
||||
- https://github.com/casascius/Bitcoin-Address-Utility/tree/master/Model
|
||||
- https://github.com/nomorecoin/python-bip38-testing/blob/master/bip38.py
|
||||
- https://github.com/pointbiz/bitaddress.org/blob/master/src/ninja.key.js
|
||||
|
239
bip38/index.js
Normal file
239
bip38/index.js
Normal file
|
@ -0,0 +1,239 @@
|
|||
var aes = require('browserify-aes')
|
||||
var assert = require('assert')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var bs58check = require('bs58check')
|
||||
var createHash = require('create-hash')
|
||||
var scrypt = require('./scryptsy')
|
||||
var xor = require('buffer-xor/inplace')
|
||||
|
||||
var ecurve = require('ecurve')
|
||||
var curve = ecurve.getCurveByName('secp256k1')
|
||||
|
||||
var BigInteger = require('bigi')
|
||||
|
||||
// constants
|
||||
var SCRYPT_PARAMS = {
|
||||
N: 16384, // specified by BIP38
|
||||
r: 8,
|
||||
p: 8
|
||||
}
|
||||
var NULL = Buffer.alloc(0)
|
||||
|
||||
function hash160 (buffer) {
|
||||
return createHash('rmd160').update(
|
||||
createHash('sha256').update(buffer).digest()
|
||||
).digest()
|
||||
}
|
||||
|
||||
function hash256 (buffer) {
|
||||
return createHash('sha256').update(
|
||||
createHash('sha256').update(buffer).digest()
|
||||
).digest()
|
||||
}
|
||||
|
||||
function getAddress (d, compressed) {
|
||||
var Q = curve.G.multiply(d).getEncoded(compressed)
|
||||
var hash = hash160(Q)
|
||||
var payload = Buffer.allocUnsafe(21)
|
||||
payload.writeUInt8(0x00, 0) // XXX TODO FIXME bitcoin only??? damn you BIP38
|
||||
hash.copy(payload, 1)
|
||||
|
||||
return bs58check.encode(payload)
|
||||
}
|
||||
|
||||
async function encryptRaw (buffer, compressed, passphrase, progressCallback, scryptParams) {
|
||||
if (buffer.length !== 32) throw new Error('Invalid private key length')
|
||||
scryptParams = scryptParams || SCRYPT_PARAMS
|
||||
|
||||
var d = BigInteger.fromBuffer(buffer)
|
||||
var address = getAddress(d, compressed)
|
||||
var secret = Buffer.from(passphrase, 'utf8')
|
||||
var salt = hash256(address).slice(0, 4)
|
||||
|
||||
var N = scryptParams.N
|
||||
var r = scryptParams.r
|
||||
var p = scryptParams.p
|
||||
|
||||
var scryptBuf = await scrypt(secret, salt, N, r, p, 64, progressCallback)
|
||||
var derivedHalf1 = scryptBuf.slice(0, 32)
|
||||
var derivedHalf2 = scryptBuf.slice(32, 64)
|
||||
|
||||
var xorBuf = xor(derivedHalf1, buffer)
|
||||
var cipher = aes.createCipheriv('aes-256-ecb', derivedHalf2, NULL)
|
||||
cipher.setAutoPadding(false)
|
||||
cipher.end(xorBuf)
|
||||
|
||||
var cipherText = cipher.read()
|
||||
|
||||
// 0x01 | 0x42 | flagByte | salt (4) | cipherText (32)
|
||||
var result = Buffer.allocUnsafe(7 + 32)
|
||||
result.writeUInt8(0x01, 0)
|
||||
result.writeUInt8(0x42, 1)
|
||||
result.writeUInt8(compressed ? 0xe0 : 0xc0, 2)
|
||||
salt.copy(result, 3)
|
||||
cipherText.copy(result, 7)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function encrypt (buffer, compressed, passphrase, progressCallback, scryptParams) {
|
||||
return bs58check.encode(encryptRaw(buffer, compressed, passphrase, progressCallback, scryptParams))
|
||||
}
|
||||
|
||||
// some of the techniques borrowed from: https://github.com/pointbiz/bitaddress.org
|
||||
async function decryptRaw (buffer, passphrase, progressCallback, scryptParams) {
|
||||
// 39 bytes: 2 bytes prefix, 37 bytes payload
|
||||
if (buffer.length !== 39) throw new Error('Invalid BIP38 data length')
|
||||
if (buffer.readUInt8(0) !== 0x01) throw new Error('Invalid BIP38 prefix')
|
||||
scryptParams = scryptParams || SCRYPT_PARAMS
|
||||
|
||||
// check if BIP38 EC multiply
|
||||
var type = buffer.readUInt8(1)
|
||||
if (type === 0x43) return await decryptECMult(buffer, passphrase, progressCallback, scryptParams)
|
||||
if (type !== 0x42) throw new Error('Invalid BIP38 type')
|
||||
|
||||
passphrase = Buffer.from(passphrase, 'utf8')
|
||||
|
||||
var flagByte = buffer.readUInt8(2)
|
||||
var compressed = flagByte === 0xe0
|
||||
if (!compressed && flagByte !== 0xc0) throw new Error('Invalid BIP38 compression flag')
|
||||
|
||||
var N = scryptParams.N
|
||||
var r = scryptParams.r
|
||||
var p = scryptParams.p
|
||||
|
||||
var salt = buffer.slice(3, 7)
|
||||
var scryptBuf = await scrypt(passphrase, salt, N, r, p, 64, progressCallback)
|
||||
var derivedHalf1 = scryptBuf.slice(0, 32)
|
||||
var derivedHalf2 = scryptBuf.slice(32, 64)
|
||||
|
||||
var privKeyBuf = buffer.slice(7, 7 + 32)
|
||||
var decipher = aes.createDecipheriv('aes-256-ecb', derivedHalf2, NULL)
|
||||
decipher.setAutoPadding(false)
|
||||
decipher.end(privKeyBuf)
|
||||
|
||||
var plainText = decipher.read()
|
||||
var privateKey = xor(derivedHalf1, plainText)
|
||||
|
||||
// verify salt matches address
|
||||
var d = BigInteger.fromBuffer(privateKey)
|
||||
var address = getAddress(d, compressed)
|
||||
var checksum = hash256(address).slice(0, 4)
|
||||
assert.deepEqual(salt, checksum)
|
||||
|
||||
return {
|
||||
privateKey: privateKey,
|
||||
compressed: compressed
|
||||
}
|
||||
}
|
||||
|
||||
async function decrypt (string, passphrase, progressCallback, scryptParams) {
|
||||
return await decryptRaw(bs58check.decode(string), passphrase, progressCallback, scryptParams)
|
||||
}
|
||||
|
||||
async function decryptECMult (buffer, passphrase, progressCallback, scryptParams) {
|
||||
passphrase = Buffer.from(passphrase, 'utf8')
|
||||
buffer = buffer.slice(1) // FIXME: we can avoid this
|
||||
scryptParams = scryptParams || SCRYPT_PARAMS
|
||||
|
||||
var flag = buffer.readUInt8(1)
|
||||
var compressed = (flag & 0x20) !== 0
|
||||
var hasLotSeq = (flag & 0x04) !== 0
|
||||
|
||||
assert.equal((flag & 0x24), flag, 'Invalid private key.')
|
||||
|
||||
var addressHash = buffer.slice(2, 6)
|
||||
var ownerEntropy = buffer.slice(6, 14)
|
||||
var ownerSalt
|
||||
|
||||
// 4 bytes ownerSalt if 4 bytes lot/sequence
|
||||
if (hasLotSeq) {
|
||||
ownerSalt = ownerEntropy.slice(0, 4)
|
||||
|
||||
// else, 8 bytes ownerSalt
|
||||
} else {
|
||||
ownerSalt = ownerEntropy
|
||||
}
|
||||
|
||||
var encryptedPart1 = buffer.slice(14, 22) // First 8 bytes
|
||||
var encryptedPart2 = buffer.slice(22, 38) // 16 bytes
|
||||
|
||||
var N = scryptParams.N
|
||||
var r = scryptParams.r
|
||||
var p = scryptParams.p
|
||||
var preFactor = await scrypt(passphrase, ownerSalt, N, r, p, 32, progressCallback)
|
||||
|
||||
var passFactor
|
||||
if (hasLotSeq) {
|
||||
var hashTarget = Buffer.concat([preFactor, ownerEntropy])
|
||||
passFactor = hash256(hashTarget)
|
||||
} else {
|
||||
passFactor = preFactor
|
||||
}
|
||||
|
||||
var passInt = BigInteger.fromBuffer(passFactor)
|
||||
var passPoint = curve.G.multiply(passInt).getEncoded(true)
|
||||
|
||||
var seedBPass = await scrypt(passPoint, Buffer.concat([addressHash, ownerEntropy]), 1024, 1, 1, 64)
|
||||
|
||||
var derivedHalf1 = seedBPass.slice(0, 32)
|
||||
var derivedHalf2 = seedBPass.slice(32, 64)
|
||||
|
||||
var decipher = aes.createDecipheriv('aes-256-ecb', derivedHalf2, Buffer.alloc(0))
|
||||
decipher.setAutoPadding(false)
|
||||
decipher.end(encryptedPart2)
|
||||
|
||||
var decryptedPart2 = decipher.read()
|
||||
var tmp = xor(decryptedPart2, derivedHalf1.slice(16, 32))
|
||||
var seedBPart2 = tmp.slice(8, 16)
|
||||
|
||||
var decipher2 = aes.createDecipheriv('aes-256-ecb', derivedHalf2, Buffer.alloc(0))
|
||||
decipher2.setAutoPadding(false)
|
||||
decipher2.write(encryptedPart1) // first 8 bytes
|
||||
decipher2.end(tmp.slice(0, 8)) // last 8 bytes
|
||||
|
||||
var seedBPart1 = xor(decipher2.read(), derivedHalf1.slice(0, 16))
|
||||
var seedB = Buffer.concat([seedBPart1, seedBPart2], 24)
|
||||
var factorB = BigInteger.fromBuffer(hash256(seedB))
|
||||
|
||||
// d = passFactor * factorB (mod n)
|
||||
var d = passInt.multiply(factorB).mod(curve.n)
|
||||
|
||||
return {
|
||||
privateKey: d.toBuffer(32),
|
||||
compressed: compressed
|
||||
}
|
||||
}
|
||||
|
||||
function verify (string) {
|
||||
var decoded = bs58check.decodeUnsafe(string)
|
||||
if (!decoded) return false
|
||||
|
||||
if (decoded.length !== 39) return false
|
||||
if (decoded.readUInt8(0) !== 0x01) return false
|
||||
|
||||
var type = decoded.readUInt8(1)
|
||||
var flag = decoded.readUInt8(2)
|
||||
|
||||
// encrypted WIF
|
||||
if (type === 0x42) {
|
||||
if (flag !== 0xc0 && flag !== 0xe0) return false
|
||||
|
||||
// EC mult
|
||||
} else if (type === 0x43) {
|
||||
if ((flag & ~0x24)) return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
decrypt: decrypt,
|
||||
decryptECMult: decryptECMult,
|
||||
decryptRaw: decryptRaw,
|
||||
encrypt: encrypt,
|
||||
encryptRaw: encryptRaw,
|
||||
verify: verify
|
||||
}
|
92
bip38/package.json
Normal file
92
bip38/package.json
Normal file
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
"_from": "git+https://github.com/Overtorment/bip38.git",
|
||||
"_id": "bip38@2.0.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-AhDzWwDTKrQ656q2Kxb4xmDIitY=",
|
||||
"_location": "/bip38",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "git",
|
||||
"raw": "bip38@git+https://github.com/Overtorment/bip38.git",
|
||||
"name": "bip38",
|
||||
"escapedName": "bip38",
|
||||
"rawSpec": "git+https://github.com/Overtorment/bip38.git",
|
||||
"saveSpec": "git+https://github.com/Overtorment/bip38.git",
|
||||
"fetchSpec": "https://github.com/Overtorment/bip38.git",
|
||||
"gitCommittish": "master"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "git+https://github.com/Overtorment/bip38.git#7eb8701bf845f84eab71f0ef9a8db219420d080d",
|
||||
"_spec": "bip38@git+https://github.com/Overtorment/bip38.git",
|
||||
"_where": "/home/burn/Documents/BlueWallet",
|
||||
"author": {
|
||||
"name": "JP Richardson"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/bitcoinjs/bip38/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"bigi": "^1.2.0",
|
||||
"browserify-aes": "^1.0.1",
|
||||
"bs58check": "<3.0.0",
|
||||
"buffer-xor": "^1.0.2",
|
||||
"create-hash": "^1.1.1",
|
||||
"ecurve": "^1.0.0",
|
||||
"pbkdf2": "^3.0.14"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "BIP38 is a standard process to encrypt Bitcoin and crypto currency private keys that is impervious to brute force attacks thus protecting the user.",
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.10.0",
|
||||
"istanbul": "^0.2.11",
|
||||
"mocha": "^2.3.3",
|
||||
"mochify": "^2.1.1",
|
||||
"standard": "^9.0.2",
|
||||
"wif": "^2.0.1"
|
||||
},
|
||||
"homepage": "http://cryptocoinjs.com/modules/currency/bip38/",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"litecoin"
|
||||
],
|
||||
"main": "index.js",
|
||||
"name": "bip38",
|
||||
"repository": {
|
||||
"url": "git+ssh://git@github.com/bitcoinjs/bip38.git",
|
||||
"type": "git"
|
||||
},
|
||||
"scripts": {
|
||||
"browser-test": "mochify --wd -R spec --timeout 100000",
|
||||
"coverage": "istanbul cover _mocha -- --reporter list test/*.js",
|
||||
"coveralls": "npm run-script coverage && coveralls < coverage/lcov.info",
|
||||
"standard": "standard",
|
||||
"test": "npm run standard && npm run unit",
|
||||
"unit": "mocha --ui bdd --timeout 240000"
|
||||
},
|
||||
"version": "2.0.2",
|
||||
"react-native": {
|
||||
"path": "path-browserify",
|
||||
"fs": "react-native-level-fs",
|
||||
"_stream_transform": "readable-stream/transform",
|
||||
"_stream_readable": "readable-stream/readable",
|
||||
"_stream_writable": "readable-stream/writable",
|
||||
"_stream_duplex": "readable-stream/duplex",
|
||||
"_stream_passthrough": "readable-stream/passthrough",
|
||||
"stream": "stream-browserify"
|
||||
},
|
||||
"browser": {
|
||||
"path": "path-browserify",
|
||||
"fs": "react-native-level-fs",
|
||||
"_stream_transform": "readable-stream/transform",
|
||||
"_stream_readable": "readable-stream/readable",
|
||||
"_stream_writable": "readable-stream/writable",
|
||||
"_stream_duplex": "readable-stream/duplex",
|
||||
"_stream_passthrough": "readable-stream/passthrough",
|
||||
"stream": "stream-browserify"
|
||||
}
|
||||
}
|
3
bip38/scryptsy/.npmignore
Normal file
3
bip38/scryptsy/.npmignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
test/
|
||||
.gitignore
|
||||
.min-wd
|
44
bip38/scryptsy/CHANGELOG.md
Normal file
44
bip38/scryptsy/CHANGELOG.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
2.0.0 / 2016-05-26
|
||||
------------------
|
||||
- **breaking** Node v0.10 not supported anymore.
|
||||
|
||||
1.2.1 / 2015-03-01
|
||||
------------------
|
||||
- now using standard for code formatting
|
||||
- now using `pbkdf2` module over `pbkdf2-sha256`, huge performance increase in Node
|
||||
|
||||
1.2.0 / 2014-12-11
|
||||
------------------
|
||||
- upgraded `pbkdf2-sha256` from `1.0.1` to `1.1.0`
|
||||
- removed `browser` field for `crypto`; not-necessary anymore
|
||||
|
||||
1.1.0 / 2014-07-28
|
||||
------------------
|
||||
- added `progressCallback` (Nadav Ivgi / #4)[https://github.com/cryptocoinjs/scryptsy/pull/4]
|
||||
|
||||
1.0.0 / 2014-06-10
|
||||
------------------
|
||||
- moved tests to fixtures
|
||||
- removed semilcolons per http://cryptocoinjs.com/about/contributing/#semicolons
|
||||
- changed `module.exports.scrypt = funct..` to `module.exports = funct...`
|
||||
- removed `terst` from dev deps
|
||||
- upgraded `"pbkdf2-sha256": "~0.1.1"` to `"pbkdf2-sha256": "^1.0.1"`
|
||||
- added `crypto-browserify` dev dep for `pbkdf2-sha256` tests
|
||||
- added TravisCI
|
||||
- added Coveralls
|
||||
- added testling
|
||||
|
||||
0.2.0 / 2014-03-05
|
||||
------------------
|
||||
- made a lot of scrypt functions internal along with variables to make thread safe
|
||||
|
||||
0.1.0 / 2014-02-18
|
||||
------------------
|
||||
- changed spacing from 4 to 2
|
||||
- removed unneeded JavaScript implementations. Using `pbkdf2-sha256` dep now.
|
||||
- add browser test support
|
||||
- convert from `Array` to typed arrays and `Buffer`
|
||||
|
||||
0.0.1 / 2014-02-18
|
||||
------------------
|
||||
- initial release. Forked from https://github.com/cheongwy/node-scrypt-js and added tests.
|
70
bip38/scryptsy/README.md
Normal file
70
bip38/scryptsy/README.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
scryptsy
|
||||
========
|
||||
|
||||
[](http://travis-ci.org/cryptocoinjs/scryptsy)
|
||||
[](https://coveralls.io/r/cryptocoinjs/scryptsy)
|
||||
[](https://www.npmjs.org/package/scryptsy)
|
||||
|
||||
`scryptsy` is a pure Javascript implementation of the [scrypt][wiki] key derivation function that is fully compatible with Node.js and the browser (via Browserify).
|
||||
|
||||
|
||||
Why?
|
||||
----
|
||||
|
||||
`Scrypt` is an integral part of many crypto currencies. It's a part of the [BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) standard for encrypting private Bitcoin keys. It also serves as the [proof-of-work system](http://en.wikipedia.org/wiki/Proof-of-work_system) for many crypto currencies, most notably: Litecoin and Dogecoin.
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
npm install --save scryptsy
|
||||
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
```js
|
||||
var scrypt = require('scryptsy')
|
||||
|
||||
var key = "pleaseletmein"
|
||||
var salt = "SodiumChloride"
|
||||
var data = scrypt(key, salt, 16384, 8, 1, 64)
|
||||
console.log(data.toString('hex'))
|
||||
// => 7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887
|
||||
```
|
||||
|
||||
|
||||
API
|
||||
---
|
||||
|
||||
### scrypt(key, salt, N, r, p, keyLenBytes, [progressCallback])
|
||||
|
||||
- **key**: The key. Either `Buffer` or `string`.
|
||||
- **salt**: The salt. Either `Buffer` or `string`.
|
||||
- **N**: The number of iterations. `number` (integer)
|
||||
- **r**: Memory factor. `number` (integer)
|
||||
- **p**: Parallelization factor. `number` (integer)
|
||||
- **keyLenBytes**: The number of bytes to return. `number` (integer)
|
||||
- **progressCallback**: Call callback on every `1000` ops. Passes in `{current, total, percent}` as first parameter to `progressCallback()`.
|
||||
|
||||
Returns `Buffer`.
|
||||
|
||||
|
||||
|
||||
Resources
|
||||
---------
|
||||
- [Tarsnap Blurb on Scrypt][tarsnap]
|
||||
- [Scrypt Whitepaper](http://www.tarsnap.com/scrypt/scrypt.pdf)
|
||||
- [IETF Scrypt](https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00) (Test vector params are [incorrect](https://twitter.com/dchest/status/247734446881640448).)
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
MIT
|
||||
|
||||
|
||||
[wiki]: http://en.wikipedia.org/wiki/Scrypt
|
||||
[tarsnap]: http://www.tarsnap.com/scrypt.html
|
195
bip38/scryptsy/lib/scrypt.js
Normal file
195
bip38/scryptsy/lib/scrypt.js
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* eslint-disable camelcase */
|
||||
let pbkdf2 = require('pbkdf2')
|
||||
|
||||
var MAX_VALUE = 0x7fffffff
|
||||
|
||||
// N = Cpu cost, r = Memory cost, p = parallelization cost
|
||||
async function scrypt (key, salt, N, r, p, dkLen, progressCallback) {
|
||||
if (N === 0 || (N & (N - 1)) !== 0) throw Error('N must be > 0 and a power of 2')
|
||||
|
||||
if (N > MAX_VALUE / 128 / r) throw Error('Parameter N is too large')
|
||||
if (r > MAX_VALUE / 128 / p) throw Error('Parameter r is too large')
|
||||
|
||||
var XY = new Buffer(256 * r)
|
||||
var V = new Buffer(128 * r * N)
|
||||
|
||||
// pseudo global
|
||||
var B32 = new Int32Array(16) // salsa20_8
|
||||
var x = new Int32Array(16) // salsa20_8
|
||||
var _X = new Buffer(64) // blockmix_salsa8
|
||||
|
||||
// pseudo global
|
||||
var B = pbkdf2.pbkdf2Sync(key, salt, 1, p * 128 * r, 'sha256')
|
||||
|
||||
var tickCallback
|
||||
if (progressCallback) {
|
||||
var totalOps = p * N * 2
|
||||
var currentOp = 0
|
||||
|
||||
tickCallback = function () {
|
||||
return new Promise(function(resolve, reject) {
|
||||
++currentOp
|
||||
|
||||
// send progress notifications once every 1,000 ops
|
||||
if (currentOp % 1000 === 0) {
|
||||
progressCallback({
|
||||
current: currentOp,
|
||||
total: totalOps,
|
||||
percent: (currentOp / totalOps) * 100.0
|
||||
})
|
||||
setTimeout(resolve, 10)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < p; i++) {
|
||||
await smix(B, i * 128 * r, r, N, V, XY)
|
||||
if (typeof shold_stop_bip38 !== 'undefined') break;
|
||||
}
|
||||
|
||||
return pbkdf2.pbkdf2Sync(key, B, 1, dkLen, 'sha256')
|
||||
|
||||
// all of these functions are actually moved to the top
|
||||
// due to function hoisting
|
||||
|
||||
async function smix (B, Bi, r, N, V, XY) {
|
||||
var Xi = 0
|
||||
var Yi = 128 * r
|
||||
var i
|
||||
|
||||
B.copy(XY, Xi, Bi, Bi + Yi)
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
XY.copy(V, i * Yi, Xi, Xi + Yi)
|
||||
blockmix_salsa8(XY, Xi, Yi, r)
|
||||
|
||||
if (tickCallback) {
|
||||
await tickCallback()
|
||||
if (typeof shold_stop_bip38 !== 'undefined') break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
var offset = Xi + (2 * r - 1) * 64
|
||||
var j = XY.readUInt32LE(offset) & (N - 1)
|
||||
blockxor(V, j * Yi, XY, Xi, Yi)
|
||||
blockmix_salsa8(XY, Xi, Yi, r)
|
||||
|
||||
if (tickCallback) {
|
||||
await tickCallback()
|
||||
if (typeof shold_stop_bip38 !== 'undefined') break;
|
||||
}
|
||||
}
|
||||
|
||||
XY.copy(B, Bi, Xi, Xi + Yi)
|
||||
}
|
||||
|
||||
function blockmix_salsa8 (BY, Bi, Yi, r) {
|
||||
var i
|
||||
|
||||
arraycopy(BY, Bi + (2 * r - 1) * 64, _X, 0, 64)
|
||||
|
||||
for (i = 0; i < 2 * r; i++) {
|
||||
blockxor(BY, i * 64, _X, 0, 64)
|
||||
salsa20_8(_X)
|
||||
arraycopy(_X, 0, BY, Yi + (i * 64), 64)
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
arraycopy(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64)
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
arraycopy(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64)
|
||||
}
|
||||
}
|
||||
|
||||
function R (a, b) {
|
||||
return (a << b) | (a >>> (32 - b))
|
||||
}
|
||||
|
||||
function salsa20_8 (B) {
|
||||
var i
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
B32[i] = (B[i * 4 + 0] & 0xff) << 0
|
||||
B32[i] |= (B[i * 4 + 1] & 0xff) << 8
|
||||
B32[i] |= (B[i * 4 + 2] & 0xff) << 16
|
||||
B32[i] |= (B[i * 4 + 3] & 0xff) << 24
|
||||
// B32[i] = B.readUInt32LE(i*4) <--- this is signficantly slower even in Node.js
|
||||
}
|
||||
|
||||
arraycopy(B32, 0, x, 0, 16)
|
||||
|
||||
for (i = 8; i > 0; i -= 2) {
|
||||
x[4] ^= R(x[0] + x[12], 7)
|
||||
x[8] ^= R(x[4] + x[0], 9)
|
||||
x[12] ^= R(x[8] + x[4], 13)
|
||||
x[0] ^= R(x[12] + x[8], 18)
|
||||
x[9] ^= R(x[5] + x[1], 7)
|
||||
x[13] ^= R(x[9] + x[5], 9)
|
||||
x[1] ^= R(x[13] + x[9], 13)
|
||||
x[5] ^= R(x[1] + x[13], 18)
|
||||
x[14] ^= R(x[10] + x[6], 7)
|
||||
x[2] ^= R(x[14] + x[10], 9)
|
||||
x[6] ^= R(x[2] + x[14], 13)
|
||||
x[10] ^= R(x[6] + x[2], 18)
|
||||
x[3] ^= R(x[15] + x[11], 7)
|
||||
x[7] ^= R(x[3] + x[15], 9)
|
||||
x[11] ^= R(x[7] + x[3], 13)
|
||||
x[15] ^= R(x[11] + x[7], 18)
|
||||
x[1] ^= R(x[0] + x[3], 7)
|
||||
x[2] ^= R(x[1] + x[0], 9)
|
||||
x[3] ^= R(x[2] + x[1], 13)
|
||||
x[0] ^= R(x[3] + x[2], 18)
|
||||
x[6] ^= R(x[5] + x[4], 7)
|
||||
x[7] ^= R(x[6] + x[5], 9)
|
||||
x[4] ^= R(x[7] + x[6], 13)
|
||||
x[5] ^= R(x[4] + x[7], 18)
|
||||
x[11] ^= R(x[10] + x[9], 7)
|
||||
x[8] ^= R(x[11] + x[10], 9)
|
||||
x[9] ^= R(x[8] + x[11], 13)
|
||||
x[10] ^= R(x[9] + x[8], 18)
|
||||
x[12] ^= R(x[15] + x[14], 7)
|
||||
x[13] ^= R(x[12] + x[15], 9)
|
||||
x[14] ^= R(x[13] + x[12], 13)
|
||||
x[15] ^= R(x[14] + x[13], 18)
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i]
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
var bi = i * 4
|
||||
B[bi + 0] = (B32[i] >> 0 & 0xff)
|
||||
B[bi + 1] = (B32[i] >> 8 & 0xff)
|
||||
B[bi + 2] = (B32[i] >> 16 & 0xff)
|
||||
B[bi + 3] = (B32[i] >> 24 & 0xff)
|
||||
// B.writeInt32LE(B32[i], i*4) //<--- this is signficantly slower even in Node.js
|
||||
}
|
||||
}
|
||||
|
||||
// naive approach... going back to loop unrolling may yield additional performance
|
||||
function blockxor (S, Si, D, Di, len) {
|
||||
for (var i = 0; i < len; i++) {
|
||||
D[Di + i] ^= S[Si + i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function arraycopy (src, srcPos, dest, destPos, length) {
|
||||
if (Buffer.isBuffer(src) && Buffer.isBuffer(dest)) {
|
||||
src.copy(dest, destPos, srcPos, srcPos + length)
|
||||
} else {
|
||||
while (length--) {
|
||||
dest[destPos++] = src[srcPos++]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = scrypt
|
87
bip38/scryptsy/package.json
Normal file
87
bip38/scryptsy/package.json
Normal file
|
@ -0,0 +1,87 @@
|
|||
{
|
||||
"_from": "scryptsy@^2.0.0",
|
||||
"_id": "scryptsy@2.0.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-Jiw28CMc+nZU4jY/o5TNLexm83g=",
|
||||
"_location": "/scryptsy",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "scryptsy@^2.0.0",
|
||||
"name": "scryptsy",
|
||||
"escapedName": "scryptsy",
|
||||
"rawSpec": "^2.0.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^2.0.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.0.0.tgz",
|
||||
"_shasum": "262c36f0231cfa7654e2363fa394cd2dec66f378",
|
||||
"_spec": "scryptsy@^2.0.0",
|
||||
"_where": "/home/burn/Documents/bip38",
|
||||
"author": "",
|
||||
"bugs": {
|
||||
"url": "https://github.com/cryptocoinjs/scryptsy/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": false,
|
||||
"description": "Pure JavaScript implementation of the scrypt key deriviation function that is fully compatible with Node.js and the browser.",
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.10.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"mocha": "^2.2.0",
|
||||
"mochify": "^2.1.0",
|
||||
"standard": "^7.1.1"
|
||||
},
|
||||
"homepage": "https://github.com/cryptocoinjs/scryptsy#readme",
|
||||
"keywords": [
|
||||
"crytpo",
|
||||
"cryptography",
|
||||
"scrypt",
|
||||
"kdf",
|
||||
"litecoin",
|
||||
"dogecoin",
|
||||
"bitcoin",
|
||||
"bip38"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/scrypt.js",
|
||||
"name": "scryptsy",
|
||||
"repository": {
|
||||
"url": "git+ssh://git@github.com/cryptocoinjs/scryptsy.git",
|
||||
"type": "git"
|
||||
},
|
||||
"scripts": {
|
||||
"browser-test": "mochify --wd -R spec",
|
||||
"coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter list test/*.js",
|
||||
"coveralls": "npm run-script coverage && node ./node_modules/.bin/coveralls < coverage/lcov.info",
|
||||
"lint": "standard",
|
||||
"test": "mocha --ui bdd",
|
||||
"unit": "mocha"
|
||||
},
|
||||
"version": "2.0.0",
|
||||
"react-native": {
|
||||
"path": "path-browserify",
|
||||
"fs": "react-native-level-fs",
|
||||
"_stream_transform": "readable-stream/transform",
|
||||
"_stream_readable": "readable-stream/readable",
|
||||
"_stream_writable": "readable-stream/writable",
|
||||
"_stream_duplex": "readable-stream/duplex",
|
||||
"_stream_passthrough": "readable-stream/passthrough",
|
||||
"stream": "stream-browserify"
|
||||
},
|
||||
"browser": {
|
||||
"path": "path-browserify",
|
||||
"fs": "react-native-level-fs",
|
||||
"_stream_transform": "readable-stream/transform",
|
||||
"_stream_readable": "readable-stream/readable",
|
||||
"_stream_writable": "readable-stream/writable",
|
||||
"_stream_duplex": "readable-stream/duplex",
|
||||
"_stream_passthrough": "readable-stream/passthrough",
|
||||
"stream": "stream-browserify"
|
||||
}
|
||||
}
|
|
@ -41,7 +41,6 @@
|
|||
"asyncstorage-down": "^3.1.1",
|
||||
"bignumber.js": "^5.0.0",
|
||||
"bip21": "^2.0.1",
|
||||
"bip38": "https://github.com/Overtorment/bip38",
|
||||
"wif": "^2.0.1",
|
||||
"bitcoinjs-lib": "^3.3.2",
|
||||
"buffer": "^4.9.1",
|
||||
|
|
|
@ -14,7 +14,7 @@ import Ionicons from 'react-native-vector-icons/Ionicons';
|
|||
import PropTypes from 'prop-types';
|
||||
let BlueApp = require('../../BlueApp');
|
||||
let EV = require('../../events');
|
||||
let bip38 = require('bip38');
|
||||
let bip38 = require('../../bip38');
|
||||
let wif = require('wif');
|
||||
let prompt = require('../../prompt');
|
||||
|
||||
|
@ -46,6 +46,7 @@ export default class CameraExample extends React.Component {
|
|||
console.log('onBarCodeRead', ret);
|
||||
if (ret.data[0] === '6') {
|
||||
// password-encrypted, need to ask for password and decrypt
|
||||
console.log('trying to decrypt...');
|
||||
|
||||
this.setState({
|
||||
message: 'Decoding',
|
||||
|
@ -74,6 +75,7 @@ export default class CameraExample extends React.Component {
|
|||
decryptedKey.compressed,
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
this.setState({ message: false });
|
||||
return alert('Bad password');
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue