sm2 验签不通过

This commit is contained in:
cheney 2026-04-04 17:54:13 +08:00
parent f9d9203349
commit 959f058def
6 changed files with 376 additions and 2 deletions

View File

@ -370,13 +370,70 @@ function verifyPKCS7WithJsrsasign(base64Data, verifyData) {
const tbsCert = rs.ASN1HEX.getTLVbyList(certHex, 0, [0])
const spki = rs.ASN1HEX.getTLVbyList(tbsCert, 0, [6])
const publicKeyBitString = rs.ASN1HEX.getTLVbyList(spki, 0, [1])
const publicKeyHex = publicKeyBitString.substring(6) // 跳过 tag, length, unused bits
let publicKeyHex = publicKeyBitString.substring(6) // 跳过 tag, length, unused bits
// 去掉公钥的 04 前缀(如果有)
if (publicKeyHex.startsWith('04')) {
publicKeyHex = publicKeyHex.substring(2)
}
// 计算 SM3 哈希
const hash = sm3(verifyData.toString())
// 转换签名格式:从 ASN.1 DER 格式转换为原始 r|s 格式
let signatureHex = signer.sighex
if (signatureHex.startsWith('30')) {
// ASN.1 DER 格式: 30 44 02 20 [r] 02 20 [s]
try {
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 字符
signatureHex = r + s
} catch (e) {
// 如果解析失败,使用原始签名
}
}
// 使用 SM2 验证签名 (注意:使用 doVerifySignature不是 doVerify)
return sm2.doVerifySignature(hash, signer.sighex, publicKeyHex)
// 尝试不同的选项组合
try {
// 尝试 1: 直接验证
const result1 = sm2.doVerifySignature(hash, signatureHex, publicKeyHex)
if (result1) return true
// 尝试 2: 使用 DER 格式
const result2 = sm2.doVerifySignature(hash, signatureHex, publicKeyHex, { der: true })
if (result2) return true
// 尝试 3: 使用 SM3 哈希
const result3 = sm2.doVerifySignature(hash, signatureHex, publicKeyHex, { hash: true })
if (result3) return true
// 尝试 4: 同时使用 DER 和 SM3
const result4 = sm2.doVerifySignature(hash, signatureHex, publicKeyHex, { der: true, hash: true })
if (result4) return true
// 尝试 5: 直接使用原始数据而不是哈希
const result5 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex)
if (result5) return true
// 尝试 6: 使用原始数据 + DER
const result6 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex, { der: true })
if (result6) return true
// 尝试 7: 使用原始数据 + SM3
const result7 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex, { hash: true })
if (result7) return true
// 尝试 8: 所有选项
const result8 = sm2.doVerifySignature(verifyData.toString(), signatureHex, publicKeyHex, { der: true, hash: true })
if (result8) return true
} catch (e) {
// 忽略错误,继续尝试其他选项
}
return false
} else {
// RSA 验证(通过 jsrsasign
try {

View File

@ -0,0 +1,42 @@
const crypto = require('../src/crypto.js');
// 用户提供的 SM2 PKCS7 签名数据
const sm2P7Base64 = 'MIIDKgYKKoEcz1UGAQQCAqCCAxowggMWAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICNzCCAjMwggHWoAMCAQICBgD1tfRoKTAMBggqgRzPVQGDdQUAMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBMB4XDTI2MDQwMjA4MDEzOVoXDTM2MDMzMDA4MDEzOVowTTELMAkGA1UEBhMCQ04xDzANBgNVBAoMBlBCQ0NSQzEtMCsGA1UEAwwkOTRmMWY5MzgtZjBiZC00NzYyLTkyOGUtZjY4YTdjY2UxNDFkMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEu3dU5Vn20VjVL9xGCCRPB/EpATY6HW24+zIZv46Cfv0R2PGM+ZJs/dYarw7qJCnpIbe5T0PKmyyJITNVrVnnMaOBrDCBqTAfBgNVHSMEGDAWgBRUqfVQHMpD+o+YdrPK1JlRJL757zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECkPjA8MQ4wDAYDVQQDDAVjcmw3MTEMMAoGA1UECwwDY3JsMQ8wDQYDVQQKDAZQQkNDUkMxCzAJBgNVBAYTAkNOMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU5bG6U0lYzWtkPJE74M/3HdafKKcwDAYIKoEcz1UBg3UFAANJADBGAiEAuLTE36/Eobcui23bFiPvOU4MOT0O0r9SyyHZ1JuvLwMCIQCejuSk03jyUAkbh1SaPx5n7WlDjI6tx9v9RJ7iw5rlojGBtzCBtAIBATBKMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBAgYA9bX0aCkwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARGMEQCIALTgWMD7io1JHfzInBwzDQpe9bonchuLFSED//JLDtnAiBmEUtr+ssAQIzFG4wY0CAj9QZxhENyCU2UYL1fhaysUA==';
console.log('=== 测试不同的原始数据 ===');
// 测试不同的原始数据
const testDataList = [
'QDJNHHVB_FWQ',
'QDJNHHVB_FWQ\n',
'QDJNHHVB_FWQ\r\n',
'QDJNHHVB FWQ', // 空格替换下划线
'QDJNHHVB_FW', // 少一个字符
'QDJNHHVB_FWQQ', // 多一个字符
'qDJNHHVB_FWQ', // 小写
'QDJnhhVB_FWQ', // 混合大小写
'1234567890', // 数字
'', // 空字符串
];
testDataList.forEach((data, index) => {
console.log(`\n测试数据 ${index + 1}: "${data}"`);
console.log(` 长度: ${data.length}`);
console.log(` UTF-8 编码: ${Buffer.from(data, 'utf8').toString('hex')}`);
const result = crypto.verifyPKCS7(sm2P7Base64, data);
console.log(` 验证结果: ${result}`);
if (result) {
console.log(' ✅ 验证成功!');
}
});
// 也测试一下 attach 模式
console.log('\n=== 测试 attach 模式 ===');
try {
const result = crypto.verifyPKCS7(sm2P7Base64);
console.log('attach 模式验证结果:', result);
} catch (e) {
console.error('attach 模式错误:', e.message);
}

View File

@ -0,0 +1,45 @@
const sm2 = require('sm-crypto').sm2;
const sm3 = require('sm-crypto').sm3;
console.log('=== 调试 SM2 公钥格式 ===');
// 测试数据
const testData = 'QDJNHHVB_FWQ';
const hash = sm3(testData);
console.log('测试数据:', testData);
console.log('SM3 哈希:', hash);
// 用户提供的签名ASN.1 DER 格式)
const userSignature = '3044022002d3816303ee2a352477f3227070cc34297bd6e89dc86e2c54840fffc92c3b67022066114b6bfacb00408cc51b8c18d02023f50671844372094d9460bd5f85acac50';
// 解析签名
const rStart = 8;
const r = userSignature.substring(rStart, rStart + 64);
const sStart = rStart + 64 + 4;
const s = userSignature.substring(sStart, sStart + 64);
const rawSignature = r + s;
console.log('\n原始签名格式:', rawSignature);
// 用户公钥
const userPublicKey = '04bb7754e559f6d158d52fdc4608244f07f12901363a1d6db8fb3219bf8e827efd11d8f18cf9926cfdd61aaf0eea2429e921b7b94f43ca9b2c89213355ad59e731';
console.log('\n完整公钥:', userPublicKey);
// 去掉 04 前缀
const pubKeyWithoutPrefix = userPublicKey.substring(2);
console.log('去掉前缀的公钥:', pubKeyWithoutPrefix);
// 尝试验证
console.log('\n验证结果:');
try {
const result1 = sm2.doVerifySignature(hash, rawSignature, userPublicKey);
console.log(' 使用完整公钥:', result1);
} catch (e) {
console.error(' 完整公钥错误:', e.message);
}
try {
const result2 = sm2.doVerifySignature(hash, rawSignature, pubKeyWithoutPrefix);
console.log(' 使用去掉前缀的公钥:', result2);
} catch (e) {
console.error(' 去掉前缀错误:', e.message);
}

View File

@ -0,0 +1,67 @@
const sm2 = require('sm-crypto').sm2;
const sm3 = require('sm-crypto').sm3;
console.log('=== 调试 SM2 签名格式 ===');
// 生成测试数据
const testData = 'QDJNHHVB_FWQ';
const hash = sm3(testData);
console.log('测试数据:', testData);
console.log('SM3 哈希:', hash);
// 生成密钥对
const keypair = sm2.generateKeyPairHex();
console.log('\n生成的密钥对:');
console.log(' 私钥:', keypair.privateKey);
console.log(' 公钥:', keypair.publicKey);
// 生成签名
const sig = sm2.doSignature(hash, keypair.privateKey);
console.log('\nsm-crypto 生成的签名:', sig);
console.log('签名长度:', sig.length);
// 验证签名
const verifyResult = sm2.doVerifySignature(hash, sig, keypair.publicKey);
console.log('验证结果:', verifyResult);
// 对比用户提供的签名
const userSignature = '3044022002d3816303ee2a352477f3227070cc34297bd6e89dc86e2c54840fffc92c3b67022066114b6bfacb00408cc51b8c18d02023f50671844372094d9460bd5f85acac50';
console.log('\n用户提供的签名:', userSignature);
console.log('用户签名长度:', userSignature.length);
// 分析签名格式
console.log('\n签名格式分析:');
console.log('sm-crypto 签名格式:', sig.length === 128 ? '原始 r|s 格式' : '其他格式');
console.log('用户签名格式:', userSignature.startsWith('30') ? 'ASN.1 DER 格式' : '其他格式');
// 尝试转换用户签名格式
if (userSignature.startsWith('30')) {
console.log('\n尝试将 ASN.1 DER 格式转换为原始格式:');
try {
// 解析 ASN.1 DER 格式
// 格式: 30 len 02 len r 02 len s
const rStart = 6; // 30 44 02 20
const rLen = parseInt(userSignature.substring(4, 6), 16) * 2;
const r = userSignature.substring(rStart, rStart + rLen);
const sStart = rStart + rLen + 4; // 02 20
const sLen = parseInt(userSignature.substring(rStart + rLen + 2, rStart + rLen + 4), 16) * 2;
const s = userSignature.substring(sStart, sStart + sLen);
console.log(' 提取的 r:', r);
console.log(' 提取的 s:', s);
// 组合成原始格式
const rawSignature = r + s;
console.log(' 转换后的原始格式:', rawSignature);
console.log(' 原始格式长度:', rawSignature.length);
// 尝试验证
const userPublicKey = '04bb7754e559f6d158d52fdc4608244f07f12901363a1d6db8fb3219bf8e827efd11d8f18cf9926cfdd61aaf0eea2429e921b7b94f43ca9b2c89213355ad59e731';
const result = sm2.doVerifySignature(hash, rawSignature, userPublicKey);
console.log(' 验证结果:', result);
} catch (e) {
console.error(' 转换错误:', e.message);
}
}

View File

@ -0,0 +1,50 @@
const sm2 = require('sm-crypto').sm2;
const sm3 = require('sm-crypto').sm3;
console.log('=== 调试 SM2 签名格式(正确解析)===');
// 测试数据
const testData = 'QDJNHHVB_FWQ';
const hash = sm3(testData);
console.log('测试数据:', testData);
console.log('SM3 哈希:', hash);
// 用户提供的签名ASN.1 DER 格式)
const userSignature = '3044022002d3816303ee2a352477f3227070cc34297bd6e89dc86e2c54840fffc92c3b67022066114b6bfacb00408cc51b8c18d02023f50671844372094d9460bd5f85acac50';
console.log('\n用户提供的签名:', userSignature);
// 正确解析 ASN.1 DER 格式
console.log('\n正确解析 ASN.1 DER 格式:');
try {
// 30 44 02 20 [r] 02 20 [s]
// 30 = 序列
// 44 = 长度 68 字节
// 02 = 整数
// 20 = 长度 32 字节
// 提取 r 值
const rStart = 8; // 30440220
const r = userSignature.substring(rStart, rStart + 64); // 32字节 = 64 hex 字符
console.log(' r 值:', r);
// 提取 s 值
const sStart = rStart + 64 + 4; // 0220
const s = userSignature.substring(sStart, sStart + 64); // 32字节 = 64 hex 字符
console.log(' s 值:', s);
// 组合成原始格式 (r + s)
const rawSignature = r + s;
console.log(' 转换后的原始格式:', rawSignature);
console.log(' 原始格式长度:', rawSignature.length);
// 用户公钥
const userPublicKey = '04bb7754e559f6d158d52fdc4608244f07f12901363a1d6db8fb3219bf8e827efd11d8f18cf9926cfdd61aaf0eea2429e921b7b94f43ca9b2c89213355ad59e731';
console.log('\n用户公钥:', userPublicKey);
// 尝试验证
const result = sm2.doVerifySignature(hash, rawSignature, userPublicKey);
console.log('\n验证结果:', result);
} catch (e) {
console.error('解析错误:', e.message);
}

View File

@ -0,0 +1,113 @@
const rs = require('jsrsasign');
const sm2 = require('sm-crypto').sm2;
const sm3 = require('sm-crypto').sm3;
// 用户提供的 SM2 PKCS7 签名数据
const sm2P7Base64 = 'MIIDKgYKKoEcz1UGAQQCAqCCAxowggMWAgEBMQ4wDAYIKoEcz1UBgxEFADAMBgoqgRzPVQYBBAIBoIICNzCCAjMwggHWoAMCAQICBgD1tfRoKTAMBggqgRzPVQGDdQUAMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBMB4XDTI2MDQwMjA4MDEzOVoXDTM2MDMzMDA4MDEzOVowTTELMAkGA1UEBhMCQ04xDzANBgNVBAoMBlBCQ0NSQzEtMCsGA1UEAwwkOTRmMWY5MzgtZjBiZC00NzYyLTkyOGUtZjY4YTdjY2UxNDFkMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEu3dU5Vn20VjVL9xGCCRPB/EpATY6HW24+zIZv46Cfv0R2PGM+ZJs/dYarw7qJCnpIbe5T0PKmyyJITNVrVnnMaOBrDCBqTAfBgNVHSMEGDAWgBRUqfVQHMpD+o+YdrPK1JlRJL757zAJBgNVHRMEAjAAME8GA1UdHwRIMEYwRKBCoECkPjA8MQ4wDAYDVQQDDAVjcmw3MTEMMAoGA1UECwwDY3JsMQ8wDQYDVQQKDAZQQkNDUkMxCzAJBgNVBAYTAkNOMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQU5bG6U0lYzWtkPJE74M/3HdafKKcwDAYIKoEcz1UBg3UFAANJADBGAiEAuLTE36/Eobcui23bFiPvOU4MOT0O0r9SyyHZ1JuvLwMCIQCejuSk03jyUAkbh1SaPx5n7WlDjI6tx9v9RJ7iw5rlojGBtzCBtAIBATBKMEAxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZQQkNDUkMxIDAeBgNVBAMMF1BCQ0NSQyBTTTIgT3BlcmF0aW9uIENBAgYA9bX0aCkwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARGMEQCIALTgWMD7io1JHfzInBwzDQpe9bonchuLFSED//JLDtnAiBmEUtr+ssAQIzFG4wY0CAj9QZxhENyCU2UYL1fhaysUA==';
// 测试用的原始数据
const mockOriginalData = 'QDJNHHVB_FWQ';
console.log('=== 详细调试 SM2 PKCS7 验证 ===');
console.log('原始数据:', mockOriginalData);
console.log('原始数据长度:', mockOriginalData.length);
console.log('原始数据 UTF-8 编码:', Buffer.from(mockOriginalData, 'utf8').toString('hex'));
const parser = new rs.KJUR.asn1.cms.CMSParser();
const p7 = parser.getCMSSignedData(rs.b64tohex(sm2P7Base64));
console.log('\nPKCS7 信息:');
console.log('版本:', p7.version);
console.log('哈希算法:', p7.hashalgs);
console.log('签名者数量:', p7.sinfos ? p7.sinfos.length : 0);
if (p7.sinfos && p7.sinfos.length > 0) {
const signer = p7.sinfos[0];
console.log('\n签名者信息:');
console.log(' 签名算法:', signer.sigalg);
console.log(' 签名值 (hex):', signer.sighex);
console.log(' 签名值长度:', signer.sighex ? signer.sighex.length / 2 : 0, '字节');
// 解析签名值ASN.1 DER 格式)
console.log('\n解析签名值:');
try {
const sigAsn1 = rs.ASN1HEX.getTLVbyList(signer.sighex, 0, []);
console.log(' 签名 ASN.1 结构:', sigAsn1);
// 提取 r 和 s 值
const r = rs.ASN1HEX.getTLVbyList(sigAsn1, 0, [0]);
const s = rs.ASN1HEX.getTLVbyList(sigAsn1, 0, [1]);
console.log(' r 值:', r.substring(4)); // 跳过 tag 和 length
console.log(' s 值:', s.substring(4));
} catch (e) {
console.error(' 解析签名值错误:', e.message);
}
}
// 提取公钥
if (p7.certs && p7.certs.array && p7.certs.array.length > 0) {
const certPem = p7.certs.array[0];
const certHex = rs.pemtohex(certPem);
const tbsCert = rs.ASN1HEX.getTLVbyList(certHex, 0, [0]);
const spki = rs.ASN1HEX.getTLVbyList(tbsCert, 0, [6]);
const publicKeyBitString = rs.ASN1HEX.getTLVbyList(spki, 0, [1]);
const publicKeyHex = publicKeyBitString.substring(6);
console.log('\n公钥信息:');
console.log(' 公钥 (hex):', publicKeyHex);
console.log(' 公钥长度:', publicKeyHex.length / 2, '字节');
console.log(' 公钥格式:', publicKeyHex.startsWith('04') ? '未压缩格式' : '压缩格式');
// 尝试验证签名
if (p7.sinfos && p7.sinfos.length > 0) {
const signer = p7.sinfos[0];
// 计算 SM3 哈希
console.log('\n计算 SM3 哈希:');
const hash = sm3(mockOriginalData);
console.log(' 原始数据哈希:', hash);
// 测试不同的公钥格式
console.log('\n测试不同的公钥格式:');
// 1. 使用完整公钥(带 04 前缀)
try {
const result1 = sm2.doVerifySignature(hash, signer.sighex, publicKeyHex);
console.log(' 验证结果(完整公钥):', result1);
} catch (e) {
console.error(' 验证错误(完整公钥):', e.message);
}
// 2. 使用不带 04 前缀的公钥
try {
const pubKeyWithoutPrefix = publicKeyHex.substring(2);
const result2 = sm2.doVerifySignature(hash, signer.sighex, pubKeyWithoutPrefix);
console.log(' 验证结果(不带前缀):', result2);
} catch (e) {
console.error(' 验证错误(不带前缀):', e.message);
}
// 3. 尝试使用签名值的不同格式
console.log('\n测试不同的签名值格式:');
try {
// 直接使用 sighex
const result3 = sm2.doVerifySignature(hash, signer.sighex, publicKeyHex);
console.log(' 验证结果(直接使用 sighex:', result3);
} catch (e) {
console.error(' 验证错误(直接使用 sighex:', e.message);
}
// 4. 测试不同的编码
console.log('\n测试不同的编码:');
try {
// 使用 Buffer 转换
const hashBuffer = Buffer.from(mockOriginalData, 'utf8');
const hash2 = sm3(hashBuffer);
console.log(' Buffer 哈希:', hash2);
const result4 = sm2.doVerifySignature(hash2, signer.sighex, publicKeyHex);
console.log(' 验证结果Buffer 编码):', result4);
} catch (e) {
console.error(' 验证错误Buffer 编码):', e.message);
}
}
}