diff --git a/blue_modules/bip38/index.js b/blue_modules/bip38/index.js index a1b65dd85..7f8cf62f4 100644 --- a/blue_modules/bip38/index.js +++ b/blue_modules/bip38/index.js @@ -146,6 +146,7 @@ async function decrypt (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 @@ -212,6 +213,13 @@ async function decryptECMult (buffer, passphrase, progressCallback, scryptParams // 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 diff --git a/package-lock.json b/package-lock.json index 4fafd3b1e..585b80adb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11562,7 +11562,7 @@ "from": "git+https://github.com/BlueWallet/react-native-biometrics.git#2.0.0" }, "react-native-blue-crypto": { - "version": "git+https://github.com/Overtorment/react-native-blue-crypto.git#30a0a054c634033cb3d0247a0a18a95fd616e45e", + "version": "git+https://github.com/Overtorment/react-native-blue-crypto.git#21d4d914a0170adb79e009f36539b90bd25f7669", "from": "git+https://github.com/Overtorment/react-native-blue-crypto.git" }, "react-native-camera": { diff --git a/tests/unit/Bip38.test.js b/tests/unit/Bip38.test.js index bf87eb7df..6c8868128 100644 --- a/tests/unit/Bip38.test.js +++ b/tests/unit/Bip38.test.js @@ -31,6 +31,8 @@ it('bip38 decodes slow', async () => { let encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN'; let callbackWasCalled = false; let decryptedKey = await bip38.decrypt(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); @@ -39,4 +41,13 @@ it('bip38 decodes slow', async () => { wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed), 'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc', ); + + let wasError = false; + try { + await bip38.decrypt(encryptedKey, 'a'); + } catch (_) { + wasError = true; + } + + assert.ok(wasError); });