Search code examples
javarsasignature

How to make “MessageDigest SHA-256 and Signature RSASSA-PSS” equivalent to “Signature SHA256withRSA/PSS ”


I want to make SHA256withRSA/PSS signature in 2 steps, first i hash a message and then sign the digest with RSASSA-PSS

    byte[] document =   {0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1};
    MessageDigest digestor256 = MessageDigest.getInstance("SHA256", "BC");
    byte[] documentDigest256 = digestor256.digest(document);

    DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new faultDigestAlgorithmIdentifierFinder();
    AlgorithmIdentifier hashingAlgorithmIdentifier256 = hashAlgorithmFinder.find("SHA256");

    DigestInfo digestInfo2 = new DigestInfo(hashingAlgorithmIdentifier256, documentDigest256);
    Signature s2 = Signature.getInstance("NONEwithRSASSA-PSS", "BC");
    MGF1ParameterSpec mgfParam = new MGF1ParameterSpec("SHA256");
    PSSParameterSpec pssParam = new PSSParameterSpec("SHA256", "MGF1", mgfParam, 32, 1);
    s.setParameter(pssParam);
    s.initSign(keyPair.getPrivate());
    s.update(digestInfo2.getEncoded());
    byte[] signature = s.sign();

But i use SHA256withRSA/PSS can't verify

    Signature ver = Signature.getInstance("SHA256withRSA/PSS", "BC");
    ver.setParameter(pssParam);
    ver.initVerify(keyPair.getPublic());
    ver.update(document);
    boolean re = ver.verify(signature);

I need some help to make it, thank you for your help.


Solution

  • Don't do the DigestInfo. RSASSA-PKCS1v1_5 signatures use the step of encoding the hash in an ASN.1 DER DigestInfo, but RSASSA-PSS signatures do not; see RFC 3447 or 8017. Also you don't need to specify the parameters on the version using the combined algorithm, because the defaults are already correct, although it doesn't hurt to do so redundantly. Example modified to use my keypair, and output to console:

        KeyStore ks = KeyStore.getInstance("jks"); ks.load(new FileInputStream(args[0]), args[1].toCharArray());
        PrivateKey prv = (PrivateKey)ks.getKey(args[2], args[1].toCharArray()); 
        PublicKey pub = ks.getCertificate(args[2]).getPublicKey();
    
        byte[] document =   {0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1};
        MessageDigest digestor256 = MessageDigest.getInstance("SHA256", "BC");
        byte[] documentDigest256 = digestor256.digest(document);
    
        Signature s2 = Signature.getInstance("NONEwithRSASSA-PSS", "BC");
        MGF1ParameterSpec mgfParam = new MGF1ParameterSpec("SHA256");
        PSSParameterSpec pssParam = new PSSParameterSpec("SHA256", "MGF1", mgfParam, 32, 1);
        s2.setParameter(pssParam);
        s2.initSign(prv);
        s2.update(documentDigest256);
        byte[] signature = s2.sign();
    
        Signature ver = Signature.getInstance("SHA256withRSA/PSS", "BC");
        if(false){ ver.setParameter(pssParam); } // can enable if desired
        ver.initVerify(pub);
        ver.update(document);
        System.out.println( ver.verify(signature) );
    

    Also, trivially, you had misspelled DefaultDigestAlgorithmIdentifierFinder and used s2 vs s for the variable name.