基于EthersJs与ReactNative实现类MetaMask的密码保护HD钱包
为HD钱包添加密码保护(React Native + Ethers.js)
核心逻辑
密码保护的核心是加密存储HD钱包的助记词/私钥,登录时通过密码解密恢复钱包——和MetaMask的思路一致,绝不明文存储任何敏感信息。
实现步骤
1. 依赖准备
先安装必要的库:
npm install react-native-keychain ethers
react-native-keychain:React Native官方推荐的安全存储工具,用于加密存储敏感数据ethers.js:处理HD钱包生成、加密解密逻辑
2. 加密助记词(创建钱包时执行)
生成HD钱包后,用用户设置的密码加密助记词,再存入Keychain:
import { ethers } from 'ethers'; import * as Keychain from 'react-native-keychain'; // 加密并存储助记词 const encryptAndSaveMnemonic = async (mnemonic, password) => { // 基于密码生成加密密钥(PBKDF2慢哈希算法,防暴力破解) const salt = ethers.randomBytes(16); const encryptionKey = await ethers.pbkdf2(password, salt, 100000, 32, 'sha256'); // AES加密助记词 const iv = ethers.randomBytes(16); const encryptedMnemonic = ethers.AES.encrypt(mnemonic, encryptionKey, { iv }).toString(); // 将加密所需的salt、iv和密文存入Keychain await Keychain.setGenericPassword( 'encrypted_wallet', JSON.stringify({ salt: salt.toString('hex'), iv: iv.toString('hex'), ciphertext: encryptedMnemonic }), { accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED } ); }; // 调用示例:生成HD钱包后加密存储 const createWallet = async (password) => { const mnemonic = ethers.Wallet.createRandom().mnemonic.phrase; await encryptAndSaveMnemonic(mnemonic, password); // 强制提示用户手动抄写助记词备份,APP内禁止留存任何备份副本 };
3. 解密登录(用户输入密码时执行)
从Keychain取出加密数据,用密码解密得到助记词,恢复HD钱包:
import { ethers } from 'ethers'; import * as Keychain from 'react-native-keychain'; // 解密并恢复钱包 const decryptAndRestoreWallet = async (password) => { try { // 从Keychain获取加密数据 const credentials = await Keychain.getGenericPassword('encrypted_wallet'); if (!credentials) throw new Error('未找到钱包数据'); const { salt, iv, ciphertext } = JSON.parse(credentials.password); // 用密码重新生成密钥 const encryptionKey = await ethers.pbkdf2(password, Buffer.from(salt, 'hex'), 100000, 32, 'sha256'); // AES解密助记词 const mnemonic = ethers.AES.decrypt(ciphertext, encryptionKey, { iv: Buffer.from(iv, 'hex') }).toString(); // 恢复HD钱包 const wallet = ethers.HDNodeWallet.fromPhrase(mnemonic); return wallet; } catch (error) { throw new Error('密码错误或钱包数据损坏'); } }; // 调用示例:登录时验证密码并恢复钱包 const handleLogin = async (password) => { try { const wallet = await decryptAndRestoreWallet(password); // 钱包恢复成功,进入主界面 } catch (err) { // 提示用户密码错误或钱包不存在 alert(err.message); } };
4. 关键注意事项
- 禁止明文存储:助记词、私钥永远不能以明文形式存在本地存储或内存中,用完及时清理相关变量
- 密码强度校验:创建/登录时必须要求密码长度≥8位,且包含大小写、数字或特殊字符,避免弱密码
- 安全存储配置:Keychain的
accessible参数建议设为WHEN_UNLOCKED,确保只有设备解锁时才能访问加密数据 - 错误模糊处理:解密失败时只提示“密码错误”,不要泄露具体错误信息,防止攻击者利用
内容的提问来源于stack exchange,提问作者An droid
相关产品推荐
相关产品推荐

