UNPKG

p-sdk-wallet

Version:

A comprehensive wallet SDK for React Native (pwc), supporting multi-chain and multi-account features.

179 lines (178 loc) 7.38 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.EncryptionService = void 0; const CryptoJS = __importStar(require("crypto-js")); const bip39 = __importStar(require("bip39")); const bip32_1 = require("bip32"); const ecc = __importStar(require("@bitcoinerlab/secp256k1")); const buffer_1 = require("buffer"); const chains_1 = require("../config/chains"); const constants_1 = require("../config/constants"); const bip32 = (0, bip32_1.BIP32Factory)(ecc); const SALT_LENGTH = constants_1.SECURITY_CONFIG.SALT_LENGTH; const KEY_LENGTH = constants_1.SECURITY_CONFIG.AES_KEY_SIZE / 8; // Convert bits to bytes const IV_LENGTH = constants_1.SECURITY_CONFIG.IV_LENGTH; /** * Service providing cryptographic operations including mnemonic generation, * encryption/decryption, and key derivation for the wallet SDK. */ class EncryptionService { /** * Generates a cryptographically secure mnemonic phrase. * @returns A 24-word mnemonic phrase following BIP-39 standard */ static generateMnemonic() { return bip39.generateMnemonic(256); } /** * Validates a mnemonic phrase to ensure it's properly formatted and contains valid words. * @param mnemonic - The mnemonic phrase to validate (12, 15, 18, 21, or 24 words) * @returns True if the mnemonic is valid, false otherwise */ static validateMnemonic(mnemonic) { return bip39.validateMnemonic(mnemonic); } /** * Encrypts data using AES-256-CBC with PBKDF2 key derivation. * @param data - The plaintext data to encrypt * @param password - The password to use for key derivation * @returns Promise resolving to the encrypted data structure * @throws Error if encryption fails */ static async encrypt(data, password) { const salt = CryptoJS.lib.WordArray.random(SALT_LENGTH); const iv = CryptoJS.lib.WordArray.random(IV_LENGTH); const key = CryptoJS.PBKDF2(password, salt, { keySize: KEY_LENGTH, iterations: (0, constants_1.getPBKDF2Iterations)(), hasher: CryptoJS.algo.SHA256, }); const encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, }); return { encryptedData: encrypted.toString(), iv: CryptoJS.enc.Base64.stringify(iv), salt: CryptoJS.enc.Base64.stringify(salt), }; } /** * Decrypts data that was encrypted using the encrypt method. * @param encryptedData - The encrypted data structure containing data, iv, and salt * @param password - The password used for the original encryption * @returns Promise resolving to the decrypted plaintext data * @throws Error if decryption fails due to incorrect password or corrupted data */ static async decrypt(encryptedData, password) { const salt = CryptoJS.enc.Base64.parse(encryptedData.salt); const iv = CryptoJS.enc.Base64.parse(encryptedData.iv); const key = CryptoJS.PBKDF2(password, salt, { keySize: KEY_LENGTH, iterations: (0, constants_1.getPBKDF2Iterations)(), hasher: CryptoJS.algo.SHA256, }); const decrypted = CryptoJS.AES.decrypt(encryptedData.encryptedData, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, }); const decryptedText = decrypted.toString(CryptoJS.enc.Utf8); if (!decryptedText) { throw new Error("Decryption failed. Invalid password or corrupted data."); } return decryptedText; } /** * Converts a mnemonic phrase to a seed buffer using PBKDF2. * @param mnemonic - The mnemonic phrase to convert * @returns Promise resolving to the seed buffer */ static async mnemonicToSeed(mnemonic) { return bip39.mnemonicToSeed(mnemonic); } /** * Derives a private key from a seed using BIP-32 derivation. * @param seed - The seed buffer to derive from * @param path - The derivation path to use (defaults to EVM path) * @returns Promise resolving to the derived private key buffer * @throws Error if private key derivation fails */ static async derivePrivateKey(seed, path = chains_1.DERIVATION_PATHS.EVM) { const root = bip32.fromSeed(seed); const child = root.derivePath(path); if (!child.privateKey) { throw new Error('Could not derive private key.'); } return buffer_1.Buffer.from(child.privateKey); } /** * Attempts to clear sensitive data from memory. * Note: JavaScript doesn't guarantee memory clearing, but this helps reduce exposure. * @param data - The sensitive data to clear (string or buffer) */ static clearSensitiveData(data) { if (typeof data === 'string') { // For strings, we can't directly clear memory, but we can help GC // by removing references and using setTimeout to delay cleanup setTimeout(() => { // This helps reduce the time sensitive data stays in memory }, 0); } else if (buffer_1.Buffer.isBuffer(data)) { // For buffers, we can fill with zeros data.fill(0); } } /** * Creates a temporary copy of sensitive data that gets cleared after use. * This is a security measure to minimize the time sensitive data stays in memory. * @param data - The sensitive data to use temporarily * @param callback - Function to execute with the temporary data * @returns The result of the callback function */ static withTemporaryData(data, callback) { try { const result = callback(data); return result; } finally { this.clearSensitiveData(data); } } } exports.EncryptionService = EncryptionService;