2012-06-20 124 views
7

對於我當前的項目,我必須將簽名從PHP發送到Java應用程序。我正在使用Crypt/RSA來簽署我的數據。SHA256withRSA來自PHP的簽名驗證來自JAVA

爲了測試我剛剛簽署的「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編碼或字節流的東西,但我暫時失去了它。

任何幫助,將不勝感激。

+0

它看起來像你用公鑰簽名,然後用公鑰進行驗證。您需要使用私鑰進行驗證。 – Polynomial

+0

謝謝@Polynomial但長字符串是我的私鑰1024字節。 – LostMohican

+2

請告訴我你沒有發佈你的*實際*私人密鑰在StackOverflow ... – Polynomial

回答

5

我使用OpenSSL的像發白已經提到。這是我的條紋示例。請注意任何字符編碼,行結尾等。這會導致文本數據的二進制表示形式發生變化。

PHP-RSA_SHA256-星座:

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

?> 

BASE64的編碼的二進制簽名的輸出是:

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

謝謝@Sascha你救了我的一天:)。你知道你不能在php自己的手冊中看到SHA256嗎? http://us3.php.net/manual/en/openssl.signature-algos.php – LostMohican

+1

今天,你已經可以;) –

1

我認爲你需要改進你的PHP解決方案。 據http://php.net/manual/en/function.openssl-get-md-methods.php你可以從PHP直接[47] => sha256WithRSAEncryption使用,可能是由命令行調用OpenSSL的也有可能:

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

感謝@Whity,但我找不到任何方法將密鑰插入到摘要方法中:/ – LostMohican

+0

檢查http://stackoverflow.com/questions/10524198/what-version-of-openssl-is-needed-to-sign -with-sha256withrsaencryption –

3

默認情況下,phpseclib使用更安全的PSS填充。 Java可能使用PKCS#1填充。所以,如果你是去phpseclib路線(我建議你這樣做)......這樣做:

$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 
+0

我不知道爲什麼,但每次我嘗試時phpseclib的標誌結果都改變了! – LostMohican

+0

當簽名模式設置爲CRYPT_RSA_SIGNATURE_PKCS1時,它們適合我。使用默認的簽名模式,它們不匹配,但這是因爲該模式會進行隨機填充。 – 2012-06-21 01:15:48