packageDocumentation module import aes from 'aes-js' ; import scrypt from 'scrypt-shim' ; import { pbkdf2Sync } from 'pbkdf2' ; import uuid from 'uuid' ; import { isPrivateKey } from '@harmony-js/utils' ; import { randomBytes } from './random' ; import { getAddressFromPrivateKey } from './keyTool' ; import { concat , hexToIntArray } from './bytes' ; import { keccak256 } from './keccak256' ; import { KDF , KDFParams , EncryptOptions , PBKDF2Params , ScryptParams , Keystore } from './types' ; hidden const DEFAULT_ALGORITHM = 'aes-128-ctr' ; param { Buffer } key param { KDF } kdf param { KDFParams } params returns { Promise < Buffer > } async function getDerivedKey ( key , kdf , params ) { const salt = Buffer . from ( params . salt , 'hex' ) ; if ( kdf === 'pbkdf2' ) { const { c , dklen } = params as PBKDF2Params ; return pbkdf2Sync ( key , salt , c , dklen , 'sha256' ) ; } if ( kdf === 'scrypt' ) { const { n , r , p , dklen } = params as ScryptParams ; return scrypt ( key , salt , n , r , p , dklen ) ; } throw new Error ( 'Only pbkdf2 and scrypt are supported' ) ; } method param { string } privateKey param { string } password param { object } options return { { version , id , address , crypto } } export const encrypt = async ( privateKey , password , options ? ) : Promise < string > => { if ( ! isPrivateKey ( privateKey ) ) { throw new Error ( 'privateKey is not correct' ) ; } if ( typeof password !== 'string' ) { throw new Error ( 'password is not found' ) ; } const address = getAddressFromPrivateKey ( privateKey ) ; const salt = randomBytes ( 32 ) ; const iv = Buffer . from ( randomBytes ( 16 ) , 'hex' ) ; const kdf = options !== undefined ? ( options . kdf ? options . kdf : 'scrypt' ) : 'scrypt' ; const level = options !== undefined ? ( options . level ? options . level : 8192 ) : 8192 ; const uuidRandom = options !== undefined ? options . uuid : undefined ; const n = kdf === 'pbkdf2' ? 262144 : level ; const kdfparams = { salt , n , r : 8 , p : 1 , dklen : 32 , } ; const derivedKey = await getDerivedKey ( Buffer . from ( password ) , kdf , kdfparams ) ; const cipher = new aes . ModeOfOperation . ctr ( derivedKey . slice ( 0 , 16 ) , new aes . Counter ( iv ) ) ; if ( ! cipher ) { throw new Error ( 'Unsupported cipher' ) ; } const ciphertext = Buffer . from ( cipher . encrypt ( Buffer . from ( privateKey . replace ( '0x' , '' ) , 'hex' ) ) ) ; const mac = keccak256 ( concat ( [ derivedKey . slice ( 16 , 32 ) , ciphertext ] ) ) ; return JSON . stringify ( { version : 3 , id : uuid . v4 ( { random : uuidRandom || hexToIntArray ( randomBytes ( 16 ) ) } ) , address : address . toLowerCase ( ) . replace ( '0x' , '' ) , crypto : { ciphertext : ciphertext . toString ( 'hex' ) , cipherparams : { iv : iv . toString ( 'hex' ) , } , cipher : DEFAULT_ALGORITHM , kdf , kdfparams , mac : mac . replace ( '0x' , '' ) , } , } ) ; } ; function param { Keystore } keystore param { string } password return { string } export const decrypt = async ( keystore , password ) : Promise < string > => { const ciphertext = Buffer . from ( keystore . crypto . ciphertext , 'hex' ) ; const iv = Buffer . from ( keystore . crypto . cipherparams . iv , 'hex' ) ; const { kdfparams } = keystore . crypto ; const derivedKey = await getDerivedKey ( Buffer . from ( password ) , keystore . crypto . kdf , kdfparams ) ; const mac = keccak256 ( concat ( [ derivedKey . slice ( 16 , 32 ) , ciphertext ] ) ) . replace ( '0x' , '' ) ; if ( mac . toUpperCase ( ) !== keystore . crypto . mac . toUpperCase ( ) ) { return Promise . reject ( new Error ( 'Failed to decrypt.' ) ) ; } const CTR = aes . ModeOfOperation . ctr ; const cipher = new CTR ( derivedKey . slice ( 0 , 16 ) , new aes . Counter ( iv ) ) ; const decrypted = '0x' + Buffer . from ( cipher . decrypt ( ciphertext ) ) . toString ( 'hex' ) ; return decrypted ; } ; /**
 * encrypt Phrase
 */ export const encryptPhrase = async ( phrase , password , options ? ) : Promise < string > => { if ( typeof password !== 'string' ) { throw new Error ( 'password is not found' ) ; } const salt = randomBytes ( 32 ) ; const iv = Buffer . from ( randomBytes ( 16 ) , 'hex' ) ; const kdf = options !== undefined ? ( options . kdf ? options . kdf : 'scrypt' ) : 'scrypt' ; const level = options !== undefined ? ( options . level ? options . level : 8192 ) : 8192 ; const uuidRandom = options !== undefined ? options . uuid : undefined ; const n = kdf === 'pbkdf2' ? 262144 : level ; const kdfparams = { salt , n , r : 8 , p : 1 , dklen : 32 , } ; const derivedKey = await getDerivedKey ( Buffer . from ( password ) , kdf , kdfparams ) ; const cipher = new aes . ModeOfOperation . ctr ( derivedKey . slice ( 0 , 16 ) , new aes . Counter ( iv ) ) ; if ( ! cipher ) { throw new Error ( 'Unsupported cipher' ) ; } const ciphertext = Buffer . from ( cipher . encrypt ( Buffer . from ( phrase ) ) ) ; const mac = keccak256 ( concat ( [ derivedKey . slice ( 16 , 32 ) , ciphertext ] ) ) ; return JSON . stringify ( { version : 3 , id : uuid . v4 ( { random : uuidRandom || hexToIntArray ( randomBytes ( 16 ) ) } ) , crypto : { ciphertext : ciphertext . toString ( 'hex' ) , cipherparams : { iv : iv . toString ( 'hex' ) , } , cipher : DEFAULT_ALGORITHM , kdf , kdfparams , mac : mac . replace ( '0x' , '' ) , } , } ) ; } ; /**
 * decrypt phrase
 */ export const decryptPhrase = async ( keystore , password ) : Promise < string > => { const result = await decrypt ( keystore , password ) ; return Buffer . from ( result . replace ( '0x' , '' ) , 'hex' ) . toString ( ) ; } ;