@ethersproject/json-wallets
Advanced tools
Comparing version 5.0.0-beta.136 to 5.0.0-beta.137
@@ -1,1 +0,1 @@ | ||
export declare const version = "json-wallets/5.0.0-beta.136"; | ||
export declare const version = "json-wallets/5.0.0-beta.137"; |
@@ -1,1 +0,1 @@ | ||
export const version = "json-wallets/5.0.0-beta.136"; | ||
export const version = "json-wallets/5.0.0-beta.137"; |
@@ -5,4 +5,5 @@ import { Bytes } from "@ethersproject/bytes"; | ||
import { getJsonWalletAddress, isCrowdsaleWallet, isKeystoreWallet } from "./inspect"; | ||
import { decrypt as decryptKeystore, encrypt as encryptKeystore, EncryptOptions, ProgressCallback } from "./keystore"; | ||
import { decrypt as decryptKeystore, decryptSync as decryptKeystoreSync, encrypt as encryptKeystore, EncryptOptions, ProgressCallback } from "./keystore"; | ||
declare function decryptJsonWallet(json: string, password: Bytes | string, progressCallback?: ProgressCallback): Promise<ExternallyOwnedAccount>; | ||
export { decryptCrowdsale, decryptKeystore, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, ProgressCallback, EncryptOptions, }; | ||
declare function decryptJsonWalletSync(json: string, password: Bytes | string): ExternallyOwnedAccount; | ||
export { decryptCrowdsale, decryptKeystore, decryptKeystoreSync, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, decryptJsonWalletSync, ProgressCallback, EncryptOptions, }; |
"use strict"; | ||
import { decrypt as decryptCrowdsale } from "./crowdsale"; | ||
import { getJsonWalletAddress, isCrowdsaleWallet, isKeystoreWallet } from "./inspect"; | ||
import { decrypt as decryptKeystore, encrypt as encryptKeystore } from "./keystore"; | ||
import { decrypt as decryptKeystore, decryptSync as decryptKeystoreSync, encrypt as encryptKeystore } from "./keystore"; | ||
function decryptJsonWallet(json, password, progressCallback) { | ||
@@ -21,2 +21,11 @@ if (isCrowdsaleWallet(json)) { | ||
} | ||
export { decryptCrowdsale, decryptKeystore, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, }; | ||
function decryptJsonWalletSync(json, password) { | ||
if (isCrowdsaleWallet(json)) { | ||
return decryptCrowdsale(json, password); | ||
} | ||
if (isKeystoreWallet(json)) { | ||
return decryptKeystoreSync(json, password); | ||
} | ||
throw new Error("invalid JSON wallet"); | ||
} | ||
export { decryptCrowdsale, decryptKeystore, decryptKeystoreSync, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, decryptJsonWalletSync, }; |
@@ -31,4 +31,5 @@ import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; | ||
}; | ||
export declare function decryptSync(json: string, password: Bytes | string): KeystoreAccount; | ||
export declare function decrypt(json: string, password: Bytes | string, progressCallback?: ProgressCallback): Promise<KeystoreAccount>; | ||
export declare function encrypt(account: ExternallyOwnedAccount, password: Bytes | string, options?: EncryptOptions, progressCallback?: ProgressCallback): Promise<string>; | ||
export {}; |
@@ -18,3 +18,3 @@ "use strict"; | ||
import { keccak256 } from "@ethersproject/keccak256"; | ||
import { pbkdf2 } from "@ethersproject/pbkdf2"; | ||
import { pbkdf2 as _pbkdf2 } from "@ethersproject/pbkdf2"; | ||
import { randomBytes } from "@ethersproject/random"; | ||
@@ -36,126 +36,133 @@ import { Description } from "@ethersproject/properties"; | ||
} | ||
export function decrypt(json, password, progressCallback) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const data = JSON.parse(json); | ||
const passwordBytes = getPassword(password); | ||
const decrypt = function (key, ciphertext) { | ||
const cipher = searchPath(data, "crypto/cipher"); | ||
if (cipher === "aes-128-ctr") { | ||
const iv = looseArrayify(searchPath(data, "crypto/cipherparams/iv")); | ||
const counter = new aes.Counter(iv); | ||
const aesCtr = new aes.ModeOfOperation.ctr(key, counter); | ||
return arrayify(aesCtr.decrypt(ciphertext)); | ||
function _decrypt(data, key, ciphertext) { | ||
const cipher = searchPath(data, "crypto/cipher"); | ||
if (cipher === "aes-128-ctr") { | ||
const iv = looseArrayify(searchPath(data, "crypto/cipherparams/iv")); | ||
const counter = new aes.Counter(iv); | ||
const aesCtr = new aes.ModeOfOperation.ctr(key, counter); | ||
return arrayify(aesCtr.decrypt(ciphertext)); | ||
} | ||
return null; | ||
} | ||
function _getAccount(data, key) { | ||
const ciphertext = looseArrayify(searchPath(data, "crypto/ciphertext")); | ||
const computedMAC = hexlify(keccak256(concat([key.slice(16, 32), ciphertext]))).substring(2); | ||
if (computedMAC !== searchPath(data, "crypto/mac").toLowerCase()) { | ||
throw new Error("invalid password"); | ||
} | ||
const privateKey = _decrypt(data, key.slice(0, 16), ciphertext); | ||
if (!privateKey) { | ||
logger.throwError("unsupported cipher", Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "decrypt" | ||
}); | ||
} | ||
const mnemonicKey = key.slice(32, 64); | ||
const address = computeAddress(privateKey); | ||
if (data.address) { | ||
let check = data.address.toLowerCase(); | ||
if (check.substring(0, 2) !== "0x") { | ||
check = "0x" + check; | ||
} | ||
if (getAddress(check) !== address) { | ||
throw new Error("address mismatch"); | ||
} | ||
} | ||
const account = { | ||
_isKeystoreAccount: true, | ||
address: address, | ||
privateKey: hexlify(privateKey) | ||
}; | ||
// Version 0.1 x-ethers metadata must contain an encrypted mnemonic phrase | ||
if (searchPath(data, "x-ethers/version") === "0.1") { | ||
const mnemonicCiphertext = looseArrayify(searchPath(data, "x-ethers/mnemonicCiphertext")); | ||
const mnemonicIv = looseArrayify(searchPath(data, "x-ethers/mnemonicCounter")); | ||
const mnemonicCounter = new aes.Counter(mnemonicIv); | ||
const mnemonicAesCtr = new aes.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter); | ||
const path = searchPath(data, "x-ethers/path") || defaultPath; | ||
const locale = searchPath(data, "x-ethers/locale") || "en"; | ||
const entropy = arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext)); | ||
try { | ||
const mnemonic = entropyToMnemonic(entropy, locale); | ||
const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path); | ||
if (node.privateKey != account.privateKey) { | ||
throw new Error("mnemonic mismatch"); | ||
} | ||
return null; | ||
account.mnemonic = node.mnemonic; | ||
} | ||
catch (error) { | ||
// If we don't have the locale wordlist installed to | ||
// read this mnemonic, just bail and don't set the | ||
// mnemonic | ||
if (error.code !== Logger.errors.INVALID_ARGUMENT || error.argument !== "wordlist") { | ||
throw error; | ||
} | ||
} | ||
} | ||
return new KeystoreAccount(account); | ||
} | ||
function pbkdf2Sync(passwordBytes, salt, count, dkLen, prfFunc) { | ||
return arrayify(_pbkdf2(passwordBytes, salt, count, dkLen, prfFunc)); | ||
} | ||
function pbkdf2(passwordBytes, salt, count, dkLen, prfFunc) { | ||
return Promise.resolve(pbkdf2Sync(passwordBytes, salt, count, dkLen, prfFunc)); | ||
} | ||
function _computeKdfKey(data, password, pbkdf2Func, scryptFunc, progressCallback) { | ||
const passwordBytes = getPassword(password); | ||
const kdf = searchPath(data, "crypto/kdf"); | ||
if (kdf && typeof (kdf) === "string") { | ||
const throwError = function (name, value) { | ||
return logger.throwArgumentError("invalid key-derivation function parameters", name, value); | ||
}; | ||
const computeMAC = function (derivedHalf, ciphertext) { | ||
return keccak256(concat([derivedHalf, ciphertext])); | ||
}; | ||
const getAccount = function (key) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const ciphertext = looseArrayify(searchPath(data, "crypto/ciphertext")); | ||
const computedMAC = hexlify(computeMAC(key.slice(16, 32), ciphertext)).substring(2); | ||
if (computedMAC !== searchPath(data, "crypto/mac").toLowerCase()) { | ||
throw new Error("invalid password"); | ||
} | ||
const privateKey = decrypt(key.slice(0, 16), ciphertext); | ||
const mnemonicKey = key.slice(32, 64); | ||
if (!privateKey) { | ||
logger.throwError("unsupported cipher", Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "decrypt" | ||
}); | ||
} | ||
const address = computeAddress(privateKey); | ||
if (data.address) { | ||
let check = data.address.toLowerCase(); | ||
if (check.substring(0, 2) !== "0x") { | ||
check = "0x" + check; | ||
} | ||
if (getAddress(check) !== address) { | ||
throw new Error("address mismatch"); | ||
} | ||
} | ||
const account = { | ||
_isKeystoreAccount: true, | ||
address: address, | ||
privateKey: hexlify(privateKey) | ||
}; | ||
// Version 0.1 x-ethers metadata must contain an encrypted mnemonic phrase | ||
if (searchPath(data, "x-ethers/version") === "0.1") { | ||
const mnemonicCiphertext = looseArrayify(searchPath(data, "x-ethers/mnemonicCiphertext")); | ||
const mnemonicIv = looseArrayify(searchPath(data, "x-ethers/mnemonicCounter")); | ||
const mnemonicCounter = new aes.Counter(mnemonicIv); | ||
const mnemonicAesCtr = new aes.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter); | ||
const path = searchPath(data, "x-ethers/path") || defaultPath; | ||
const locale = searchPath(data, "x-ethers/locale") || "en"; | ||
const entropy = arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext)); | ||
try { | ||
const mnemonic = entropyToMnemonic(entropy, locale); | ||
const node = HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path); | ||
if (node.privateKey != account.privateKey) { | ||
throw new Error("mnemonic mismatch"); | ||
} | ||
account.mnemonic = node.mnemonic; | ||
} | ||
catch (error) { | ||
// If we don't have the locale wordlist installed to | ||
// read this mnemonic, just bail and don't set the | ||
// mnemonic | ||
if (error.code !== Logger.errors.INVALID_ARGUMENT || error.argument !== "wordlist") { | ||
throw error; | ||
} | ||
} | ||
} | ||
return new KeystoreAccount(account); | ||
}); | ||
}; | ||
const kdf = searchPath(data, "crypto/kdf"); | ||
if (kdf && typeof (kdf) === "string") { | ||
const throwError = function (name, value) { | ||
return logger.throwArgumentError("invalid key-derivation function parameters", name, value); | ||
}; | ||
if (kdf.toLowerCase() === "scrypt") { | ||
const salt = looseArrayify(searchPath(data, "crypto/kdfparams/salt")); | ||
const N = parseInt(searchPath(data, "crypto/kdfparams/n")); | ||
const r = parseInt(searchPath(data, "crypto/kdfparams/r")); | ||
const p = parseInt(searchPath(data, "crypto/kdfparams/p")); | ||
// Check for all required parameters | ||
if (!N || !r || !p) { | ||
throwError("kdf", kdf); | ||
} | ||
// Make sure N is a power of 2 | ||
if ((N & (N - 1)) !== 0) { | ||
throwError("N", N); | ||
} | ||
const dkLen = parseInt(searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
const key = yield scrypt.scrypt(passwordBytes, salt, N, r, p, 64, progressCallback); | ||
//key = arrayify(key); | ||
return getAccount(key); | ||
if (kdf.toLowerCase() === "scrypt") { | ||
const salt = looseArrayify(searchPath(data, "crypto/kdfparams/salt")); | ||
const N = parseInt(searchPath(data, "crypto/kdfparams/n")); | ||
const r = parseInt(searchPath(data, "crypto/kdfparams/r")); | ||
const p = parseInt(searchPath(data, "crypto/kdfparams/p")); | ||
// Check for all required parameters | ||
if (!N || !r || !p) { | ||
throwError("kdf", kdf); | ||
} | ||
else if (kdf.toLowerCase() === "pbkdf2") { | ||
const salt = looseArrayify(searchPath(data, "crypto/kdfparams/salt")); | ||
let prfFunc = null; | ||
const prf = searchPath(data, "crypto/kdfparams/prf"); | ||
if (prf === "hmac-sha256") { | ||
prfFunc = "sha256"; | ||
} | ||
else if (prf === "hmac-sha512") { | ||
prfFunc = "sha512"; | ||
} | ||
else { | ||
throwError("prf", prf); | ||
} | ||
const c = parseInt(searchPath(data, "crypto/kdfparams/c")); | ||
const dkLen = parseInt(searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
const key = arrayify(pbkdf2(passwordBytes, salt, c, dkLen, prfFunc)); | ||
return getAccount(key); | ||
// Make sure N is a power of 2 | ||
if ((N & (N - 1)) !== 0) { | ||
throwError("N", N); | ||
} | ||
const dkLen = parseInt(searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
return scryptFunc(passwordBytes, salt, N, r, p, 64, progressCallback); | ||
} | ||
return logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf); | ||
else if (kdf.toLowerCase() === "pbkdf2") { | ||
const salt = looseArrayify(searchPath(data, "crypto/kdfparams/salt")); | ||
let prfFunc = null; | ||
const prf = searchPath(data, "crypto/kdfparams/prf"); | ||
if (prf === "hmac-sha256") { | ||
prfFunc = "sha256"; | ||
} | ||
else if (prf === "hmac-sha512") { | ||
prfFunc = "sha512"; | ||
} | ||
else { | ||
throwError("prf", prf); | ||
} | ||
const count = parseInt(searchPath(data, "crypto/kdfparams/c")); | ||
const dkLen = parseInt(searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
return pbkdf2Func(passwordBytes, salt, count, dkLen, prfFunc); | ||
} | ||
} | ||
return logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf); | ||
} | ||
export function decryptSync(json, password) { | ||
const data = JSON.parse(json); | ||
const key = _computeKdfKey(data, password, pbkdf2Sync, scrypt.syncScrypt); | ||
return _getAccount(data, key); | ||
} | ||
export function decrypt(json, password, progressCallback) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const data = JSON.parse(json); | ||
const key = yield _computeKdfKey(data, password, pbkdf2, scrypt.scrypt, progressCallback); | ||
return _getAccount(data, key); | ||
}); | ||
@@ -162,0 +169,0 @@ } |
@@ -1,1 +0,1 @@ | ||
export declare const version = "json-wallets/5.0.0-beta.136"; | ||
export declare const version = "json-wallets/5.0.0-beta.137"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.version = "json-wallets/5.0.0-beta.136"; | ||
exports.version = "json-wallets/5.0.0-beta.137"; |
@@ -5,4 +5,5 @@ import { Bytes } from "@ethersproject/bytes"; | ||
import { getJsonWalletAddress, isCrowdsaleWallet, isKeystoreWallet } from "./inspect"; | ||
import { decrypt as decryptKeystore, encrypt as encryptKeystore, EncryptOptions, ProgressCallback } from "./keystore"; | ||
import { decrypt as decryptKeystore, decryptSync as decryptKeystoreSync, encrypt as encryptKeystore, EncryptOptions, ProgressCallback } from "./keystore"; | ||
declare function decryptJsonWallet(json: string, password: Bytes | string, progressCallback?: ProgressCallback): Promise<ExternallyOwnedAccount>; | ||
export { decryptCrowdsale, decryptKeystore, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, ProgressCallback, EncryptOptions, }; | ||
declare function decryptJsonWalletSync(json: string, password: Bytes | string): ExternallyOwnedAccount; | ||
export { decryptCrowdsale, decryptKeystore, decryptKeystoreSync, encryptKeystore, isCrowdsaleWallet, isKeystoreWallet, getJsonWalletAddress, decryptJsonWallet, decryptJsonWalletSync, ProgressCallback, EncryptOptions, }; |
@@ -11,2 +11,3 @@ "use strict"; | ||
exports.decryptKeystore = keystore_1.decrypt; | ||
exports.decryptKeystoreSync = keystore_1.decryptSync; | ||
exports.encryptKeystore = keystore_1.encrypt; | ||
@@ -30,1 +31,11 @@ function decryptJsonWallet(json, password, progressCallback) { | ||
exports.decryptJsonWallet = decryptJsonWallet; | ||
function decryptJsonWalletSync(json, password) { | ||
if (inspect_1.isCrowdsaleWallet(json)) { | ||
return crowdsale_1.decrypt(json, password); | ||
} | ||
if (inspect_1.isKeystoreWallet(json)) { | ||
return keystore_1.decryptSync(json, password); | ||
} | ||
throw new Error("invalid JSON wallet"); | ||
} | ||
exports.decryptJsonWalletSync = decryptJsonWalletSync; |
@@ -31,4 +31,5 @@ import { ExternallyOwnedAccount } from "@ethersproject/abstract-signer"; | ||
}; | ||
export declare function decryptSync(json: string, password: Bytes | string): KeystoreAccount; | ||
export declare function decrypt(json: string, password: Bytes | string, progressCallback?: ProgressCallback): Promise<KeystoreAccount>; | ||
export declare function encrypt(account: ExternallyOwnedAccount, password: Bytes | string, options?: EncryptOptions, progressCallback?: ProgressCallback): Promise<string>; | ||
export {}; |
@@ -92,5 +92,132 @@ "use strict"; | ||
exports.KeystoreAccount = KeystoreAccount; | ||
function _decrypt(data, key, ciphertext) { | ||
var cipher = utils_1.searchPath(data, "crypto/cipher"); | ||
if (cipher === "aes-128-ctr") { | ||
var iv = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/cipherparams/iv")); | ||
var counter = new aes_js_1.default.Counter(iv); | ||
var aesCtr = new aes_js_1.default.ModeOfOperation.ctr(key, counter); | ||
return bytes_1.arrayify(aesCtr.decrypt(ciphertext)); | ||
} | ||
return null; | ||
} | ||
function _getAccount(data, key) { | ||
var ciphertext = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/ciphertext")); | ||
var computedMAC = bytes_1.hexlify(keccak256_1.keccak256(bytes_1.concat([key.slice(16, 32), ciphertext]))).substring(2); | ||
if (computedMAC !== utils_1.searchPath(data, "crypto/mac").toLowerCase()) { | ||
throw new Error("invalid password"); | ||
} | ||
var privateKey = _decrypt(data, key.slice(0, 16), ciphertext); | ||
if (!privateKey) { | ||
logger.throwError("unsupported cipher", logger_1.Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "decrypt" | ||
}); | ||
} | ||
var mnemonicKey = key.slice(32, 64); | ||
var address = transactions_1.computeAddress(privateKey); | ||
if (data.address) { | ||
var check = data.address.toLowerCase(); | ||
if (check.substring(0, 2) !== "0x") { | ||
check = "0x" + check; | ||
} | ||
if (address_1.getAddress(check) !== address) { | ||
throw new Error("address mismatch"); | ||
} | ||
} | ||
var account = { | ||
_isKeystoreAccount: true, | ||
address: address, | ||
privateKey: bytes_1.hexlify(privateKey) | ||
}; | ||
// Version 0.1 x-ethers metadata must contain an encrypted mnemonic phrase | ||
if (utils_1.searchPath(data, "x-ethers/version") === "0.1") { | ||
var mnemonicCiphertext = utils_1.looseArrayify(utils_1.searchPath(data, "x-ethers/mnemonicCiphertext")); | ||
var mnemonicIv = utils_1.looseArrayify(utils_1.searchPath(data, "x-ethers/mnemonicCounter")); | ||
var mnemonicCounter = new aes_js_1.default.Counter(mnemonicIv); | ||
var mnemonicAesCtr = new aes_js_1.default.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter); | ||
var path = utils_1.searchPath(data, "x-ethers/path") || hdnode_1.defaultPath; | ||
var locale = utils_1.searchPath(data, "x-ethers/locale") || "en"; | ||
var entropy = bytes_1.arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext)); | ||
try { | ||
var mnemonic = hdnode_1.entropyToMnemonic(entropy, locale); | ||
var node = hdnode_1.HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path); | ||
if (node.privateKey != account.privateKey) { | ||
throw new Error("mnemonic mismatch"); | ||
} | ||
account.mnemonic = node.mnemonic; | ||
} | ||
catch (error) { | ||
// If we don't have the locale wordlist installed to | ||
// read this mnemonic, just bail and don't set the | ||
// mnemonic | ||
if (error.code !== logger_1.Logger.errors.INVALID_ARGUMENT || error.argument !== "wordlist") { | ||
throw error; | ||
} | ||
} | ||
} | ||
return new KeystoreAccount(account); | ||
} | ||
function pbkdf2Sync(passwordBytes, salt, count, dkLen, prfFunc) { | ||
return bytes_1.arrayify(pbkdf2_1.pbkdf2(passwordBytes, salt, count, dkLen, prfFunc)); | ||
} | ||
function pbkdf2(passwordBytes, salt, count, dkLen, prfFunc) { | ||
return Promise.resolve(pbkdf2Sync(passwordBytes, salt, count, dkLen, prfFunc)); | ||
} | ||
function _computeKdfKey(data, password, pbkdf2Func, scryptFunc, progressCallback) { | ||
var passwordBytes = utils_1.getPassword(password); | ||
var kdf = utils_1.searchPath(data, "crypto/kdf"); | ||
if (kdf && typeof (kdf) === "string") { | ||
var throwError = function (name, value) { | ||
return logger.throwArgumentError("invalid key-derivation function parameters", name, value); | ||
}; | ||
if (kdf.toLowerCase() === "scrypt") { | ||
var salt = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/kdfparams/salt")); | ||
var N = parseInt(utils_1.searchPath(data, "crypto/kdfparams/n")); | ||
var r = parseInt(utils_1.searchPath(data, "crypto/kdfparams/r")); | ||
var p = parseInt(utils_1.searchPath(data, "crypto/kdfparams/p")); | ||
// Check for all required parameters | ||
if (!N || !r || !p) { | ||
throwError("kdf", kdf); | ||
} | ||
// Make sure N is a power of 2 | ||
if ((N & (N - 1)) !== 0) { | ||
throwError("N", N); | ||
} | ||
var dkLen = parseInt(utils_1.searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
return scryptFunc(passwordBytes, salt, N, r, p, 64, progressCallback); | ||
} | ||
else if (kdf.toLowerCase() === "pbkdf2") { | ||
var salt = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/kdfparams/salt")); | ||
var prfFunc = null; | ||
var prf = utils_1.searchPath(data, "crypto/kdfparams/prf"); | ||
if (prf === "hmac-sha256") { | ||
prfFunc = "sha256"; | ||
} | ||
else if (prf === "hmac-sha512") { | ||
prfFunc = "sha512"; | ||
} | ||
else { | ||
throwError("prf", prf); | ||
} | ||
var count = parseInt(utils_1.searchPath(data, "crypto/kdfparams/c")); | ||
var dkLen = parseInt(utils_1.searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
return pbkdf2Func(passwordBytes, salt, count, dkLen, prfFunc); | ||
} | ||
} | ||
return logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf); | ||
} | ||
function decryptSync(json, password) { | ||
var data = JSON.parse(json); | ||
var key = _computeKdfKey(data, password, pbkdf2Sync, scrypt.syncScrypt); | ||
return _getAccount(data, key); | ||
} | ||
exports.decryptSync = decryptSync; | ||
function decrypt(json, password, progressCallback) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var data, passwordBytes, decrypt, computeMAC, getAccount, kdf, throwError, salt, N, r, p, dkLen, key, salt, prfFunc, prf, c, dkLen, key; | ||
var data, key; | ||
return __generator(this, function (_a) { | ||
@@ -100,128 +227,6 @@ switch (_a.label) { | ||
data = JSON.parse(json); | ||
passwordBytes = utils_1.getPassword(password); | ||
decrypt = function (key, ciphertext) { | ||
var cipher = utils_1.searchPath(data, "crypto/cipher"); | ||
if (cipher === "aes-128-ctr") { | ||
var iv = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/cipherparams/iv")); | ||
var counter = new aes_js_1.default.Counter(iv); | ||
var aesCtr = new aes_js_1.default.ModeOfOperation.ctr(key, counter); | ||
return bytes_1.arrayify(aesCtr.decrypt(ciphertext)); | ||
} | ||
return null; | ||
}; | ||
computeMAC = function (derivedHalf, ciphertext) { | ||
return keccak256_1.keccak256(bytes_1.concat([derivedHalf, ciphertext])); | ||
}; | ||
getAccount = function (key) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var ciphertext, computedMAC, privateKey, mnemonicKey, address, check, account, mnemonicCiphertext, mnemonicIv, mnemonicCounter, mnemonicAesCtr, path, locale, entropy, mnemonic, node; | ||
return __generator(this, function (_a) { | ||
ciphertext = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/ciphertext")); | ||
computedMAC = bytes_1.hexlify(computeMAC(key.slice(16, 32), ciphertext)).substring(2); | ||
if (computedMAC !== utils_1.searchPath(data, "crypto/mac").toLowerCase()) { | ||
throw new Error("invalid password"); | ||
} | ||
privateKey = decrypt(key.slice(0, 16), ciphertext); | ||
mnemonicKey = key.slice(32, 64); | ||
if (!privateKey) { | ||
logger.throwError("unsupported cipher", logger_1.Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "decrypt" | ||
}); | ||
} | ||
address = transactions_1.computeAddress(privateKey); | ||
if (data.address) { | ||
check = data.address.toLowerCase(); | ||
if (check.substring(0, 2) !== "0x") { | ||
check = "0x" + check; | ||
} | ||
if (address_1.getAddress(check) !== address) { | ||
throw new Error("address mismatch"); | ||
} | ||
} | ||
account = { | ||
_isKeystoreAccount: true, | ||
address: address, | ||
privateKey: bytes_1.hexlify(privateKey) | ||
}; | ||
// Version 0.1 x-ethers metadata must contain an encrypted mnemonic phrase | ||
if (utils_1.searchPath(data, "x-ethers/version") === "0.1") { | ||
mnemonicCiphertext = utils_1.looseArrayify(utils_1.searchPath(data, "x-ethers/mnemonicCiphertext")); | ||
mnemonicIv = utils_1.looseArrayify(utils_1.searchPath(data, "x-ethers/mnemonicCounter")); | ||
mnemonicCounter = new aes_js_1.default.Counter(mnemonicIv); | ||
mnemonicAesCtr = new aes_js_1.default.ModeOfOperation.ctr(mnemonicKey, mnemonicCounter); | ||
path = utils_1.searchPath(data, "x-ethers/path") || hdnode_1.defaultPath; | ||
locale = utils_1.searchPath(data, "x-ethers/locale") || "en"; | ||
entropy = bytes_1.arrayify(mnemonicAesCtr.decrypt(mnemonicCiphertext)); | ||
try { | ||
mnemonic = hdnode_1.entropyToMnemonic(entropy, locale); | ||
node = hdnode_1.HDNode.fromMnemonic(mnemonic, null, locale).derivePath(path); | ||
if (node.privateKey != account.privateKey) { | ||
throw new Error("mnemonic mismatch"); | ||
} | ||
account.mnemonic = node.mnemonic; | ||
} | ||
catch (error) { | ||
// If we don't have the locale wordlist installed to | ||
// read this mnemonic, just bail and don't set the | ||
// mnemonic | ||
if (error.code !== logger_1.Logger.errors.INVALID_ARGUMENT || error.argument !== "wordlist") { | ||
throw error; | ||
} | ||
} | ||
} | ||
return [2 /*return*/, new KeystoreAccount(account)]; | ||
}); | ||
}); | ||
}; | ||
kdf = utils_1.searchPath(data, "crypto/kdf"); | ||
if (!(kdf && typeof (kdf) === "string")) return [3 /*break*/, 3]; | ||
throwError = function (name, value) { | ||
return logger.throwArgumentError("invalid key-derivation function parameters", name, value); | ||
}; | ||
if (!(kdf.toLowerCase() === "scrypt")) return [3 /*break*/, 2]; | ||
salt = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/kdfparams/salt")); | ||
N = parseInt(utils_1.searchPath(data, "crypto/kdfparams/n")); | ||
r = parseInt(utils_1.searchPath(data, "crypto/kdfparams/r")); | ||
p = parseInt(utils_1.searchPath(data, "crypto/kdfparams/p")); | ||
// Check for all required parameters | ||
if (!N || !r || !p) { | ||
throwError("kdf", kdf); | ||
} | ||
// Make sure N is a power of 2 | ||
if ((N & (N - 1)) !== 0) { | ||
throwError("N", N); | ||
} | ||
dkLen = parseInt(utils_1.searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
return [4 /*yield*/, scrypt.scrypt(passwordBytes, salt, N, r, p, 64, progressCallback)]; | ||
return [4 /*yield*/, _computeKdfKey(data, password, pbkdf2, scrypt.scrypt, progressCallback)]; | ||
case 1: | ||
key = _a.sent(); | ||
//key = arrayify(key); | ||
return [2 /*return*/, getAccount(key)]; | ||
case 2: | ||
if (kdf.toLowerCase() === "pbkdf2") { | ||
salt = utils_1.looseArrayify(utils_1.searchPath(data, "crypto/kdfparams/salt")); | ||
prfFunc = null; | ||
prf = utils_1.searchPath(data, "crypto/kdfparams/prf"); | ||
if (prf === "hmac-sha256") { | ||
prfFunc = "sha256"; | ||
} | ||
else if (prf === "hmac-sha512") { | ||
prfFunc = "sha512"; | ||
} | ||
else { | ||
throwError("prf", prf); | ||
} | ||
c = parseInt(utils_1.searchPath(data, "crypto/kdfparams/c")); | ||
dkLen = parseInt(utils_1.searchPath(data, "crypto/kdfparams/dklen")); | ||
if (dkLen !== 32) { | ||
throwError("dklen", dkLen); | ||
} | ||
key = bytes_1.arrayify(pbkdf2_1.pbkdf2(passwordBytes, salt, c, dkLen, prfFunc)); | ||
return [2 /*return*/, getAccount(key)]; | ||
} | ||
_a.label = 3; | ||
case 3: return [2 /*return*/, logger.throwArgumentError("unsupported key-derivation function", "kdf", kdf)]; | ||
return [2 /*return*/, _getAccount(data, key)]; | ||
} | ||
@@ -228,0 +233,0 @@ }); |
@@ -39,5 +39,5 @@ { | ||
}, | ||
"tarballHash": "0x8090a7e2dad9b2fb916389e0c7796d9bde973caf1eb55600b6d817449905cd54", | ||
"tarballHash": "0x444f5beaea128ad7f3894689177e2b70875b2ddd08fcae32a0dd09d499f6bf81", | ||
"types": "./lib/index.d.ts", | ||
"version": "5.0.0-beta.136" | ||
"version": "5.0.0-beta.137" | ||
} |
@@ -27,3 +27,3 @@ declare module "aes-js" { | ||
export function scrypt(password: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number, callback?: ProgressCallback): Promise<Uint8Array>; | ||
export function scryptSync(password: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number): Uint8Array; | ||
export function syncScrypt(password: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number): Uint8Array; | ||
} | ||
@@ -30,0 +30,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1253
55038