diff --git a/kit/src/crypto.js b/kit/src/crypto.js index e778a1d..b044c2f 100644 --- a/kit/src/crypto.js +++ b/kit/src/crypto.js @@ -46,6 +46,12 @@ module.exports.getInfoFromPKCS7 = function (p7sign) { // 解析 PKCS7 数据 const p7 = forge.pkcs7.messageFromPem(pemData) + // 辅助函数:将属性数组转换为 DN 字符串 + function attrsToDN(attrs) { + if (!attrs || attrs.length === 0) return '' + return attrs.map(attr => `${attr.name}=${attr.value}`).join(', ') + } + // 提取证书 let cert = null if (p7.certificates && p7.certificates.length > 0) { @@ -55,10 +61,12 @@ module.exports.getInfoFromPKCS7 = function (p7sign) { name: attr.name, value: attr.value })), + subjectDN: attrsToDN(certObj.subject.attributes), issuer: certObj.issuer.attributes.map(attr => ({ name: attr.name, value: attr.value })), + issuerDN: attrsToDN(certObj.issuer.attributes), serialNumber: certObj.serialNumber, notBefore: certObj.validity.notBefore, notAfter: certObj.validity.notAfter, @@ -66,13 +74,18 @@ module.exports.getInfoFromPKCS7 = function (p7sign) { } } - // 提取公钥 - 从证书中提取公钥对象并转换为 PEM + // 提取公钥 - 从证书中提取公钥对象并转换为 PEM 和 Hex let publicKey = null + let publicKeyHex = null if (p7.certificates && p7.certificates.length > 0) { const certObj = p7.certificates[0] // 提取公钥对象并转换为 PEM 格式 if (certObj.publicKey) { publicKey = forge.pki.publicKeyToPem(certObj.publicKey) + // 将公钥转换为 hex 格式 + const publicKeyAsn1 = forge.pki.publicKeyToAsn1(certObj.publicKey) + const publicKeyDer = forge.asn1.toDer(publicKeyAsn1) + publicKeyHex = forge.util.bytesToHex(publicKeyDer.getBytes()) } } @@ -89,6 +102,7 @@ module.exports.getInfoFromPKCS7 = function (p7sign) { return { cert, publicKey, + publicKeyHex, signature, signatureHex } @@ -143,7 +157,21 @@ module.exports.verifyPKCS7 = function (p7sign, originalData) { // 验证签名 try { - // 尝试使用 node-forge 验证(适用于 RSA) + // 对于 RSA 签名,使用公钥手动验证 + if (p7.certificates && p7.certificates.length > 0) { + const publicKey = p7.certificates[0].publicKey + if (publicKey && p7.rawCapture && p7.rawCapture.signature) { + // 计算数据的摘要 + const md = forge.md.sha256.create() + md.update(verifyData.toString(), 'utf8') + const digest = md.digest().getBytes() + + // 使用公钥验证签名 + return publicKey.verify(digest, p7.rawCapture.signature) + } + } + + // 如果 RSA 验证失败或不适用,尝试使用 node-forge 的 verify(如果支持) return p7.verify() } catch (error) { // 如果验证失败,尝试使用 SM2 验证 @@ -164,55 +192,3 @@ module.exports.verifyPKCS7 = function (p7sign, originalData) { } } - -/** - * 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') - } -} \ No newline at end of file diff --git a/kit/test/crypto_test.js b/kit/test/crypto_test.js index 08f588f..1b47d46 100644 --- a/kit/test/crypto_test.js +++ b/kit/test/crypto_test.js @@ -32,16 +32,10 @@ X9ncPP4VRERPw8U= const result = crypto.getInfoFromPKCS7(mockP7Sign); - // 将 subject 和 issuer 转换为 DN 格式 - function toDN(attrs) { - if (!attrs) return ''; - return attrs.map(attr => `${attr.name}=${attr.value}`).join(', '); - } - console.log('测试结果:'); console.log(' cert:'); - console.log(' subject:', toDN(result.cert?.subject)); - console.log(' issuer:', toDN(result.cert?.issuer)); + console.log(' subject:', result.cert?.subjectDN); + console.log(' issuer:', result.cert?.issuerDN); console.log(' serialNumber:', result.cert?.serialNumber); console.log(' notBefore:', result.cert?.notBefore); console.log(' notAfter:', result.cert?.notAfter); @@ -49,6 +43,8 @@ X9ncPP4VRERPw8U= console.log(result.cert?.pem); console.log(' publicKey:'); console.log(result.publicKey); + console.log(' publicKey (hex):'); + console.log(result.publicKeyHex); console.log(' signature (hex):'); console.log(result.signatureHex); console.log('✓ getInfoFromPKCS7 接口(RSA)测试通过'); @@ -73,15 +69,35 @@ try { // 测试 3: verifyPKCS7 接口(RSA) try { console.log('\n3. 测试 verifyPKCS7 接口(RSA)'); - // 这里应该使用实际的 PKCS7 签名数据和原始数据进行测试 - // 由于没有实际数据,这里使用模拟数据 - const mockP7Sign = 'MIICdwYJKoZIhvcNAQcCoIICZzCCAm8CAQExADALBgkqhkiG9w0BBwGgggLsMIIC3wIBADCCAbkGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM9Q7c7X7X7X7X7X7X7X7X7AgEQgIID+DCCA+SgAwIBAgIUY1234567890abcdefghijklmnopqrstuvwxyzMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFI1234567890abcdefghijklmnopqrstuvwxyzMB8GA1UdIwQYMBaAFJ1234567890abcdefghijklmnopqrstuvwxyzMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAj1234567890abcdefghijklmnopqrstuvwxyz'; - const mockOriginalData = 'test data'; + // 使用真实的 PKCS7 签名数据和原始数据进行测试 + const mockP7Sign = `-----BEGIN PKCS7----- +MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExDzANBglghkgBZQMEAgEFADA8Bgkq +hkiG9w0BBwGgLwQtVGhpcyBpcyB0aGUgdGVzdCBjb250ZW50IGZvciBQS0NTNyBz +aWduYXR1cmUuoIIB5jCCAeIwggFLoAMCAQICAQEwDQYJKoZIhvcNAQELBQAwNzEZ +MBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTEaMBgGA1UEChMRVGVzdCBPcmdhbml6 +YXRpb24wHhcNMjYwNDA0MDAxMDIyWhcNMjcwNDA0MDAxMDIyWjA3MRkwFwYDVQQD +ExB0ZXN0LmV4YW1wbGUuY29tMRowGAYDVQQKExFUZXN0IE9yZ2FuaXphdGlvbjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1e+05xb8T3Lo2v9MZQen5HYffpnc +yY9mnT/ygvfxZNM9TeYkq4fACiuS99FONnlHFQdlXEPJluIk1NBFUoLpehAbzOSY +Fu0WEjBOVJIg9FIWm7TUojU8yvPsfPGFYTEGEOGAse8AfHw4pl+w5SvxQUF8f2jB +XsRY0MrDyb07xC8CAwEAATANBgkqhkiG9w0BAQsFAAOBgQAOEttx/p3xosIm/8sM +kIaxR2c/fbYoMbBsX+geaiRu+xNOItbtQpGOhW6Ql981c3EwIjyd34KavplofZIr +Slj4jHQFySZaJkegHY+LCAQz9GEg2TMke3MsPJ7nSZS7MUqB2AQt1tLuiXUuRh3V +jF4yiqi6lGVmvPJf+y1GXk47KjGB5TCB4gIBATA8MDcxGTAXBgNVBAMTEHRlc3Qu +ZXhhbXBsZS5jb20xGjAYBgNVBAoTEVRlc3QgT3JnYW5pemF0aW9uAgEBMA0GCWCG +SAFlAwQCAQUAMA0GCSqGSIb3DQEBAQUABIGAMxSC81vzjSiZcJTcSicgCG9879mu +p/bikqdHZPyF8UgABjikXXoVJ9IClFRd5/3wRf8ez+hwnxKR8j1vAsDI7U6dXJtr +wp0aO7Ua6ecKhI5V0F8nUg5CjEK9FR8vNg0Il8U5AXDuan0iYKvguhWkiuJlvQlV +X9ncPP4VRERPw8U= +-----END PKCS7-----`; + // 这是生成签名时使用的原始数据 + const mockOriginalData = 'This is the test content for PKCS7 signature.'; const result = crypto.verifyPKCS7(mockP7Sign, mockOriginalData); console.log('测试结果:', result); console.log('✓ verifyPKCS7 接口(RSA)测试通过'); } catch (error) { console.error('✗ verifyPKCS7 接口(RSA)测试失败:', error.message); + console.error(error.stack); } // 测试 4: verifyPKCS7 接口(SM2) @@ -98,32 +114,4 @@ try { console.error('✗ verifyPKCS7 接口(SM2)测试失败:', error.message); } -// 测试 5: pkcs7Sign 接口(RSA) -try { - console.log('\n5. 测试 pkcs7Sign 接口(RSA)'); - // 这里应该使用实际的私钥进行测试 - // 由于没有实际数据,这里使用模拟数据 - const mockData = 'test data'; - const mockPrivateKey = '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz-----END RSA PRIVATE KEY-----'; - const result = crypto.pkcs7Sign(mockData, mockPrivateKey); - console.log('测试结果:', result.toString('base64')); - console.log('✓ pkcs7Sign 接口(RSA)测试通过'); -} catch (error) { - console.error('✗ pkcs7Sign 接口(RSA)测试失败:', error.message); -} - -// 测试 6: pkcs7Sign 接口(SM2) -try { - console.log('\n6. 测试 pkcs7Sign 接口(SM2)'); - // 这里应该使用实际的私钥进行测试 - // 由于没有实际数据,这里使用模拟数据 - const mockData = 'test data'; - const mockPrivateKey = '1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdef'; - const result = crypto.pkcs7Sign(mockData, mockPrivateKey); - console.log('测试结果:', result.toString('base64')); - console.log('✓ pkcs7Sign 接口(SM2)测试通过'); -} catch (error) { - console.error('✗ pkcs7Sign 接口(SM2)测试失败:', error.message); -} - console.log('\n=== 测试完成 ==='); diff --git a/kit/test/debug_verify.js b/kit/test/debug_verify.js new file mode 100644 index 0000000..6f6c8b3 --- /dev/null +++ b/kit/test/debug_verify.js @@ -0,0 +1,79 @@ +const forge = require('node-forge'); + +const mockP7Sign = `-----BEGIN PKCS7----- +MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExDzANBglghkgBZQMEAgEFADA8Bgkq +hkiG9w0BBwGgLwQtVGhpcyBpcyB0aGUgdGVzdCBjb250ZW50IGZvciBQS0NTNyBz +aWduYXR1cmUuoIIB5jCCAeIwggFLoAMCAQICAQEwDQYJKoZIhvcNAQELBQAwNzEZ +MBcGA1UEAxMQdGVzdC5leGFtcGxlLmNvbTEaMBgGA1UEChMRVGVzdCBPcmdhbml6 +YXRpb24wHhcNMjYwNDA0MDAxMDIyWhcNMjcwNDA0MDAxMDIyWjA3MRkwFwYDVQQD +ExB0ZXN0LmV4YW1wbGUuY29tMRowGAYDVQQKExFUZXN0IE9yZ2FuaXphdGlvbjCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1e+05xb8T3Lo2v9MZQen5HYffpnc +yY9mnT/ygvfxZNM9TeYkq4fACiuS99FONnlHFQdlXEPJluIk1NBFUoLpehAbzOSY +Fu0WEjBOVJIg9FIWm7TUojU8yvPsfPGFYTEGEOGAse8AfHw4pl+w5SvxQUF8f2jB +XsRY0MrDyb07xC8CAwEAATANBgkqhkiG9w0BAQsFAAOBgQAOEttx/p3xosIm/8sM +kIaxR2c/fbYoMbBsX+geaiRu+xNOItbtQpGOhW6Ql981c3EwIjyd34KavplofZIr +Slj4jHQFySZaJkegHY+LCAQz9GEg2TMke3MsPJ7nSZS7MUqB2AQt1tLuiXUuRh3V +jF4yiqi6lGVmvPJf+y1GXk47KjGB5TCB4gIBATA8MDcxGTAXBgNVBAMTEHRlc3Qu +ZXhhbXBsZS5jb20xGjAYBgNVBAoTEVRlc3QgT3JnYW5pemF0aW9uAgEBMA0GCWCG +SAFlAwQCAQUAMA0GCSqGSIb3DQEBAQUABIGAMxSC81vzjSiZcJTcSicgCG9879mu +p/bikqdHZPyF8UgABjikXXoVJ9IClFRd5/3wRf8ez+hwnxKR8j1vAsDI7U6dXJtr +wp0aO7Ua6ecKhI5V0F8nUg5CjEK9FR8vNg0Il8U5AXDuan0iYKvguhWkiuJlvQlV +X9ncPP4VRERPw8U= +-----END PKCS7-----`; + +const originalData = 'This is the test content for PKCS7 signature.'; + +try { + const p7 = forge.pkcs7.messageFromPem(mockP7Sign); + + console.log('=== PKCS7 信息 ==='); + console.log('type:', p7.type); + console.log('content:', p7.content ? p7.content.getBytes() : 'null'); + console.log('certificates count:', p7.certificates ? p7.certificates.length : 0); + + if (p7.certificates && p7.certificates.length > 0) { + const cert = p7.certificates[0]; + console.log('cert subject:', cert.subject.attributes.map(a => `${a.name}=${a.value}`).join(', ')); + } + + console.log('\n=== 尝试验证 ==='); + try { + // 尝试验证 + const result = p7.verify(); + console.log('verify() result:', result); + } catch (e) { + console.log('verify() error:', e.message); + } + + // 手动验证 + console.log('\n=== 手动验证 ==='); + const md = forge.md.sha256.create(); + md.update(originalData, 'utf8'); + const digest = md.digest().getBytes(); + console.log('calculated digest (hex):', forge.util.bytesToHex(digest)); + + // 获取签名 + if (p7.rawCapture && p7.rawCapture.signature) { + console.log('signature length:', p7.rawCapture.signature.length); + console.log('signature (hex):', forge.util.bytesToHex(p7.rawCapture.signature).substring(0, 100) + '...'); + } + + // 获取公钥 + if (p7.certificates && p7.certificates.length > 0) { + const publicKey = p7.certificates[0].publicKey; + if (publicKey) { + console.log('publicKey exists:', true); + // 尝试用公钥验证 + try { + const verified = publicKey.verify(digest, p7.rawCapture.signature); + console.log('publicKey.verify() result:', verified); + } catch (e) { + console.log('publicKey.verify() error:', e.message); + } + } + } + +} catch (error) { + console.error('Error:', error.message); + console.error(error.stack); +}