55 lines
1.8 KiB
TypeScript

import crypto from 'crypto'
export async function encrypt(seed: string, password: string) {
const salt = crypto.randomBytes(16)
const iv = crypto.randomBytes(12)
// derive 32-byte key từ password
const key = await new Promise<Buffer>((resolve, reject) => {
crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => {
if (err) reject(err)
else resolve(derivedKey as Buffer)
})
})
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)
const ciphertext = Buffer.concat([cipher.update(seed, 'utf8'), cipher.final()])
const authTag = cipher.getAuthTag()
const encryptedMnemonic = Buffer.concat([salt, iv, authTag, ciphertext]).toString('hex')
const keystore = {
type: 'neptune-wallet',
encryption: 'aes-256-gcm',
version: 1,
wallet: {
mnemonic: encryptedMnemonic,
},
}
return JSON.stringify(keystore, null, 2)
}
export async function fromEncryptedJson(json: string, password: string) {
const data = JSON.parse(json)
const encrypted = Buffer.from(data.wallet.mnemonic, 'hex')
const salt = encrypted.subarray(0, 16)
const iv = encrypted.subarray(16, 28)
const authTag = encrypted.subarray(28, 44)
const ciphertext = encrypted.subarray(44)
const key = await new Promise<Buffer>((resolve, reject) => {
crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => {
if (err) reject(err)
else resolve(derivedKey as Buffer)
})
})
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
decipher.setAuthTag(authTag)
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
return decrypted.toString('utf8')
}