You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何两种签名方式生成的数据不一致?及Token签名代码优化咨询

问题背景与现象

操作流程

  • 使用OpenSSL生成CSR文件和私钥PEM文件:
    openssl req -new -utf8 -nameopt multiline,utf8 -config rahat.cnf -newkey rsa:2048 -nodes -keyout rahat.key -out rahat.Csr
    
  • 从证书机构获取crt格式证书,转换为cer格式后提取公钥:
    openssl x509 -pubkey -noout -in rahat.cer > pubkey.txt
    
  • 创建包含证书、公钥和私钥的p12文件:
    openssl pkcs12 -export -out rahat.p12 -inkey rahat.key -in rahat.cer
    
  • 将p12文件导入ePass3003Auto令牌,提取的cer文件导出公钥与pubkey.txt内容一致。

核心问题

用令牌对“Hello World”字符串签名,结果可通过证书/公钥验证;但用rahat.key中的Base64私钥通过本地Java代码签名同一字符串,结果与令牌签名不同。无法修改本地私钥签名代码,需调整令牌签名代码使两者签名结果一致。

相关代码

本地私钥签名代码

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.security.cert.Certificate;
import java.security.Provider;
import java.security.Security;
import java.util.Base64;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;


public byte[] signData(byte[] data, String PRIVATE_KEY) throws Exception {

    byte[] encoded = Base64.getDecoder().decode(PRIVATE_KEY);

    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey pk = kf.generatePrivate(keySpec);
    
    Signature signature = Signature.getInstance("SHA256withRSA");
    signature.initSign(pk);
    signature.update(data);

    byte[] signedData = signature.sign();

    return signedData;
}

令牌签名代码

Provider p = Security.getProvider("SunPKCS11");
p = p.configure("config.cfg");
Security.addProvider(p);
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);

char[] pin = "4321".toCharArray();
keyStore.load(null, pin);

java.util.Enumeration<String> aliases = keyStore.aliases();
String alias = aliases.nextElement();

PrivateKey pk = (PrivateKey)keyStore.getKey(alias, "4321".toCharArray());
Certificate[] chain = keyStore.getCertificateChain(alias);
X509Certificate cert = (X509Certificate)chain[0];

Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(pk);
signature.update(data);

byte[] signedData = signature.sign();

signature.initVerify(cert.getPublicKey());
signature.update(data);
boolean verified = signature.verify(signedData);
System.out.println("Verified: " + verified);
return signedData;

解决方案

原因分析

两种签名结果不一致的核心原因是RSA签名填充方式不匹配:本地代码使用的SHA256withRSA对应标准的PKCS#1 v1.5固定填充,而ePass3003Auto令牌默认可能启用了RSASSA-PSS概率性填充,导致签名结果不同。此外需确保待签名的字节数组完全一致(如字符串转byte时的编码统一)。

修改后的令牌签名代码

需强制指定令牌使用PKCS#1 v1.5填充的签名算法,同时确保输入数据编码与本地代码一致:

Provider p = Security.getProvider("SunPKCS11");
p = p.configure("config.cfg");
Security.addProvider(p);
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);

char[] pin = "4321".toCharArray();
keyStore.load(null, pin);

java.util.Enumeration<String> aliases = keyStore.aliases();
String alias = aliases.nextElement();

PrivateKey pk = (PrivateKey)keyStore.getKey(alias, "4321".toCharArray());
Certificate[] chain = keyStore.getCertificateChain(alias);
X509Certificate cert = (X509Certificate)chain[0];

// 强制指定PKCS#1 v1.5填充的SHA256withRSA算法,部分PKCS11驱动需明确填充类型
Signature signature = Signature.getInstance("SHA256withRSA");
// 若上述写法不生效,尝试带填充标识的完整算法名称:
// Signature signature = Signature.getInstance("SHA256withRSA/PKCS1Padding", p);

// 确保待签名数据编码与本地代码一致(示例:统一用UTF-8转字符串为字节数组)
// byte[] data = "Hello World".getBytes(java.nio.charset.StandardCharsets.UTF_8);

signature.initSign(pk);
signature.update(data);

byte[] signedData = signature.sign();

signature.initVerify(cert.getPublicKey());
signature.update(data);
boolean verified = signature.verify(signedData);
System.out.println("Verified: " + verified);
return signedData;

额外检查项

  1. 算法名称兼容性:若SHA256withRSA仍不生效,尝试SHA256withRSAEncryption作为算法名称,适配不同PKCS11驱动的命名规则。
  2. 令牌配置验证:通过ePassManagerAdm_3003.exe检查令牌的签名模板,确认是否默认启用PSS填充,需调整为PKCS#1 v1.5填充。
  3. 输入数据一致性:确保两种场景下待签名的data字节数组完全相同(无编码差异、隐藏字符等)。

内容的提问来源于stack exchange,提问作者RAHAT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 12:57:51