2026-03-05 01:48:10 +08:00
|
|
|
|
import crypto from 'crypto';
|
|
|
|
|
|
|
|
|
|
|
|
/** 自动补全 PEM 格式(PKCS8) */
|
|
|
|
|
|
function formatPrivateKey(key: string): string {
|
|
|
|
|
|
if (key.includes('-----BEGIN')) return key;
|
|
|
|
|
|
return `-----BEGIN PRIVATE KEY-----\n${key}\n-----END PRIVATE KEY-----`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatPublicKey(key: string): string {
|
|
|
|
|
|
if (key.includes('-----BEGIN')) return key;
|
|
|
|
|
|
return `-----BEGIN PUBLIC KEY-----\n${key}\n-----END PUBLIC KEY-----`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 生成 RSA2 签名 */
|
|
|
|
|
|
export function generateSign(params: Record<string, string>, privateKey: string): string {
|
|
|
|
|
|
const filtered = Object.entries(params)
|
2026-03-07 04:15:48 +08:00
|
|
|
|
.filter(([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null)
|
2026-03-05 01:48:10 +08:00
|
|
|
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
|
|
|
|
|
|
|
|
|
|
const signStr = filtered.map(([key, value]) => `${key}=${value}`).join('&');
|
|
|
|
|
|
|
|
|
|
|
|
const signer = crypto.createSign('RSA-SHA256');
|
|
|
|
|
|
signer.update(signStr);
|
|
|
|
|
|
return signer.sign(formatPrivateKey(privateKey), 'base64');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 用支付宝公钥验证签名 */
|
|
|
|
|
|
export function verifySign(params: Record<string, string>, alipayPublicKey: string, sign: string): boolean {
|
|
|
|
|
|
const filtered = Object.entries(params)
|
2026-03-07 04:15:48 +08:00
|
|
|
|
.filter(([key, value]) => key !== 'sign' && key !== 'sign_type' && value !== '' && value !== undefined && value !== null)
|
2026-03-05 01:48:10 +08:00
|
|
|
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
|
|
|
|
|
|
|
|
|
|
const signStr = filtered.map(([key, value]) => `${key}=${value}`).join('&');
|
|
|
|
|
|
|
|
|
|
|
|
const verifier = crypto.createVerify('RSA-SHA256');
|
|
|
|
|
|
verifier.update(signStr);
|
|
|
|
|
|
return verifier.verify(formatPublicKey(alipayPublicKey), sign, 'base64');
|
|
|
|
|
|
}
|