|
import * as util from 'util' |
|
import * as readline from 'readline' |
|
import { webcrypto } from 'node:crypto' |
|
import { stdin as input, stdout as output } from 'process' |
|
|
|
const { subtle } = webcrypto |
|
|
|
const rl = readline.createInterface({ input, output }) |
|
|
|
rl.input.on('keypress', (c) => { |
|
if (c.charCodeAt() === 127) { |
|
const len = rl.line.length |
|
readline.moveCursor(rl.output, -len, 0) |
|
readline.clearLine(rl.output, 1) |
|
return |
|
} |
|
readline.moveCursor(rl.output, -1, 0) |
|
readline.clearLine(rl.output, 1) |
|
}) |
|
|
|
const question = util.promisify(rl.question).bind(rl) |
|
|
|
;(async () => { |
|
try { |
|
let password = await question('password for encrypt: ') |
|
password = password.trim() |
|
let data = await question('seed phrase: ') |
|
data = data.trim() |
|
|
|
const encoder = new TextEncoder() |
|
|
|
const keyMaterial = await subtle.importKey( |
|
'raw', |
|
encoder.encode(password), |
|
'PBKDF2', |
|
false, |
|
['deriveKey', 'deriveBits'] |
|
) |
|
|
|
const salt = encoder.encode(password) |
|
|
|
const bits = await subtle.deriveBits({ |
|
name: 'PBKDF2', |
|
hash: 'SHA-512', |
|
salt, |
|
iterations: 1000 |
|
}, keyMaterial, 256) |
|
|
|
const key = await subtle.deriveKey( |
|
{ |
|
name: 'PBKDF2', |
|
hash: 'SHA-512', |
|
salt, |
|
iterations: 100, |
|
}, |
|
keyMaterial, |
|
{ |
|
name: 'AES-GCM', |
|
length: 256, |
|
}, |
|
true, |
|
['encrypt', 'decrypt'] |
|
) |
|
|
|
const ciphertext = await subtle.encrypt( |
|
{ |
|
name: 'AES-GCM', |
|
iv: bits |
|
}, |
|
key, |
|
encoder.encode(data) |
|
) |
|
|
|
const base64 = Buffer.from(ciphertext).toString('base64') |
|
// const hex = Buffer.from(ciphertext).toString('hex') |
|
|
|
console.log('base64:', base64) |
|
// console.log('hex:', hex) |
|
} catch (err) { |
|
console.error('rejected', err) |
|
} |
|
process.exit(1) |
|
})() |