forked from imbytecat/fullstack-starter
feat: 添加支持Java兼容的RSA加密解密工具
- 添加RSA加密解密工具函数,支持与Java兼容的OAEPWithSHA-256AndMGF1Padding加密标准,使用DER/SPKI和DER/PKCS8格式的公私钥进行加解密操作。
This commit is contained in:
109
apps/server/src/lib/crypto.ts
Normal file
109
apps/server/src/lib/crypto.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
constants,
|
||||
createPrivateKey,
|
||||
createPublicKey,
|
||||
privateDecrypt,
|
||||
publicEncrypt,
|
||||
} from 'node:crypto'
|
||||
|
||||
// 对应 Java: RSA/ECB/OAEPWithSHA-256AndMGF1Padding
|
||||
const OAEP_HASH = 'sha256'
|
||||
|
||||
/**
|
||||
* 使用 Base64 编码的公钥加密明文
|
||||
*
|
||||
* 加密标准: RSA/ECB/OAEPWithSHA-256AndMGF1Padding (兼容 Java)
|
||||
* 公钥格式: SPKI/DER (对应 Java X509EncodedKeySpec)
|
||||
*
|
||||
* @param plainText - 待加密的明文字符串
|
||||
* @param publicKeyBase64 - Base64 编码的公钥 (DER/SPKI 格式)
|
||||
* @returns Base64 编码的加密数据
|
||||
* @throws {Error} 加密失败时抛出错误
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const publicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...'
|
||||
* const encrypted = encrypt('sensitive data', publicKey)
|
||||
* console.log(encrypted) // "a3f5e8c2d1b4..."
|
||||
* ```
|
||||
*/
|
||||
export function encrypt(plainText: string, publicKeyBase64: string): string {
|
||||
const buffer = Buffer.from(plainText, 'utf-8')
|
||||
const keyBuffer = Buffer.from(publicKeyBase64, 'base64')
|
||||
|
||||
try {
|
||||
// 1. 先创建 KeyObject,在这里指定密钥的格式 (DER/SPKI)
|
||||
const publicKey = createPublicKey({
|
||||
key: keyBuffer,
|
||||
format: 'der',
|
||||
type: 'spki', // 对应 Java X509EncodedKeySpec
|
||||
})
|
||||
|
||||
// 2. 使用 KeyObject 进行加密,在这里指定 Padding 模式
|
||||
const encrypted = publicEncrypt(
|
||||
{
|
||||
key: publicKey,
|
||||
padding: constants.RSA_PKCS1_OAEP_PADDING,
|
||||
oaepHash: OAEP_HASH,
|
||||
},
|
||||
buffer,
|
||||
)
|
||||
|
||||
return encrypted.toString('base64')
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Encryption failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 Base64 编码的私钥解密数据
|
||||
*
|
||||
* 解密标准: RSA/ECB/OAEPWithSHA-256AndMGF1Padding (兼容 Java)
|
||||
* 私钥格式: PKCS8/DER (对应 Java PKCS8EncodedKeySpec)
|
||||
*
|
||||
* @param encryptedData - Base64 编码的加密数据
|
||||
* @param privateKeyBase64 - Base64 编码的私钥 (DER/PKCS8 格式)
|
||||
* @returns 解密后的明文字符串
|
||||
* @throws {Error} 解密失败时抛出错误
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const privateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...'
|
||||
* const decrypted = decrypt('a3f5e8c2d1b4...', privateKey)
|
||||
* console.log(decrypted) // "sensitive data"
|
||||
* ```
|
||||
*/
|
||||
export function decrypt(
|
||||
encryptedData: string,
|
||||
privateKeyBase64: string,
|
||||
): string {
|
||||
const buffer = Buffer.from(encryptedData, 'base64')
|
||||
const keyBuffer = Buffer.from(privateKeyBase64, 'base64')
|
||||
|
||||
try {
|
||||
// 1. 先创建 KeyObject,在这里指定密钥的格式 (DER/PKCS8)
|
||||
const privateKey = createPrivateKey({
|
||||
key: keyBuffer,
|
||||
format: 'der',
|
||||
type: 'pkcs8', // 对应 Java PKCS8EncodedKeySpec
|
||||
})
|
||||
|
||||
// 2. 使用 KeyObject 进行解密
|
||||
const decrypted = privateDecrypt(
|
||||
{
|
||||
key: privateKey,
|
||||
padding: constants.RSA_PKCS1_OAEP_PADDING,
|
||||
oaepHash: OAEP_HASH,
|
||||
},
|
||||
buffer,
|
||||
)
|
||||
|
||||
return decrypted.toString('utf-8')
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Decryption failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user