const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); class KeyPairGenerator { constructor(options = {}) { this.options = { modulusLength: 2048, // 2048位在安全性和性能间取得平衡 publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', // 可选加密私钥 passphrase: options.passphrase || '' // 私钥密码 }, ...options }; } // 生成密钥对 generateKeyPair() { return new Promise((resolve, reject) => { crypto.generateKeyPair('rsa', this.options, (err, publicKey, privateKey) => { if (err) { reject(err); return; } resolve({ publicKey, privateKey }); }); }); } // 保存密钥到文件 saveKeyToFile(key, filename, directory = './keys') { if (!fs.existsSync(directory)) { fs.mkdirSync(directory, { recursive: true }); } const filePath = path.join(directory, filename); fs.writeFileSync(filePath, key); console.log(`✅ ${filename} 已保存到: ${filePath}`); return filePath; } // 验证密钥对 validateKeyPair(publicKey, privateKey, passphrase = '') { try { // 使用公钥加密测试数据 const testData = 'test-signature-validation'; const encrypted = crypto.publicEncrypt(publicKey, Buffer.from(testData)); // 使用私钥解密 const decrypted = crypto.privateDecrypt( { key: privateKey, passphrase }, encrypted ); return decrypted.toString() === testData; } catch (error) { console.error('❌ 密钥对验证失败:', error.message); return false; } } // 生成完整的密钥对文件 async generateAndSaveKeyPair(outputDir = './keys', keyName = 'app') { try { console.log('🔐 正在生成 RSA 密钥对...'); // 生成密钥对 const { publicKey, privateKey } = await this.generateKeyPair(); // 验证密钥对 console.log('🔍 验证密钥对...'); const isValid = this.validateKeyPair(publicKey, privateKey, this.options.privateKeyEncoding.passphrase); if (!isValid) { throw new Error('密钥对验证失败'); } console.log('✅ 密钥对验证成功'); // 保存文件 const timestamp = new Date().toISOString().split('T')[0]+"-"+(new Date()).getTime(); const publicKeyFile = this.saveKeyToFile( publicKey, `${keyName}-public-key-${timestamp}.pem`, outputDir ); const privateKeyFile = this.saveKeyToFile( privateKey, `${keyName}-private-key-${timestamp}.pem`, outputDir ); // 生成配置文件示例 this.generateConfigExample(publicKey, privateKey, outputDir, keyName); return { publicKey, privateKey, publicKeyFile, privateKeyFile, isValid }; } catch (error) { console.error('❌ 生成密钥对失败:', error.message); throw error; } } // 生成配置文件示例 generateConfigExample(publicKey, privateKey, outputDir, keyName) { const frontendConfig = ` // 前端配置 (JavaScript/TypeScript) const RSA_PUBLIC_KEY = \`${publicKey}\`; // 或者从文件导入 // import publicKey from './${keyName}-public-key.pem'; `; const backendConfig = ` // 后端配置 (Go) package config const ( RSAPrivateKey = \`${privateKey}\` ) // 或者从环境变量读取 // privateKey := os.Getenv("RSA_PRIVATE_KEY") `; const envExample = ` # 环境变量示例 RSA_PRIVATE_KEY="你的私钥内容" RSA_PUBLIC_KEY="你的公钥内容" KEY_PASSPHRASE="你的私钥密码(如果有)" `; const timestamp = new Date().toISOString().split('T')[0]+"-"+(new Date()).getTime(); this.saveKeyToFile(frontendConfig.trim(), 'frontend-config-example-'+timestamp+'.js', outputDir); this.saveKeyToFile(backendConfig.trim(), 'backend-config-example-'+timestamp+'.go', outputDir); this.saveKeyToFile(envExample.trim(), '.env.example', outputDir); console.log('📝 配置文件示例已生成'); } // 显示密钥信息 displayKeyInfo(publicKey, privateKey) { const publicKeyInfo = crypto.createPublicKey(publicKey); const privateKeyInfo = crypto.createPrivateKey({ key: privateKey, passphrase: this.options.privateKeyEncoding.passphrase }); console.log('\n🔑 密钥信息:'); console.log('──────────────────────────────'); console.log(`算法: ${publicKeyInfo.asymmetricKeyType}`); console.log(`模数长度: ${publicKeyInfo.asymmetricKeySize} 位`); console.log(`格式: PEM`); if (this.options.privateKeyEncoding.passphrase) { console.log(`私钥加密: ${this.options.privateKeyEncoding.cipher}`); } else { console.log('⚠️ 私钥未加密,建议在生产环境中使用加密私钥'); } } } // 命令行界面 function main() { const args = process.argv.slice(2); const outputDir = args[0] || './keys'; const keyName = args[1] || 'app'; const useEncryption = args.includes('--encrypt'); const passphrase = process.env.KEY_PASSPHRASE || ''; const generator = new KeyPairGenerator({ privateKeyEncoding: { type: 'pkcs8', format: 'pem', ...(useEncryption && { cipher: 'aes-256-cbc', passphrase: passphrase }) } }); console.log(` 🔐 RSA 密钥对生成器 ────────────────────────────── 输出目录: ${outputDir} 密钥名称: ${keyName} 私钥加密: ${useEncryption ? '是' : '否'} 密钥长度: 2048 位 (平衡安全性与性能) `); if (useEncryption && !passphrase) { console.log('❌ 请设置 KEY_PASSPHRASE 环境变量来加密私钥'); console.log(' 例如: KEY_PASSPHRASE=your-secret-password node generate-keys.js'); process.exit(1); } generator.generateAndSaveKeyPair(outputDir, keyName) .then((result) => { generator.displayKeyInfo(result.publicKey, result.privateKey); console.log('\n🎉 密钥对生成完成!'); console.log('──────────────────────────────'); console.log('📁 生成的文件:'); console.log(` 公钥: ${result.publicKeyFile}`); console.log(` 私钥: ${result.privateKeyFile}`); console.log(` 配置文件示例: ${outputDir}/`); console.log('\n💡 使用建议:'); console.log(' • 将公钥用于前端加密'); console.log(' • 将私钥安全地存储在后端'); console.log(' • 定期轮换密钥(建议每1-2年)'); console.log(' • 不要将私钥提交到版本控制系统'); if (!useEncryption) { console.log('\n⚠️ 安全警告:'); console.log(' 当前私钥未加密,建议在生产环境中使用加密私钥'); console.log(' 重新运行并添加 --encrypt 参数和 KEY_PASSPHRASE 环境变量'); } }) .catch((error) => { console.error('❌ 生成失败:', error.message); process.exit(1); }); } // 如果直接运行此文件 if (require.main === module) { main(); } module.exports = KeyPairGenerator;