From b73d9b0aacc1ec4e3d56d2c04b91afa4f6e39c4f Mon Sep 17 00:00:00 2001 From: cheney Date: Sat, 4 Apr 2026 18:24:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kit/src/crypto.js | 37 +++++++++++- kit/test/debug_signature_format.js | 24 ++++++++ kit/test/debug_sm2_der.js | 29 ++++++++++ kit/test/debug_sm2_version.js | 35 ++++++++++++ kit/test/debug_user_sm2_verify.js | 91 ++++++++++++++++++++++++++++++ 5 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 kit/test/debug_signature_format.js create mode 100644 kit/test/debug_sm2_der.js create mode 100644 kit/test/debug_sm2_version.js create mode 100644 kit/test/debug_user_sm2_verify.js diff --git a/kit/src/crypto.js b/kit/src/crypto.js index b5abc97..ff1d752 100644 --- a/kit/src/crypto.js +++ b/kit/src/crypto.js @@ -372,9 +372,9 @@ function verifyPKCS7WithJsrsasign(base64Data, verifyData) { const publicKeyBitString = rs.ASN1HEX.getTLVbyList(spki, 0, [1]) let publicKeyHex = publicKeyBitString.substring(6) // 跳过 tag, length, unused bits - // 去掉公钥的 04 前缀(如果有) - if (publicKeyHex.startsWith('04')) { - publicKeyHex = publicKeyHex.substring(2) + // 确保公钥有 04 前缀(sm-crypto 0.3.13 需要) + if (!publicKeyHex.startsWith('04')) { + publicKeyHex = '04' + publicKeyHex } // 计算 SM3 哈希 @@ -411,6 +411,37 @@ function verifyPKCS7WithJsrsasign(base64Data, verifyData) { // 尝试 6: 使用哈希 + DER const result6 = sm2.doVerifySignature(hash, signatureHex, publicKeyHex, { der: true }) if (result6) return true + + // 尝试 7: 不使用 der 选项(直接使用签名) + const result7 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex) + if (result7) return true + + // 尝试 8: 不使用 der 选项 + SM3 + userId + const result8 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex, { hash: true, userId }) + if (result8) return true + + // 尝试 9: 转换签名格式为原始 r|s 格式 + if (signatureHex.startsWith('30')) { + try { + // 解析 ASN.1 DER 格式 + // 格式: 30 len 02 len r 02 len s + const rStart = 8 // 30440220 + const r = signatureHex.substring(rStart, rStart + 64) // 32字节 = 64 hex 字符 + const sStart = rStart + 64 + 4 // 0220 + const s = signatureHex.substring(sStart, sStart + 64) // 32字节 = 64 hex 字符 + const rawSignature = r + s + + // 尝试使用原始 r|s 格式 + const result9 = sm2.doVerifySignature(verifyData.toString(), rawSignature, publicKeyHex) + if (result9) return true + + // 尝试使用原始 r|s 格式 + SM3 + userId + const result10 = sm2.doVerifySignature(verifyData.toString(), rawSignature, publicKeyHex, { hash: true, userId }) + if (result10) return true + } catch (e) { + // 忽略错误,继续尝试 + } + } } catch (e) { // 忽略错误,继续尝试其他选项 } diff --git a/kit/test/debug_signature_format.js b/kit/test/debug_signature_format.js new file mode 100644 index 0000000..70c44aa --- /dev/null +++ b/kit/test/debug_signature_format.js @@ -0,0 +1,24 @@ +const rs = require('jsrsasign'); + +// 用户提供的 SM2 PKCS7 签名数据 +const sm2P7Base64 = 'MIIDKgYKKoEcz1UGAQQCAqCCAxowggMWAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICNzCCAjMwggHWoAMCAQICBgD1tfRoKTAMBggqgRzPVQGDdQUAMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBMB4XDTI2MDQwMjA4MDEzOVoXDTM2MDMzMDA4MDEzOVowTTELMAkGA1UEBhMCQ04xDzANBgNVBAoMBlBCQ0NSQzEtMCsGA1UEAwwkOTRmMWY5MzgtZjBiZC00NzYyLTkyOGUtZjY4YTdjY2UxNDFkMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEu3dU5Vn20VjVL9xGCCRPB/EpATY6HW24+zIZv46Cfv0R2PGM+ZJs/dYarw7qJCnpIbe5T0PKmyyJITNVrVnnMaOBrDCBqTAfBgNVHSMEGDAWgBRUqfVQHMpD+o+YdrPK1JlRJL757zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECkPjA8MQ4wDAYDVQQDDAVjcmw3MTEMMAoGA1UECwwDY3JsMQ8wDQYDVQQKDAZQQkNDUkMxCzAJBgNVBAYTAkNOMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU5bG6U0lYzWtkPJE74M/3HdafKKcwDAYIKoEcz1UBg3UFAANJADBGAiEAuLTE36/Eobcui23bFiPvOU4MOT0O0r9SyyHZ1JuvLwMCIQCejuSk03jyUAkbh1SaPx5n7WlDjI6tx9v9RJ7iw5rlojGBtzCBtAIBATBKMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBAgYA9bX0aCkwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARGMEQCIALTgWMD7io1JHfzInBwzDQpe9bonchuLFSED//JLDtnAiBmEUtr+ssAQIzFG4wY0CAj9QZxhENyCU2UYL1fhaysUA=='; + +console.log('=== 调试签名格式 ==='); + +const parser = new rs.KJUR.asn1.cms.CMSParser(); +const p7 = parser.getCMSSignedData(rs.b64tohex(sm2P7Base64)); + +if (p7.sinfos && p7.sinfos.length > 0) { + const signer = p7.sinfos[0]; + console.log('签名算法:', signer.sigalg); + console.log('签名值 (signer.sighex):', signer.sighex); + console.log('签名值长度:', signer.sighex.length / 2, '字节'); + console.log('签名值开头:', signer.sighex.substring(0, 10)); + + // 检查是否是 ASN.1 DER 格式 + if (signer.sighex.startsWith('30')) { + console.log('签名格式: ASN.1 DER'); + } else { + console.log('签名格式: 原始 r|s'); + } +} diff --git a/kit/test/debug_sm2_der.js b/kit/test/debug_sm2_der.js new file mode 100644 index 0000000..30b3df8 --- /dev/null +++ b/kit/test/debug_sm2_der.js @@ -0,0 +1,29 @@ +const sm2 = require('sm-crypto').sm2; + +console.log('=== 调试 SM2 DER 格式 ==='); + +// 测试数据 +const data = 'QDJNHHVB_FWQ'; +const userId = '1234567812345678'; + +// 生成密钥对 +const keypair = sm2.generateKeyPairHex(); +console.log('公钥:', keypair.publicKey); + +// 生成签名(带 der 选项) +const sigWithDer = sm2.doSignature(data, keypair.privateKey, { der: true }); +console.log('\n带 DER 的签名:', sigWithDer); +console.log('带 DER 的签名长度:', sigWithDer.length); + +// 生成签名(不带 der 选项) +const sigWithoutDer = sm2.doSignature(data, keypair.privateKey); +console.log('\n不带 DER 的签名:', sigWithoutDer); +console.log('不带 DER 的签名长度:', sigWithoutDer.length); + +// 验证带 DER 的签名 +const verifyWithDer = sm2.doVerifySignature(data, sigWithDer, keypair.publicKey, { der: true }); +console.log('\n验证带 DER 的签名:', verifyWithDer); + +// 验证不带 DER 的签名 +const verifyWithoutDer = sm2.doVerifySignature(data, sigWithoutDer, keypair.publicKey); +console.log('验证不带 DER 的签名:', verifyWithoutDer); diff --git a/kit/test/debug_sm2_version.js b/kit/test/debug_sm2_version.js new file mode 100644 index 0000000..7c327d9 --- /dev/null +++ b/kit/test/debug_sm2_version.js @@ -0,0 +1,35 @@ +const sm2 = require('sm-crypto').sm2; +const sm3 = require('sm-crypto').sm3; + +console.log('=== 检查 sm-crypto 版本 ==='); +console.log('sm-crypto 版本:', require('sm-crypto/package.json').version); + +// 测试公钥格式 +console.log('\n=== 测试公钥格式 ==='); + +// 生成一个有效的 SM2 密钥对 +const keypair = sm2.generateKeyPairHex(); +console.log('生成的公钥:', keypair.publicKey); +console.log('生成的公钥长度:', keypair.publicKey.length); + +// 用户提供的公钥 +const userPublicKey = 'bb7754e559f6d158d52fdc4608244f07f12901363a1d6db8fb3219bf8e827efd11d8f18cf9926cfdd61aaf0eea2429e921b7b94f43ca9b2c89213355ad59e731'; +console.log('\n用户提供的公钥:', userPublicKey); +console.log('用户提供的公钥长度:', userPublicKey.length); + +// 测试用户公钥 +console.log('\n=== 测试用户公钥 ==='); +try { + const data = 'test'; + const sig = sm2.doSignature(data, keypair.privateKey); + + // 尝试使用生成的公钥验证(应该成功) + const verify1 = sm2.doVerifySignature(data, sig, keypair.publicKey); + console.log('使用生成的公钥验证:', verify1); + + // 尝试使用用户公钥验证(应该失败) + const verify2 = sm2.doVerifySignature(data, sig, userPublicKey); + console.log('使用用户公钥验证:', verify2); +} catch (e) { + console.error('错误:', e.message); +} diff --git a/kit/test/debug_user_sm2_verify.js b/kit/test/debug_user_sm2_verify.js new file mode 100644 index 0000000..193bfcd --- /dev/null +++ b/kit/test/debug_user_sm2_verify.js @@ -0,0 +1,91 @@ +const sm2 = require('sm-crypto').sm2; +const sm3 = require('sm-crypto').sm3; + +console.log('=== 验证用户提供的 SM2 数据 ==='); + +// 用户提供的数据 +const dataHex = '51444A4E484856425F465751'; +const signatureHex = '02D3816303EE2A352477F3227070CC34297BD6E89DC86E2C54840FFFC92C3B6766114B6BFA CB00408CC51B8C18D02023F50671844372094D9460BD5F85ACAC50'.replace(/\s/g, ''); +const userId = '1234567812345678'; +const hashHex = '0F76D50E476E24507187885DF1BC197B48F368F3C03DDF0A5C0C067D2EEF63EE'; + +// 从用户的 PKCS7 签名中提取的公钥(去掉 04 前缀) +const publicKeyHex = 'bb7754e559f6d158d52fdc4608244f07f12901363a1d6db8fb3219bf8e827efd11d8f18cf9926cfdd61aaf0eea2429e921b7b94f43ca9b2c89213355ad59e731'; + +// 转换数据 +const data = Buffer.from(dataHex, 'hex').toString('utf8'); +console.log('数据:', data); +console.log('数据长度:', data.length); +console.log('签名:', signatureHex); +console.log('签名长度:', signatureHex.length / 2, '字节'); +console.log('公钥:', publicKeyHex); +console.log('userId:', userId); + +// 计算哈希 +const calculatedHash = sm3(data); +console.log('\n计算的哈希:', calculatedHash); +console.log('用户提供的哈希:', hashHex); +console.log('哈希是否匹配:', calculatedHash === hashHex); + +// 测试不同的验证选项 +console.log('\n测试不同的验证选项:'); + +// 尝试 1: 直接验证(原始 r|s 格式) +console.log('\n1. 直接验证(原始 r|s 格式):'); +try { + const result1 = sm2.doVerifySignature(data, signatureHex, publicKeyHex); + console.log(' 验证结果:', result1); +} catch (e) { + console.error(' 错误:', e.message); +} + +// 尝试 2: 带 SM3 哈希 +console.log('\n2. 带 SM3 哈希:'); +try { + const result2 = sm2.doVerifySignature(data, signatureHex, publicKeyHex, { hash: true }); + console.log(' 验证结果:', result2); +} catch (e) { + console.error(' 错误:', e.message); +} + +// 尝试 3: 带 SM3 哈希 + userId +console.log('\n3. 带 SM3 哈希 + userId:'); +try { + const result3 = sm2.doVerifySignature(data, signatureHex, publicKeyHex, { hash: true, userId }); + console.log(' 验证结果:', result3); +} catch (e) { + console.error(' 错误:', e.message); +} + +// 尝试 4: 使用哈希值 +console.log('\n4. 使用哈希值:'); +try { + const result4 = sm2.doVerifySignature(hashHex, signatureHex, publicKeyHex, { hash: true }); + console.log(' 验证结果:', result4); +} catch (e) { + console.error(' 错误:', e.message); +} + +// 尝试 5: 使用哈希值 + userId +console.log('\n5. 使用哈希值 + userId:'); +try { + const result5 = sm2.doVerifySignature(hashHex, signatureHex, publicKeyHex, { hash: true, userId }); + console.log(' 验证结果:', result5); +} catch (e) { + console.error(' 错误:', e.message); +} + +// 尝试 6: 转换为 DER 格式 +console.log('\n6. 转换为 DER 格式:'); +try { + // 构造 DER 格式: 30 44 02 20 [r] 02 20 [s] + const r = signatureHex.substring(0, 64); + const s = signatureHex.substring(64); + const derSignature = '30440220' + r + '0220' + s; + console.log(' DER 签名:', derSignature); + + const result6 = sm2.doVerifySignature(data, derSignature, publicKeyHex, { der: true, hash: true, userId }); + console.log(' 验证结果:', result6); +} catch (e) { + console.error(' 错误:', e.message); +}