mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-20 02:09:10 +01:00
Merge pull request #3556 from BlueWallet/limpbrains-bip38
REF: move bip38 to separate repository
This commit is contained in:
commit
d0d424bf5f
@ -1,4 +0,0 @@
|
||||
test/
|
||||
.min-wd
|
||||
.gitignore
|
||||
.travis.yml
|
@ -1,52 +0,0 @@
|
||||
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
|
@ -1,21 +0,0 @@
|
||||
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.
|
@ -1,70 +0,0 @@
|
||||
# bip38
|
||||
|
||||
[![build status](https://secure.travis-ci.org/bitcoinjs/bip38.svg)](https://travis-ci.org/bitcoinjs/bip38)
|
||||
[![Coverage Status](https://img.shields.io/coveralls/cryptocoinjs/bip38.svg)](https://coveralls.io/r/cryptocoinjs/bip38)
|
||||
[![Version](https://img.shields.io/npm/v/bip38.svg)](https://www.npmjs.org/package/bip38)
|
||||
|
||||
[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](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
|
||||
|
@ -1,260 +0,0 @@
|
||||
const BlueCrypto = require('react-native-blue-crypto');
|
||||
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 scryptWrapper(secret, salt, N, r, p, dkLen, progressCallback) {
|
||||
if (BlueCrypto.isAvailable()) {
|
||||
secret = Buffer.from(secret).toString('hex');
|
||||
salt = Buffer.from(salt).toString('hex');
|
||||
const hex = await BlueCrypto.scrypt(secret, salt, N, r, p, dkLen);
|
||||
return Buffer.from(hex, 'hex');
|
||||
} else {
|
||||
// fallback to js implementation
|
||||
return scrypt(secret, salt, N, r, p, dkLen, progressCallback);
|
||||
}
|
||||
}
|
||||
|
||||
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 scryptWrapper(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 scryptWrapper(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')
|
||||
const bufferOrig = buffer;
|
||||
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 scryptWrapper(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 scryptWrapper(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)
|
||||
|
||||
// added by overtorment: see https://github.com/bitcoinjs/bip38/issues/60
|
||||
// verify salt matches address
|
||||
var address = getAddress(d, compressed)
|
||||
var checksum = hash256(address).slice(0, 4)
|
||||
var salt = bufferOrig.slice(3, 7)
|
||||
assert.deepEqual(salt, checksum)
|
||||
|
||||
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
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
{
|
||||
"_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"
|
||||
}
|
||||
}
|
@ -24,8 +24,8 @@ import { useContext } from 'react';
|
||||
import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||
import Notifications from '../blue_modules/notifications';
|
||||
import IdleTimerManager from 'react-native-idle-timer';
|
||||
import bip38 from 'bip38';
|
||||
const A = require('../blue_modules/analytics');
|
||||
const bip38 = require('../blue_modules/bip38');
|
||||
const wif = require('wif');
|
||||
const prompt = require('../blue_modules/prompt');
|
||||
|
||||
@ -171,7 +171,7 @@ function WalletImport() {
|
||||
importText = importText.trim();
|
||||
|
||||
if (importText.startsWith('6P')) {
|
||||
const decryptedKey = await bip38.decrypt(importText, password);
|
||||
const decryptedKey = await bip38.decryptAsync(importText, password);
|
||||
|
||||
if (decryptedKey) {
|
||||
importText = wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed);
|
||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -5686,6 +5686,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"bip38": {
|
||||
"version": "github:BlueWallet/bip38#60018f7c61e70584647d724b9b9264a7ebc8182e",
|
||||
"from": "github:BlueWallet/bip38",
|
||||
"requires": {
|
||||
"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",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"scryptsy": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"bip39": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
|
||||
|
@ -116,6 +116,7 @@
|
||||
"bignumber.js": "9.0.1",
|
||||
"bip21": "2.0.3",
|
||||
"bip32": "2.0.6",
|
||||
"bip38": "github:BlueWallet/bip38",
|
||||
"bip39": "3.0.4",
|
||||
"bitcoinjs-lib": "5.2.0",
|
||||
"bitcoinjs-message": "2.2.0",
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ScrollView, View, StyleSheet } from 'react-native';
|
||||
import wif from 'wif';
|
||||
import bip38 from 'bip38';
|
||||
|
||||
import loc from '../loc';
|
||||
import { BlueSpacing20, SafeBlueArea, BlueCard, BlueText, BlueLoading } from '../BlueComponents';
|
||||
@ -201,14 +203,30 @@ export default class Selftest extends Component {
|
||||
// skipping RN-specific test
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// BlueCrypto test
|
||||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
||||
const hex = await BlueCrypto.scrypt('717765727479', '4749345a22b23cf3', 64, 8, 8, 32); // using non-default parameters to speed it up (not-bip38 compliant)
|
||||
if (hex.toUpperCase() !== 'F36AB2DC12377C788D61E6770126D8A01028C8F6D8FE01871CE0489A1F696A90')
|
||||
throw new Error('react-native-blue-crypto is not ok');
|
||||
}
|
||||
|
||||
// bip38 test
|
||||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
||||
let callbackWasCalled = false;
|
||||
const decryptedKey = await bip38.decryptAsync(
|
||||
'6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN',
|
||||
'qwerty',
|
||||
() => (callbackWasCalled = true),
|
||||
);
|
||||
assertStrictEqual(
|
||||
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
|
||||
'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc',
|
||||
'bip38 failed',
|
||||
);
|
||||
// bip38 with BlueCrypto doesn't support progress callback
|
||||
assertStrictEqual(callbackWasCalled, false, "bip38 doesn't use BlueCrypto");
|
||||
}
|
||||
|
||||
// slip39 test
|
||||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
||||
const w = new SLIP39LegacyP2PKHWallet();
|
||||
@ -216,7 +234,7 @@ export default class Selftest extends Component {
|
||||
'shadow pistol academic always adequate wildlife fancy gross oasis cylinder mustang wrist rescue view short owner flip making coding armed\n' +
|
||||
'shadow pistol academic acid actress prayer class unknown daughter sweater depict flip twice unkind craft early superior advocate guest smoking',
|
||||
);
|
||||
assertStrictEqual(w._getExternalAddressByIndex(0), '18pvMjy7AJbCDtv4TLYbGPbR7SzGzjqUpj');
|
||||
assertStrictEqual(w._getExternalAddressByIndex(0), '18pvMjy7AJbCDtv4TLYbGPbR7SzGzjqUpj', 'SLIP39 failed');
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1,11 +1,10 @@
|
||||
const assert = require('assert');
|
||||
import assert from 'assert';
|
||||
import wif from 'wif';
|
||||
import bip38 from 'bip38';
|
||||
|
||||
it('bip38 decodes', async () => {
|
||||
const bip38 = require('../../blue_modules/bip38');
|
||||
const wif = require('wif');
|
||||
|
||||
const encryptedKey = '6PRVWUbkzq2VVjRuv58jpwVjTeN46MeNmzUHqUjQptBJUHGcBakduhrUNc';
|
||||
const decryptedKey = await bip38.decrypt(
|
||||
const decryptedKey = await bip38.decryptAsync(
|
||||
encryptedKey,
|
||||
'TestingOneTwoThree',
|
||||
() => {},
|
||||
@ -24,16 +23,15 @@ it('bip38 decodes slow', async () => {
|
||||
return;
|
||||
}
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000;
|
||||
const bip38 = require('../../blue_modules/bip38');
|
||||
const wif = require('wif');
|
||||
|
||||
const encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
|
||||
let callbackWasCalled = false;
|
||||
const decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', () => {
|
||||
const decryptedKey = await bip38.decryptAsync(encryptedKey, 'qwerty', () => {
|
||||
// callbacks make sense only with pure js scrypt implementation (nodejs and browsers).
|
||||
// on RN scrypt is handled by native module and takes ~4 secs
|
||||
callbackWasCalled = true;
|
||||
});
|
||||
|
||||
assert.ok(callbackWasCalled);
|
||||
|
||||
assert.strictEqual(
|
||||
@ -41,12 +39,7 @@ it('bip38 decodes slow', async () => {
|
||||
'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc',
|
||||
);
|
||||
|
||||
let wasError = false;
|
||||
try {
|
||||
await bip38.decrypt(encryptedKey, 'a');
|
||||
} catch (_) {
|
||||
wasError = true;
|
||||
}
|
||||
|
||||
assert.ok(wasError);
|
||||
await assert.rejects(async () => await bip38.decryptAsync(encryptedKey, 'a'), {
|
||||
message: 'Incorrect passphrase.',
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user