dongshi4773
dongshi4773
2012-06-20 09:03

来自JAVA的PHP验证SHA256withRSA签名

已采纳

For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.

For test I am signing just "abc" with following code :

$rsa = new Crypt_RSA();
$plaintext = 'abc';

    $rsa->loadKey("MIICXgIBAAKBgQDjh+hNsqJe566JO0Sg7Iq5H1AdkauACdd8QMLp9YNY0HPslVH0
rXaOFo0zgH0Ktu/Ku3lS1lfxbFQAY8b6ywZKvu4eoxlnEwuBwy09CG+3ZiVLBjCj
TZHA/KOkpVLa+tA6KsoP6zv/xI/ACkSCxPGR0q3SiRuhXV/6tacoKxUYnwIDAQAB
AoGBAIC00GOjONYWmFRoglnFdHNjkx4m2KyE5LAUsi1GBBapU+nwTXvq47VcbGNF
u3XkJaC4i9igBv86GApgZp5XWia86On/Lz9NR4fB2EFP6Ydy84GfCDNNvkism4BR
aA+eYdNiQ3Wfyi98ZpUi+rPsoI6Cid4eSkCC4poTUaqzMkiBAkEA9Gn1oIlUEoVI
q/u5Y9vflXRDt95AA9AokJkQj7XTNjsz8ypU8TO6D6ZykpcbK6zjU0UJsQiC3dKj
AgmAR2VzYwJBAO5RETMAyDnR+5g+MtHpwGqGdY4dq0j4y4CsdtOYKWwSTh3VQy+C
eghJoyPRfIpulw2Mk/l+occEI0ohJl0+UJUCQQDSZtjVLwMZwnUx4EvSw/ewL9sP
0Jpo7evNtoaEQDEncUWiYeGnljDowg/FU6FHMtiq2TajmMEXdflvioBMdfAjAkEA
3TB60SbJr/i4Fo6sJm5ZO8W+eAALiTf50VzBERTqZTb8L+5PZFoqn2SROV5mxClu
o5G1idzBlHC/vD7WV7bNnQJAd0FrxaMBurJ4Uv/B8TDP+eeBdB7d9rKw0+TVlcel
cbpIz6BIP6+nmsgy6dbDRnx0eC/MgF2EU0wrCu1DK0PyWA==");
    $rsa->setHash("sha256");
    $signature = $rsa->sign($plaintext);

$signature_encoding = mb_convert_encoding($signature, "UTF-8");
    error_log("signature encoded in UTF-8 :" . $signature_encoding);

    $encoded_sign = base64_encode($signature_encoding);
    error_log("encoded sign for abc: " . $encoded_sign);

I can verify the signature from php code. But when it comes to verifying from JAVA, i was not successfull. Here is the java code that does the verify operation :

public boolean verify(String signed, String data, PubKey pubKey) throws Exception{

    PublicKey publicKey = jceProvider.generateRSAPublicKeyFromX509(
            base64.decode(pubKey.getEncodedKey())
    );

    byte[] signature = base64.decode(signed);
    byte[] verifier = data.getBytes(Charset.forName("UTF-8"));

    return jceProvider.verify(signature, verifier, publicKey);

}

public class JCEProvider {

    public boolean verify (byte[] signature, byte[] verifier, PublicKey publicKey) throws Exception{

        Signature rsaSignature = Signature.getInstance("SHA256withRSA");

        rsaSignature.initVerify(publicKey);
        rsaSignature.update(verifier);

        return rsaSignature.verify(signature);

    }

I dont think it is because of keys, I can already verify it from PHP as I told before. There is something that I miss about PHP encoding or byte streams but I am lost for the moment.

Any help would be appreciated.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

3条回答

  • duanmeng1858 duanmeng1858 9年前

    I'm using openssl like Whity already mentioned. Here is my striped down example. Be aware of any character encoding, line ending, etc. This results in changed binary representation of your text data.

    PHP-RSA_SHA256-Sign:

    <?php
    
    $data = "For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.";
    
    $private_key = <<<EOD
    -----BEGIN RSA PRIVATE KEY-----
    MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
    RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
    sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
    6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
    h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
    Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
    I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
    -----END RSA PRIVATE KEY-----
    EOD;
    
    $binary_signature = "";
    
    $algo = "SHA256";
    openssl_sign($data, $binary_signature, $private_key, $algo);
    print(base64_encode($binary_signature) ."
    ");
    
    ?>
    

    The output of base64 encoded binary signature is:

    OnqiWnFQ2nAjOa1S57Du9jDpVr4Wp2nLdMk2FX+/qX1+SAHpVsW1JvQYqQUDlxvbTOE9vg6dlU6i3omR7KipLw==

    JAVA-RSA_SHA256-Verify:

    import java.security.GeneralSecurityException;
    import java.security.KeyFactory;
    import java.security.PublicKey;
    import java.security.Signature;
    import java.security.spec.X509EncodedKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    public class RsaVerify {
    
        public static void main(String args[]){
            String publicKey = 
    //              "-----BEGIN PUBLIC KEY-----"+
                    "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6"+
                    "zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==";
    //              "-----END PUBLIC KEY-----";
    
            byte[] data = "For my current project I have to send a signature from PHP to Java application. I am using Crypt/RSA right now for signing my data.".getBytes();
            byte[] signature = Base64.decodeBase64("OnqiWnFQ2nAjOa1S57Du9jDpVr4Wp2nLdMk2FX+/qX1+SAHpVsW1JvQYqQUDlxvbTOE9vg6dlU6i3omR7KipLw==");
    
            try {
                System.out.println(verify(data, signature, publicKey));
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }
    
        }
    
        private static boolean verify(byte[] data, byte[] signature, String publicKey) throws GeneralSecurityException{
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
            Signature sig = Signature.getInstance("SHA256withRSA");
            sig.initVerify(pubKey);
            sig.update(data);
            return sig.verify(signature);
        }
    }
    
    点赞 评论 复制链接分享
  • drhdjp97757 drhdjp97757 9年前

    phpseclib uses the more secure PSS padding by default. Java is probably using PKCS#1 padding. So if you were to go the phpseclib route (which I'd recommend doing)... do this:

    $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
    
    点赞 评论 复制链接分享
  • dpzjl68484 dpzjl68484 9年前

    I think u need to improve your PHP solution. According to http://php.net/manual/en/function.openssl-get-md-methods.php you can use directly [47] => sha256WithRSAEncryption from PHP, probably call openssl from commandline also be possible:

    openssl dgst -sha256 -sign my.key -out in.txt.sha256 in.txt 
    
    点赞 评论 复制链接分享

为你推荐