SHA256withRSA签名来自PHP验证来自JAVA

SHA256withRSA签名来自PHP验证来自JAVA,java,php,cryptography,Java,Php,Cryptography,对于我当前的项目,我必须将签名从PHP发送到Java应用程序。我现在正在使用Crypt/RSA对数据进行签名 对于测试,我只在“abc”上签名,代码如下: $rsa = new Crypt_RSA(); $plaintext = 'abc'; $rsa->loadKey("MIICXgIBAAKBgQDjh+hNsqJe566JO0Sg7Iq5H1AdkauACdd8QMLp9YNY0HPslVH0 rXaOFo0zgH0Ktu/Ku3lS1lfxbFQAY8b6ywZKvu4e

对于我当前的项目,我必须将签名从PHP发送到Java应用程序。我现在正在使用Crypt/RSA对数据进行签名

对于测试,我只在“abc”上签名,代码如下:

$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);
我可以从php代码中验证签名。但是当涉及到从JAVA验证时,我并没有成功。以下是执行验证操作的java代码:

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

    }
我不认为这是因为键,我已经可以从PHP验证它,正如我之前所说的。关于PHP编码或字节流,我错过了一些东西,但我现在迷路了


任何帮助都将不胜感激。

我认为您需要改进您的PHP解决方案。 根据您可以直接使用[47]=>SHA256WithRSA从PHP加密,可能从命令行调用openssl也是可能的:

openssl dgst -sha256 -sign my.key -out in.txt.sha256 in.txt 

我正在使用像Whity已经提到的openssl。这是我的分条示例。请注意任何字符编码、行尾等。这会导致文本数据的二进制表示形式发生变化

PHP-RSA\u-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) ."\n");

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

默认情况下,phpseclib使用更安全的PSS填充。Java可能正在使用PKCS#1填充。因此,如果您选择phpseclib路线(我建议您这样做)。。。这样做:

$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);

看起来您正在使用公钥对其进行签名,然后使用公钥对其进行验证。你需要用私钥来验证它。谢谢@polyman,但那长字符串是我的私钥1024字节。请告诉我你没有在StackOverflow上发布你的实际私钥…:D ahahah这只是我用opensslthanks@Whity生成的一个测试密钥,但我找不到任何方法将密钥插入摘要方法:/Check谢谢@Sascha你救了我一天:)。你知道你不能在php自己的手册中看到SHA256吗?救了我的命。!我不知道为什么,但每次我尝试时,phpseclib的符号结果都会改变!当签名模式设置为CRYPT_RSA_signature_PKCS1时,它们对我来说很匹配。使用默认签名模式时,它们不匹配,但这是因为该模式没有随机填充。