单独的摘要&使用java安全提供程序签名

时间:2017-04-19 08:18:25

标签: java hash cryptography rsa digital-signature

由于一些实现细节,我需要拆分散列和签名生成。我尝试使用'NONEwithRSA'签名算法实现这一目标。

这是一个基本的工作示例:

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);
}

运行它,verifier.verify()方法抛出一个Signature异常:

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

验证者对象似乎期望某种DER编码结构,它不是由签名者对象产生的。

有关如何使其发挥作用的任何建议吗?

1 个答案:

答案 0 :(得分:3)

如所怀疑的,RSA签名是使用包含的摘要值生成的,其中包含hash 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 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);
    }
}