Browse Source

fixed bip38

localNotifications
Overtorment 7 years ago
parent
commit
f2c1aa0f59
  1. 21
      App.test.js
  2. 8
      app.json
  3. 4
      bip38/.npmignore
  4. 52
      bip38/CHANGELOG.md
  5. 21
      bip38/LICENSE
  6. 70
      bip38/README.md
  7. 239
      bip38/index.js
  8. 92
      bip38/package.json
  9. 3
      bip38/scryptsy/.npmignore
  10. 44
      bip38/scryptsy/CHANGELOG.md
  11. 70
      bip38/scryptsy/README.md
  12. 195
      bip38/scryptsy/lib/scrypt.js
  13. 87
      bip38/scryptsy/package.json
  14. 1
      package.json
  15. 4
      screen/wallets/scanQrWifSegwitP2SHAddress.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

@ -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

@ -0,0 +1,4 @@
test/
.min-wd
.gitignore
.travis.yml

52
bip38/CHANGELOG.md

@ -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

@ -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

@ -0,0 +1,70 @@
# bip38
[![build status](https://secure.travis-ci.org/bitcoinjs/bip38.svg)](http://travis-ci.org/bitcoinjs/bip38)
[![Coverage Status](https://img.shields.io/coveralls/cryptocoinjs/bip38.svg)](https://coveralls.io/r/cryptocoinjs/bip38)
[![Version](http://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

239
bip38/index.js

@ -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

@ -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

@ -0,0 +1,3 @@
test/
.gitignore
.min-wd

44
bip38/scryptsy/CHANGELOG.md

@ -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

@ -0,0 +1,70 @@
scryptsy
========
[![build status](https://secure.travis-ci.org/cryptocoinjs/scryptsy.svg)](http://travis-ci.org/cryptocoinjs/scryptsy)
[![Coverage Status](https://img.shields.io/coveralls/cryptocoinjs/scryptsy.svg)](https://coveralls.io/r/cryptocoinjs/scryptsy)
[![Version](http://img.shields.io/npm/v/scryptsy.svg)](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

@ -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

@ -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"
}
}

1
package.json

@ -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",

4
screen/wallets/scanQrWifSegwitP2SHAddress.js

@ -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…
Cancel
Save