import { createHash, randomBytes } from 'crypto'; import * as t from '@emurgo/cardano-serialization-lib-nodejs/cardano_serialization_lib'; const cbor = require('cbor'); const bip39 = require('bip39'); let _CardanoWasm: typeof import ('@emurgo/cardano-serialization-lib-nodejs'); interface Payload { [name: string]: any; } class Wasm { static async load() { if (_CardanoWasm) { return _CardanoWasm; } _CardanoWasm = await import ('@emurgo/cardano-serialization-lib-nodejs'); return _CardanoWasm; } } export const expose = async () => Wasm.load(); export async function issueJWTCborToken(payload:Object, privateKey: t.PrivateKey):Promise { const cborPayload = cbor.encode({...payload}); const signed = await signBuffer(cborPayload, privateKey); return `${cborPayload.toString('hex')}.${signed.to_hex()}`; } export async function verifyJWTCborToken(token:string, publicKey: t.PublicKey):Promise { const {Ed25519Signature} = await expose(); const [payploadHex, signatureHex] = token.split("."); const payloadBuffer = Buffer.from(payploadHex, 'hex'); const signature = Ed25519Signature.from_hex(signatureHex); const verified = await verifyBuffer(payloadBuffer, publicKey, signature); if (!verified) { throw new Error("Verification failed"); } return cbor.decode(payloadBuffer); } export function getBip39Entropy(mnemonic: string):Buffer{ const entropy: Buffer = Buffer.from(bip39.mnemonicToEntropy(mnemonic), 'hex'); return entropy; } export async function mnemonicToRootKeyPair(mnemonic: string, password:string = ''):Promise { const {Bip32PrivateKey} = await expose(); const seed: Buffer = getBip39Entropy(mnemonic); return Bip32PrivateKey.from_bip39_entropy(seed, Buffer.from(password)).to_raw_key(); } export async function encryptWithPin(payload: Payload, pin: string): Promise { const wasm = await expose(); const salt = createHash('sha256').update(`wallet:mnemonic:${pin}`).digest('hex'); const nonce = randomBytes(12).toString('hex'); const hexPayload = Buffer.from(JSON.stringify(payload)).toString('hex'); const hexPin = Buffer.from(pin).toString('hex'); return wasm.encrypt_with_password(hexPin, salt, nonce, hexPayload); } export async function decryptWithPin(payload: string, pin: string): Promise { const wasm = await expose(); const hexPin = Buffer.from(pin).toString('hex'); const decrypted = wasm.decrypt_with_password(hexPin, payload); return JSON.parse(Buffer.from(decrypted, 'hex').toString()); } export async function randomPin(n2?: string): Promise { const n1 = randomBytes(3).readUIntLE(0, 3) >>> 4; const nn1 = n1; if (n1 < 1000000) return `${nn1}`.toString(); if (typeof n2 === 'undefined') return `${await randomPin(`${nn1}`)}`.toString(); return `${Math.abs(nn1 - parseInt(n2))}`.toString(); } export async function signBuffer(msg: Buffer, privKey: t.PrivateKey):Promise{ const msgBuffer = Buffer.from(msg); return privKey.sign(msgBuffer); } export async function verifyBuffer(msg: Buffer, pubKey: t.PublicKey, signature: t.Ed25519Signature){ const msgBuffer = Buffer.from(msg); return pubKey.verify(msgBuffer, signature); } export default { expose, mnemonicToRootKeyPair, encryptWithPin, decryptWithPin, randomPin, signBuffer, verifyBuffer, issueJWTCborToken, verifyJWTCborToken, getBip39Entropy }