mirror of
https://github.com/alexgo-io/stacks.js.git
synced 2026-04-29 01:35:50 +08:00
fix: prettier formatting
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
src/wallet.ts
|
||||
src/encryption/wallet.ts
|
||||
src/encryption/index.ts
|
||||
src/encryption/ec.ts
|
||||
src/errors.ts
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { validateMnemonic, mnemonicToEntropy, entropyToMnemonic } from 'bip39'
|
||||
import { randomBytes, GetRandomBytes } from './cryptoRandom'
|
||||
import { createSha2Hash } from './sha2Hash'
|
||||
import { createHmacSha256 } from './hmacSha256'
|
||||
import { createCipher } from './aesCipher'
|
||||
import { createPbkdf2 } from './pbkdf2'
|
||||
import { TriplesecDecryptSignature } from './cryptoUtils'
|
||||
import { validateMnemonic, mnemonicToEntropy, entropyToMnemonic } from 'bip39';
|
||||
import { randomBytes, GetRandomBytes } from './cryptoRandom';
|
||||
import { createSha2Hash } from './sha2Hash';
|
||||
import { createHmacSha256 } from './hmacSha256';
|
||||
import { createCipher } from './aesCipher';
|
||||
import { createPbkdf2 } from './pbkdf2';
|
||||
import { TriplesecDecryptSignature } from './cryptoUtils';
|
||||
|
||||
/**
|
||||
* Encrypt a raw mnemonic phrase to be password protected
|
||||
@@ -12,115 +12,132 @@ import { TriplesecDecryptSignature } from './cryptoUtils'
|
||||
* @param {string} password - Password to encrypt mnemonic with
|
||||
* @return {Promise<Buffer>} The encrypted phrase
|
||||
* @private
|
||||
* @ignore
|
||||
* @ignore
|
||||
* */
|
||||
export async function encryptMnemonic(phrase: string, password: string, opts?: {
|
||||
getRandomBytes?: GetRandomBytes
|
||||
}): Promise<Buffer> {
|
||||
export async function encryptMnemonic(
|
||||
phrase: string,
|
||||
password: string,
|
||||
opts?: {
|
||||
getRandomBytes?: GetRandomBytes;
|
||||
}
|
||||
): Promise<Buffer> {
|
||||
// hex encoded mnemonic string
|
||||
let mnemonicEntropy: string
|
||||
let mnemonicEntropy: string;
|
||||
try {
|
||||
// must be bip39 mnemonic
|
||||
mnemonicEntropy = mnemonicToEntropy(phrase)
|
||||
mnemonicEntropy = mnemonicToEntropy(phrase);
|
||||
} catch (error) {
|
||||
console.error('Invalid mnemonic phrase provided')
|
||||
console.error(error)
|
||||
throw new Error('Not a valid bip39 mnemonic')
|
||||
console.error('Invalid mnemonic phrase provided');
|
||||
console.error(error);
|
||||
throw new Error('Not a valid bip39 mnemonic');
|
||||
}
|
||||
|
||||
|
||||
// normalize plaintext to fixed length byte string
|
||||
const plaintextNormalized = Buffer.from(mnemonicEntropy, 'hex')
|
||||
const plaintextNormalized = Buffer.from(mnemonicEntropy, 'hex');
|
||||
|
||||
// AES-128-CBC with SHA256 HMAC
|
||||
const pbkdf2 = await createPbkdf2()
|
||||
let salt: Buffer
|
||||
const pbkdf2 = await createPbkdf2();
|
||||
let salt: Buffer;
|
||||
if (opts && opts.getRandomBytes) {
|
||||
salt = opts.getRandomBytes(16)
|
||||
salt = opts.getRandomBytes(16);
|
||||
} else {
|
||||
salt = randomBytes(16)
|
||||
salt = randomBytes(16);
|
||||
}
|
||||
const keysAndIV = await pbkdf2.derive(password, salt, 100000, 48, 'sha512')
|
||||
const encKey = keysAndIV.slice(0, 16)
|
||||
const macKey = keysAndIV.slice(16, 32)
|
||||
const iv = keysAndIV.slice(32, 48)
|
||||
const keysAndIV = await pbkdf2.derive(password, salt, 100000, 48, 'sha512');
|
||||
const encKey = keysAndIV.slice(0, 16);
|
||||
const macKey = keysAndIV.slice(16, 32);
|
||||
const iv = keysAndIV.slice(32, 48);
|
||||
|
||||
const cipher = await createCipher()
|
||||
const cipherText = await cipher.encrypt('aes-128-cbc', encKey, iv, plaintextNormalized)
|
||||
const cipher = await createCipher();
|
||||
const cipherText = await cipher.encrypt(
|
||||
'aes-128-cbc',
|
||||
encKey,
|
||||
iv,
|
||||
plaintextNormalized
|
||||
);
|
||||
|
||||
const hmacPayload = Buffer.concat([salt, cipherText])
|
||||
const hmacSha256 = await createHmacSha256()
|
||||
const hmacDigest = await hmacSha256.digest(macKey, hmacPayload)
|
||||
const hmacPayload = Buffer.concat([salt, cipherText]);
|
||||
const hmacSha256 = await createHmacSha256();
|
||||
const hmacDigest = await hmacSha256.digest(macKey, hmacPayload);
|
||||
|
||||
const payload = Buffer.concat([salt, hmacDigest, cipherText])
|
||||
return payload
|
||||
const payload = Buffer.concat([salt, hmacDigest, cipherText]);
|
||||
return payload;
|
||||
}
|
||||
|
||||
// Used to distinguish bad password during decrypt vs invalid format
|
||||
class PasswordError extends Error { }
|
||||
class PasswordError extends Error {}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
async function decryptMnemonicBuffer(dataBuffer: Buffer, password: string): Promise<string> {
|
||||
const salt = dataBuffer.slice(0, 16)
|
||||
const hmacSig = dataBuffer.slice(16, 48) // 32 bytes
|
||||
const cipherText = dataBuffer.slice(48)
|
||||
const hmacPayload = Buffer.concat([salt, cipherText])
|
||||
* @ignore
|
||||
*/
|
||||
async function decryptMnemonicBuffer(
|
||||
dataBuffer: Buffer,
|
||||
password: string
|
||||
): Promise<string> {
|
||||
const salt = dataBuffer.slice(0, 16);
|
||||
const hmacSig = dataBuffer.slice(16, 48); // 32 bytes
|
||||
const cipherText = dataBuffer.slice(48);
|
||||
const hmacPayload = Buffer.concat([salt, cipherText]);
|
||||
|
||||
const pbkdf2 = await createPbkdf2()
|
||||
const keysAndIV = await pbkdf2.derive(password, salt, 100000, 48, 'sha512')
|
||||
const encKey = keysAndIV.slice(0, 16)
|
||||
const macKey = keysAndIV.slice(16, 32)
|
||||
const iv = keysAndIV.slice(32, 48)
|
||||
const pbkdf2 = await createPbkdf2();
|
||||
const keysAndIV = await pbkdf2.derive(password, salt, 100000, 48, 'sha512');
|
||||
const encKey = keysAndIV.slice(0, 16);
|
||||
const macKey = keysAndIV.slice(16, 32);
|
||||
const iv = keysAndIV.slice(32, 48);
|
||||
|
||||
const decipher = await createCipher()
|
||||
const decryptedResult = await decipher.decrypt('aes-128-cbc', encKey, iv, cipherText);
|
||||
const decipher = await createCipher();
|
||||
const decryptedResult = await decipher.decrypt(
|
||||
'aes-128-cbc',
|
||||
encKey,
|
||||
iv,
|
||||
cipherText
|
||||
);
|
||||
|
||||
const hmacSha256 = await createHmacSha256()
|
||||
const hmacDigest = await hmacSha256.digest(macKey, hmacPayload)
|
||||
const hmacSha256 = await createHmacSha256();
|
||||
const hmacDigest = await hmacSha256.digest(macKey, hmacPayload);
|
||||
|
||||
// hash both hmacSig and hmacDigest so string comparison time
|
||||
// is uncorrelated to the ciphertext
|
||||
const sha2Hash = await createSha2Hash()
|
||||
const hmacSigHash = await sha2Hash.digest(hmacSig)
|
||||
const hmacDigestHash = await sha2Hash.digest(hmacDigest)
|
||||
const sha2Hash = await createSha2Hash();
|
||||
const hmacSigHash = await sha2Hash.digest(hmacSig);
|
||||
const hmacDigestHash = await sha2Hash.digest(hmacDigest);
|
||||
|
||||
if (!hmacSigHash.equals(hmacDigestHash)) {
|
||||
// not authentic
|
||||
throw new PasswordError('Wrong password (HMAC mismatch)')
|
||||
throw new PasswordError('Wrong password (HMAC mismatch)');
|
||||
}
|
||||
|
||||
let mnemonic: string
|
||||
let mnemonic: string;
|
||||
try {
|
||||
mnemonic = entropyToMnemonic(decryptedResult)
|
||||
mnemonic = entropyToMnemonic(decryptedResult);
|
||||
} catch (error) {
|
||||
console.error('Error thrown by `entropyToMnemonic`')
|
||||
console.error(error)
|
||||
throw new PasswordError('Wrong password (invalid plaintext)')
|
||||
console.error('Error thrown by `entropyToMnemonic`');
|
||||
console.error(error);
|
||||
throw new PasswordError('Wrong password (invalid plaintext)');
|
||||
}
|
||||
if (!validateMnemonic(mnemonic)) {
|
||||
throw new PasswordError('Wrong password (invalid plaintext)')
|
||||
throw new PasswordError('Wrong password (invalid plaintext)');
|
||||
}
|
||||
|
||||
return mnemonic
|
||||
return mnemonic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decrypt legacy triplesec keys
|
||||
* @param {Buffer} dataBuffer - The encrypted key
|
||||
* @param {String} password - Password for data
|
||||
* @return {Promise<Buffer>} Decrypted seed
|
||||
* @private
|
||||
* @ignore
|
||||
* @ignore
|
||||
*/
|
||||
function decryptLegacy(dataBuffer: Buffer,
|
||||
password: string,
|
||||
triplesecDecrypt: TriplesecDecryptSignature
|
||||
function decryptLegacy(
|
||||
dataBuffer: Buffer,
|
||||
password: string,
|
||||
triplesecDecrypt: TriplesecDecryptSignature
|
||||
): Promise<Buffer> {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
if (!triplesecDecrypt) {
|
||||
reject(new Error('The `triplesec.decrypt` function must be provided'))
|
||||
reject(new Error('The `triplesec.decrypt` function must be provided'));
|
||||
}
|
||||
triplesecDecrypt(
|
||||
{
|
||||
@@ -129,34 +146,34 @@ function decryptLegacy(dataBuffer: Buffer,
|
||||
},
|
||||
(err, plaintextBuffer) => {
|
||||
if (!err) {
|
||||
resolve(plaintextBuffer)
|
||||
resolve(plaintextBuffer);
|
||||
} else {
|
||||
reject(err)
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt an encrypted mnemonic phrase with a password.
|
||||
* Legacy triplesec encrypted payloads are also supported.
|
||||
* Decrypt an encrypted mnemonic phrase with a password.
|
||||
* Legacy triplesec encrypted payloads are also supported.
|
||||
* @param data - Buffer or hex-encoded string of the encrypted mnemonic
|
||||
* @param password - Password for data
|
||||
* @return the raw mnemonic phrase
|
||||
* @private
|
||||
* @ignore
|
||||
* @ignore
|
||||
*/
|
||||
export async function decryptMnemonic(
|
||||
data: string | Buffer,
|
||||
password: string,
|
||||
password: string,
|
||||
triplesecDecrypt?: TriplesecDecryptSignature
|
||||
) {
|
||||
const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data, 'hex');
|
||||
try {
|
||||
return await decryptMnemonicBuffer(dataBuffer, password);
|
||||
} catch (err) {
|
||||
if (err instanceof PasswordError) {
|
||||
if (err instanceof PasswordError) {
|
||||
throw err;
|
||||
}
|
||||
const data = await decryptLegacy(dataBuffer, password, triplesecDecrypt);
|
||||
|
||||
Reference in New Issue
Block a user