Compare commits
3 Commits
dev
...
20f500ebcf
| Author | SHA1 | Date | |
|---|---|---|---|
| 20f500ebcf | |||
| fd13fafd86 | |||
| 8926ec889b |
252
pkg/rsa/rsa.go
252
pkg/rsa/rsa.go
@@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Public = (*rsaPub)(nil)
|
var _ Public = (*rsaPub)(nil)
|
||||||
@@ -20,6 +19,7 @@ type Public interface {
|
|||||||
|
|
||||||
type Private interface {
|
type Private interface {
|
||||||
i()
|
i()
|
||||||
|
|
||||||
Decrypt(decryptStr string) (string, error)
|
Decrypt(decryptStr string) (string, error)
|
||||||
DecryptURLEncoding(decryptStr string) (string, error)
|
DecryptURLEncoding(decryptStr string) (string, error)
|
||||||
}
|
}
|
||||||
@@ -46,260 +46,86 @@ func NewPrivate(privateKey string) Private {
|
|||||||
|
|
||||||
func (pub *rsaPub) i() {}
|
func (pub *rsaPub) i() {}
|
||||||
|
|
||||||
// parsePublicKey 解析多种格式的公钥
|
|
||||||
func parsePublicKey(pemData []byte) (*rsa.PublicKey, error) {
|
|
||||||
block, _ := pem.Decode(pemData)
|
|
||||||
if block == nil {
|
|
||||||
return nil, errors.New("failed to decode PEM block containing public key")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查PEM块类型
|
|
||||||
switch block.Type {
|
|
||||||
case "PUBLIC KEY": // PKIX/SPKI 格式 (Node.js生成的格式)
|
|
||||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if rsaPub, ok := pub.(*rsa.PublicKey); ok {
|
|
||||||
return rsaPub, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not an RSA public key")
|
|
||||||
|
|
||||||
case "RSA PUBLIC KEY": // PKCS#1 格式
|
|
||||||
return x509.ParsePKCS1PublicKey(block.Bytes)
|
|
||||||
|
|
||||||
default:
|
|
||||||
// 尝试自动检测格式
|
|
||||||
// 先尝试PKIX格式
|
|
||||||
if pub, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil {
|
|
||||||
if rsaPub, ok := pub.(*rsa.PublicKey); ok {
|
|
||||||
return rsaPub, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再尝试PKCS#1格式
|
|
||||||
if pub, err := x509.ParsePKCS1PublicKey(block.Bytes); err == nil {
|
|
||||||
return pub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("unsupported public key format: " + block.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pub *rsaPub) Encrypt(encryptStr string) (string, error) {
|
func (pub *rsaPub) Encrypt(encryptStr string) (string, error) {
|
||||||
publicKey, err := parsePublicKey([]byte(pub.PublicKey))
|
// pem 解码
|
||||||
|
block, _ := pem.Decode([]byte(pub.PublicKey))
|
||||||
|
|
||||||
|
// x509 解码
|
||||||
|
publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对明文进行加密
|
// 类型断言
|
||||||
|
publicKey := publicKeyInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
//对明文进行加密
|
||||||
encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr))
|
encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回密文
|
//返回密文
|
||||||
return base64.StdEncoding.EncodeToString(encryptedStr), nil
|
return base64.StdEncoding.EncodeToString(encryptedStr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pub *rsaPub) EncryptURLEncoding(encryptStr string) (string, error) {
|
func (pub *rsaPub) EncryptURLEncoding(encryptStr string) (string, error) {
|
||||||
publicKey, err := parsePublicKey([]byte(pub.PublicKey))
|
// pem 解码
|
||||||
|
block, _ := pem.Decode([]byte(pub.PublicKey))
|
||||||
|
|
||||||
|
// x509 解码
|
||||||
|
publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对明文进行加密
|
// 类型断言
|
||||||
|
publicKey := publicKeyInterface.(*rsa.PublicKey)
|
||||||
|
|
||||||
|
//对明文进行加密
|
||||||
encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr))
|
encryptedStr, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(encryptStr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回密文
|
//返回密文
|
||||||
return base64.URLEncoding.EncodeToString(encryptedStr), nil
|
return base64.URLEncoding.EncodeToString(encryptedStr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pri *rsaPri) i() {}
|
func (pri *rsaPri) i() {}
|
||||||
|
|
||||||
// parsePrivateKey 解析多种格式的私钥
|
|
||||||
func parsePrivateKey(pemData []byte) (*rsa.PrivateKey, error) {
|
|
||||||
block, _ := pem.Decode(pemData)
|
|
||||||
if block == nil {
|
|
||||||
return nil, errors.New("failed to decode PEM block containing private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查PEM块类型
|
|
||||||
switch block.Type {
|
|
||||||
case "RSA PRIVATE KEY": // PKCS#1 格式
|
|
||||||
return x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
|
|
||||||
case "PRIVATE KEY": // PKCS#8 格式 (Node.js生成的格式)
|
|
||||||
priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if rsaPriv, ok := priv.(*rsa.PrivateKey); ok {
|
|
||||||
return rsaPriv, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not an RSA private key")
|
|
||||||
|
|
||||||
case "ENCRYPTED PRIVATE KEY": // 加密的PKCS#8格式
|
|
||||||
// 注意:对于加密的PKCS#8私钥,需要先解密
|
|
||||||
// 这里返回错误,建议用户先解密再使用
|
|
||||||
return nil, errors.New("encrypted private key detected. Please decrypt it first before using")
|
|
||||||
|
|
||||||
default:
|
|
||||||
// 尝试自动检测格式
|
|
||||||
// 先尝试PKCS#1格式
|
|
||||||
if priv, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
|
|
||||||
return priv, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再尝试PKCS#8格式
|
|
||||||
if priv, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
|
|
||||||
if rsaPriv, ok := priv.(*rsa.PrivateKey); ok {
|
|
||||||
return rsaPriv, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not an RSA private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("unsupported private key format: " + block.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pri *rsaPri) Decrypt(decryptStr string) (string, error) {
|
func (pri *rsaPri) Decrypt(decryptStr string) (string, error) {
|
||||||
return pri.decryptInternal(decryptStr, base64.StdEncoding.DecodeString)
|
// pem 解码
|
||||||
}
|
block, _ := pem.Decode([]byte(pri.PrivateKey))
|
||||||
|
|
||||||
func (pri *rsaPri) DecryptURLEncoding(decryptStr string) (string, error) {
|
// X509 解码
|
||||||
return pri.decryptInternal(decryptStr, base64.URLEncoding.DecodeString)
|
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
}
|
|
||||||
|
|
||||||
// decryptInternal 内部解密方法
|
|
||||||
func (pri *rsaPri) decryptInternal(
|
|
||||||
decryptStr string,
|
|
||||||
decodeFunc func(string) ([]byte, error),
|
|
||||||
) (string, error) {
|
|
||||||
// 解析私钥
|
|
||||||
privateKey, err := parsePrivateKey([]byte(pri.PrivateKey))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
decryptBytes, err := base64.StdEncoding.DecodeString(decryptStr)
|
||||||
|
|
||||||
// 解码Base64密文
|
//对密文进行解密
|
||||||
decryptBytes, err := decodeFunc(decryptStr)
|
decrypted, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对密文进行解密
|
//返回明文
|
||||||
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回明文
|
|
||||||
return string(decrypted), nil
|
return string(decrypted), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetectKeyFormat 辅助函数:检测密钥格式并提供使用建议
|
func (pri *rsaPri) DecryptURLEncoding(decryptStr string) (string, error) {
|
||||||
func DetectKeyFormat(key string) (string, string, error) {
|
// pem 解码
|
||||||
block, _ := pem.Decode([]byte(key))
|
block, _ := pem.Decode([]byte(pri.PrivateKey))
|
||||||
if block == nil {
|
|
||||||
return "", "", errors.New("invalid PEM format")
|
|
||||||
}
|
|
||||||
|
|
||||||
var format string
|
// X509 解码
|
||||||
var suggestion string
|
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
|
||||||
switch block.Type {
|
|
||||||
case "PUBLIC KEY":
|
|
||||||
if _, err := x509.ParsePKIXPublicKey(block.Bytes); err == nil {
|
|
||||||
format = "PKIX/SPKI Public Key"
|
|
||||||
suggestion = "可以直接使用"
|
|
||||||
} else {
|
|
||||||
format = "Unknown Public Key"
|
|
||||||
}
|
|
||||||
|
|
||||||
case "RSA PUBLIC KEY":
|
|
||||||
format = "PKCS#1 Public Key"
|
|
||||||
suggestion = "可以直接使用"
|
|
||||||
|
|
||||||
case "RSA PRIVATE KEY":
|
|
||||||
format = "PKCS#1 Private Key"
|
|
||||||
suggestion = "可以直接使用"
|
|
||||||
|
|
||||||
case "PRIVATE KEY":
|
|
||||||
// 尝试解析以确认是否是PKCS#8
|
|
||||||
if _, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
|
|
||||||
format = "PKCS#8 Private Key"
|
|
||||||
suggestion = "可以直接使用(兼容Node.js生成的格式)"
|
|
||||||
} else {
|
|
||||||
format = "Unknown PKCS#8 Private Key"
|
|
||||||
}
|
|
||||||
|
|
||||||
case "ENCRYPTED PRIVATE KEY":
|
|
||||||
format = "Encrypted PKCS#8 Private Key"
|
|
||||||
suggestion = "请先使用OpenSSL解密:openssl pkcs8 -in encrypted.pem -out decrypted.pem -nocrypt"
|
|
||||||
|
|
||||||
default:
|
|
||||||
format = "Unknown Key Type: " + block.Type
|
|
||||||
suggestion = "请转换为支持的格式"
|
|
||||||
}
|
|
||||||
|
|
||||||
return format, suggestion, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertPKCS8ToPKCS1 转换函数:PKCS#8 转 PKCS#1(如果需要)
|
|
||||||
func ConvertPKCS8ToPKCS1(pkcs8Key string) (string, error) {
|
|
||||||
block, _ := pem.Decode([]byte(pkcs8Key))
|
|
||||||
if block == nil {
|
|
||||||
return "", errors.New("failed to decode PEM block")
|
|
||||||
}
|
|
||||||
|
|
||||||
if block.Type != "PRIVATE KEY" {
|
|
||||||
return "", errors.New("not a PKCS#8 private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
decryptBytes, err := base64.URLEncoding.DecodeString(decryptStr)
|
||||||
|
|
||||||
rsaKey, ok := key.(*rsa.PrivateKey)
|
//对密文进行解密
|
||||||
if !ok {
|
decrypted, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decryptBytes)
|
||||||
return "", errors.New("not an RSA private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编码为 PKCS#1
|
//返回明文
|
||||||
pkcs1Bytes := x509.MarshalPKCS1PrivateKey(rsaKey)
|
return string(decrypted), nil
|
||||||
pkcs1Block := &pem.Block{
|
|
||||||
Type: "RSA PRIVATE KEY",
|
|
||||||
Bytes: pkcs1Bytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(pem.EncodeToMemory(pkcs1Block)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEncryptedKey 检查是否是加密私钥
|
|
||||||
func IsEncryptedKey(key string) bool {
|
|
||||||
block, _ := pem.Decode([]byte(key))
|
|
||||||
if block == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 现代加密私钥使用 ENCRYPTED PRIVATE KEY 类型
|
|
||||||
return block.Type == "ENCRYPTED PRIVATE KEY"
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecryptPrivateKey 解密加密私钥的辅助函数(使用OpenSSL命令)
|
|
||||||
func DecryptPrivateKey(encryptedKey, passphrase string) (string, error) {
|
|
||||||
if !IsEncryptedKey(encryptedKey) {
|
|
||||||
return "", errors.New("not an encrypted private key")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注意:这里只提供建议,实际解密应在外部进行
|
|
||||||
return "", errors.New(`请使用OpenSSL解密:
|
|
||||||
openssl pkcs8 -in encrypted.pem -out decrypted.pem -passin pass:"` + passphrase + `"
|
|
||||||
|
|
||||||
或者使用编程方式在外部解密后再传入本库`)
|
|
||||||
}
|
}
|
||||||
|
|||||||
244
pkg/rsa/rsa.js
244
pkg/rsa/rsa.js
@@ -1,244 +0,0 @@
|
|||||||
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;
|
|
||||||
Reference in New Issue
Block a user