单独的摘要&使用java安全提供程序签名 [英] Separate digest & signing using java security provider
问题描述
这是一个基本的工作示例:
public void rsaSignatureIntegrityTest(){
KeyPairGenerator gen = KeyPairGenerator.getInstance(RSA);
gen.initialize(2048,new SecureRandom());
KeyPair pair = gen.generateKeyPair();
byte [] digest = MessageDigest.getInstance(SHA-256)。digest(MESSAGE);
签名签名人= Signature.getInstance(NONEwithRSA);
signer.initSign(pair.getPrivate());
signer.update(digest);
byte [] signed = signer.sign();
签名验证者= Signature.getInstance(SHA256withRSA);
verifier.initVerify(pair.getPublic());
verifier.update(MESSAGE);
verifier.verify(signed);
$ / code>
运行这个函数, verifier.verify()
方法抛出Signature异常:
java.security.SignatureException:签名编码错误
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:204)$ java.util.Signature中的
$ Delegate.engineVerify(Signature.java:1219)$ java.util.Signature.verify中的$ b $( Signature.java:652)
位于testing.rsaSignatureIntegrityTest(testing.java:38)
...
引起:java.io.IOException:序列标记错误
在太阳.security.util.DerInputStream.getSequence(DerInputStream.java:297)
at sun.security.rsa.RSASignature.decodeSignature(RSASignature.java:229)
at sun.security.rsa.RSASignature.engineVerify (RSASignature.java:195)
... 26 more
验证器对象似乎期望某种DER编码结构,它不是由signer对象产生的。
任何s uggestions如何让这个工作成功?
可疑的是,RSA签名是用一个包装摘要值生成的, OID。使用 bouncycastle 这可以很舒服地完成。
示例:
public void rsaSignatureIntegrityTest(){
KeyPairGenerator gen = KeyPairGenerator.getInstance(RSA);
gen.initialize(2048,new SecureRandom());
KeyPair pair = gen.generateKeyPair();
byte [] digest = MessageDigest.getInstance(SHA-256)。digest(MESSAGE);
签名签名人= Signature.getInstance(NONEwithRSA);
signer.initSign(pair.getPrivate());
signer.update(wrapForRsaSign(摘要,SHA-256));
byte [] signed = signer.sign();
System.out.println(Base64.getEncoder()。encodeToString(signed));
签名验证者= Signature.getInstance(SHA256withRSA);
verifier.initVerify(pair.getPublic());
verifier.update(MESSAGE);
verifier.verify(signed);
$ b private byte [] wrapForRsaSign(byte [] dig,String hashAlgo){
ASN1ObjectIdentifier oid = new DefaultDigestAlgorithmIdentifierFinder()。find(hashAlgo).getAlgorithm();
ASN1Sequence oidSeq = new DERSequence(new ASN1Encodable [] {oid,DERNull.INSTANCE});
ASN1Sequence seq = new DERSequence(new ASN1Encodable [] {oidSeq,new DEROctetString(dig)});
尝试{
return seq.getEncoded();
} catch(IOException e){
throw new DigestException(e);
}
}
Due to some implementation detail, I need to split hashing and signature generation. I tried to achieve this using the 'NONEwithRSA' signature algorithm.
This is a basic working example:
public void rsaSignatureIntegrityTest() {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048, new SecureRandom());
KeyPair pair = gen.generateKeyPair();
byte[] digest = MessageDigest.getInstance("SHA-256").digest(MESSAGE);
Signature signer = Signature.getInstance("NONEwithRSA");
signer.initSign(pair.getPrivate());
signer.update(digest);
byte[] signed = signer.sign();
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pair.getPublic());
verifier.update(MESSAGE);
verifier.verify(signed);
}
Running this, the verifier.verify()
method throws a Signature exception:
java.security.SignatureException: Signature encoding error
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:204)
at java.security.Signature$Delegate.engineVerify(Signature.java:1219)
at java.security.Signature.verify(Signature.java:652)
at testing.rsaSignatureIntegrityTest(testing.java:38)
...
Caused by: java.io.IOException: Sequence tag error
at sun.security.util.DerInputStream.getSequence(DerInputStream.java:297)
at sun.security.rsa.RSASignature.decodeSignature(RSASignature.java:229)
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:195)
... 26 more
The verifier object seems to expect some kind of DER encoded structure, which is not produced by the signer object.
Any suggestions on how to get this to work?
As suspected, RSA signatures are generated with a wrapped digest value, containing the hash oid. Using bouncycastle this can be done quite comfortably.
Example:
public void rsaSignatureIntegrityTest() {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048, new SecureRandom());
KeyPair pair = gen.generateKeyPair();
byte[] digest = MessageDigest.getInstance("SHA-256").digest(MESSAGE);
Signature signer = Signature.getInstance("NONEwithRSA");
signer.initSign(pair.getPrivate());
signer.update(wrapForRsaSign(digest, "SHA-256"));
byte[] signed = signer.sign();
System.out.println(Base64.getEncoder().encodeToString(signed));
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pair.getPublic());
verifier.update(MESSAGE);
verifier.verify(signed);
}
private byte[] wrapForRsaSign(byte[] dig, String hashAlgo) {
ASN1ObjectIdentifier oid = new DefaultDigestAlgorithmIdentifierFinder().find(hashAlgo).getAlgorithm();
ASN1Sequence oidSeq = new DERSequence(new ASN1Encodable[] { oid, DERNull.INSTANCE });
ASN1Sequence seq = new DERSequence(new ASN1Encodable[] { oidSeq, new DEROctetString(dig) });
try {
return seq.getEncoded();
} catch (IOException e) {
throw new DigestException(e);
}
}
这篇关于单独的摘要&使用java安全提供程序签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!