如何实现KECCAK-384哈希与NONEwithRSA签名分步操作(无外部库)
解决方案
核心逻辑
由于KECCAK-384无官方标准OID,无法直接通过Signature.getInstance("KECCAK-384withRSA")调用标准签名算法,因此需要手动构造符合PKCS#1规范的DigestInfo DER结构,再通过NoneWithRSA签名该结构,以此等效实现「KECCAK-384哈希→RSA签名」的两步流程。
分步实现
1. 计算KECCAK-384哈希值
Java 11及以上版本原生支持KECCAK哈希算法,直接通过MessageDigest计算:
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; // 待签名原始数据 byte[] rawData = "your data to sign".getBytes(); // 计算KECCAK-384哈希 MessageDigest keccakDigest = MessageDigest.getInstance("KECCAK-384"); byte[] hashValue = keccakDigest.digest(rawData);
2. 手动构造DigestInfo的DER编码
PKCS#1定义的DigestInfo ASN.1结构为:
DigestInfo ::= SEQUENCE { digestAlgorithm AlgorithmIdentifier, digest OCTET STRING } AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL }
KECCAK-384对应的标准OID为2.16.840.1.101.3.4.2.9,我们基于该OID构造DER编码:
import java.io.ByteArrayOutputStream; import java.io.IOException; // 1. 构造AlgorithmIdentifier的DER编码 // KECCAK-384 OID的DER编码:06 09 60 86 48 01 65 03 04 02 09 byte[] oidDer = new byte[]{0x06, 0x09, 0x60, (byte)0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09}; // 参数部分为NULL(KECCAK无额外参数),DER编码:05 00 byte[] paramsDer = new byte[]{0x05, 0x00}; ByteArrayOutputStream algIdBaos = new ByteArrayOutputStream(); algIdBaos.write(0x30); // SEQUENCE标签 algIdBaos.write(oidDer.length + paramsDer.length); // 总长度 algIdBaos.write(oidDer); algIdBaos.write(paramsDer); byte[] algIdDer = algIdBaos.toByteArray(); // 2. 构造Digest的OCTET STRING编码 ByteArrayOutputStream digestBaos = new ByteArrayOutputStream(); digestBaos.write(0x04); // OCTET STRING标签 digestBaos.write(hashValue.length); // 哈希值长度 digestBaos.write(hashValue); byte[] digestDer = digestBaos.toByteArray(); // 3. 构造完整的DigestInfo SEQUENCE ByteArrayOutputStream digestInfoBaos = new ByteArrayOutputStream(); digestInfoBaos.write(0x30); // SEQUENCE标签 digestInfoBaos.write(algIdDer.length + digestDer.length); // 总长度 digestInfoBaos.write(algIdDer); digestInfoBaos.write(digestDer); byte[] digestInfo = digestInfoBaos.toByteArray();
3. 执行RSA签名
与你提供的SHA3-384示例逻辑一致,使用NoneWithRSA签名构造好的DigestInfo:
import java.security.KeyPair; import java.security.PrivateKey; import java.security.Signature; import java.security.NoSuchAlgorithmException; import java.security.InvalidKeyException; import java.security.SignatureException; // 初始化RSA签名实例 Signature signatureEngine = Signature.getInstance("NoneWithRSA"); PrivateKey rsaPrivateKey = yourRsaKeyPair.getPrivate(); // 替换为你的RSA私钥 signatureEngine.initSign(rsaPrivateKey); signatureEngine.update(digestInfo); byte[] finalSignature = signatureEngine.sign();
签名验证说明
验证签名时需同步执行以下步骤:
- 对原始数据重新计算KECCAK-384哈希
- 使用相同OID构造DigestInfo
- 初始化
NoneWithRSA签名实例,传入公钥后调用verify()方法,传入DigestInfo和签名值
内容的提问来源于stack exchange,提问作者Chico Rico
相关产品推荐
相关产品推荐

