rsa p7 info 通过

This commit is contained in:
cheney
2026-04-04 08:24:27 +08:00
parent e97d7d7fd0
commit 5a033318c0
6 changed files with 457 additions and 0 deletions
+200
View File
@@ -1,5 +1,8 @@
const sm4 = require('sm-crypto').sm4
const sm3 = require('sm-crypto').sm3
const sm2 = require('sm-crypto').sm2
const crypto = require('crypto')
const forge = require('node-forge')
module.exports.sm4en3 = function (key, data){
@@ -15,4 +18,201 @@ module.exports.sm4de3 = function (key, data){
sm3key = sm3key.substring(0, 32)
let decryptData = sm4.decrypt(data, sm3key)
return decryptData
}
/**
* 从 PKCS7 签名中获取信息(包含证书、公钥和签名值)
* @param {Buffer|string} p7sign - PKCS7 签名数据
* @returns {Object} 包含证书、公钥和签名值的对象
*/
module.exports.getInfoFromPKCS7 = function (p7sign) {
// 处理输入数据
let pemData
if (Buffer.isBuffer(p7sign)) {
pemData = p7sign.toString('ascii')
} else if (typeof p7sign === 'string') {
// 判断是否是 PEM 格式
if (p7sign.includes('-----BEGIN PKCS7-----')) {
pemData = p7sign
} else {
// 如果不是 PEM 格式,假设是 base64,包装成 PEM
pemData = `-----BEGIN PKCS7-----\n${p7sign}\n-----END PKCS7-----`
}
} else {
throw new Error('Invalid input type for p7sign')
}
// 解析 PKCS7 数据
const p7 = forge.pkcs7.messageFromPem(pemData)
// 提取证书
let cert = null
if (p7.certificates && p7.certificates.length > 0) {
const certObj = p7.certificates[0]
cert = {
subject: certObj.subject.attributes.map(attr => ({
name: attr.name,
value: attr.value
})),
issuer: certObj.issuer.attributes.map(attr => ({
name: attr.name,
value: attr.value
})),
serialNumber: certObj.serialNumber,
notBefore: certObj.validity.notBefore,
notAfter: certObj.validity.notAfter,
pem: forge.pki.certificateToPem(certObj)
}
}
// 提取公钥 - 从证书中提取公钥对象并转换为 PEM
let publicKey = null
if (p7.certificates && p7.certificates.length > 0) {
const certObj = p7.certificates[0]
// 提取公钥对象并转换为 PEM 格式
if (certObj.publicKey) {
publicKey = forge.pki.publicKeyToPem(certObj.publicKey)
}
}
// 提取签名值 - 从 rawCapture 中获取(已经是原始签名值)
let signature = null
let signatureHex = null
if (p7.rawCapture && p7.rawCapture.signature) {
// rawCapture.signature 已经是原始签名值字符串
signature = forge.util.encode64(p7.rawCapture.signature)
// 同时提供 hex 格式
signatureHex = forge.util.bytesToHex(p7.rawCapture.signature)
}
return {
cert,
publicKey,
signature,
signatureHex
}
}
/**
* 验签 PKCS7 签名(自动判断 RSA 或 SM2 算法)
* @param {Buffer|string} p7sign - PKCS7 签名数据
* @param {Buffer|string} [originalData] - 原始数据,当签名是 detech 时必须,当签名是 attach 时不传
* @returns {boolean} 验签结果
*/
module.exports.verifyPKCS7 = function (p7sign, originalData) {
// 处理输入数据
let pemData
if (Buffer.isBuffer(p7sign)) {
pemData = p7sign.toString('ascii')
} else if (typeof p7sign === 'string') {
// 判断是否是 PEM 格式
if (p7sign.includes('-----BEGIN PKCS7-----')) {
pemData = p7sign
} else {
// 如果不是 PEM 格式,假设是 base64,包装成 PEM
pemData = `-----BEGIN PKCS7-----\n${p7sign}\n-----END PKCS7-----`
}
} else {
throw new Error('Invalid input type for p7sign')
}
// 解析 PKCS7 数据
const p7 = forge.pkcs7.messageFromPem(pemData)
// 准备验证所需的数据
let verifyData
if (originalData) {
// 当提供了原始数据时,使用原始数据进行验证(detch 模式)
if (Buffer.isBuffer(originalData)) {
verifyData = originalData
} else if (typeof originalData === 'string') {
verifyData = Buffer.from(originalData)
} else {
throw new Error('Invalid input type for originalData')
}
} else {
// 当没有提供原始数据时,从 PKCS7 中提取数据进行验证(attach 模式)
if (p7.content) {
verifyData = Buffer.from(p7.content.getBytes(), 'binary')
} else {
throw new Error('No content found in PKCS7 signature for attach mode')
}
}
// 验证签名
try {
// 尝试使用 node-forge 验证(适用于 RSA)
return p7.verify()
} catch (error) {
// 如果验证失败,尝试使用 SM2 验证
try {
// 提取签名值和公钥
const signInfo = module.exports.getInfoFromPKCS7(p7sign)
if (!signInfo.publicKey || !signInfo.signature) {
throw new Error('Cannot extract public key or signature from PKCS7')
}
// 使用 SM2 验证签名
const hash = sm3(verifyData.toString())
return sm2.doVerify(hash, signInfo.signature, signInfo.publicKey)
} catch (sm2Error) {
console.error('SM2 verification error:', sm2Error)
return false
}
}
}
/**
* PKCS7 签名(自动判断 RSA 或 SM2 算法)
* @param {Buffer|string} data - 待签名数据
* @param {string} privateKey - 私钥
* @returns {Buffer} PKCS7 签名数据
*/
module.exports.pkcs7Sign = function (data, privateKey) {
// 处理输入数据
let inputData
if (Buffer.isBuffer(data)) {
inputData = data
} else if (typeof data === 'string') {
inputData = Buffer.from(data)
} else {
throw new Error('Invalid input type for data')
}
// 判断私钥类型
if (privateKey.includes('RSA PRIVATE KEY')) {
// RSA 算法签名
const pkey = forge.pki.privateKeyFromPem(privateKey)
const p7 = forge.pkcs7.createSignedData()
p7.content = forge.util.createBuffer(inputData.toString('binary'))
p7.addCertificate(forge.pki.certificateFromPem(privateKey)) // 假设私钥包含证书
p7.addSigner({
key: pkey,
certificate: forge.pki.certificateFromPem(privateKey),
digestAlgorithm: forge.pki.oids.sha256
})
p7.sign()
const pem = forge.pkcs7.messageToPem(p7)
return Buffer.from(pem, 'ascii')
} else if (privateKey.includes('SM2') || privateKey.length === 64) {
// SM2 算法签名
// 由于 node-forge 不直接支持 SM2 算法
// 这里需要使用 sm-crypto 库进行 SM2 签名,然后封装到 PKCS7 格式中
// 注意:这只是一个简化的实现,实际应用中可能需要更复杂的处理
const hash = sm3(inputData.toString())
const signature = sm2.doSignature(hash, privateKey)
// 创建一个简单的 PKCS7 结构来存储 SM2 签名
// 注意:这不是标准的 PKCS7 SM2 签名实现
const p7 = forge.pkcs7.createSignedData()
p7.content = forge.util.createBuffer(inputData.toString('binary'))
// 这里需要添加 SM2 证书和签名逻辑
// 由于复杂性,这里暂时抛出错误
throw new Error('SM2 PKCS7 signature not fully implemented yet')
} else {
throw new Error('Unsupported private key type')
}
}