2012-06-20 10 views
7

Para mi proyecto actual tengo que enviar una firma de PHP a la aplicación de Java. Estoy usando Crypt/RSA ahora mismo para firmar mis datos.SHA256withRSA firmar de PHP verificar de JAVA

Para la prueba estoy firmando simplemente "abc" con el siguiente código:

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

que puede verificar la firma de código php. Pero cuando se trata de verificar desde JAVA, no tuve éxito. Aquí está el código de Java que realiza la operación de verificación:

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

    } 

no creo que es a causa de llaves, ya puedo verificarlo desde PHP como le dije antes. Hay algo que echo de menos sobre la codificación PHP o las secuencias de bytes, pero estoy perdido por el momento.

Cualquier ayuda sería apreciada.

+0

Parece que está firmando con la clave pública, y luego verificar con la clave pública. Debe verificarlo con la clave privada. – Polynomial

+0

gracias @Polynomial pero esa cadena larga es mi clave privada de 1024 bytes. – LostMohican

+2

Por favor, dime que no has publicado tu clave privada * actual * en StackOverflow ... – Polynomial

Respuesta

5

estoy usando openssl como Whity ya se ha mencionado. Aquí está mi ejemplo a rayas. Tenga en cuenta cualquier codificación de caracteres, final de línea, etc. Esto da como resultado una representación binaria modificada de sus datos de texto.

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

?> 

La salida de base64 codificado firma binaria es:

OnqiWnFQ2nAjOa1S57Du9jDpVr4Wp2nLdMk2FX +/+ Qx1 SAHpVsW1JvQYqQUDlxvbTOE9vg6dlU6i3omR7KipLw ==

Java- RSA_SHA256-Verificació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); 
    } 
} 
+0

Gracias @Sascha me salvaste el día :). ¿Sabes que no puedes ver SHA256 en los propios manuales de php? http://us3.php.net/manual/en/openssl.signature-algos.php – LostMohican

+1

Hoy en día, ya puedes;) –

1

Creo que necesita mejorar su solución de PHP. Según http://php.net/manual/en/function.openssl-get-md-methods.php puede utilizar directamente [47] => sha256WithRSAEncryption desde PHP, probablemente llamar openssl de comandos también será posible:

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

gracias @Whity pero no pude encontrar ninguna forma de insertar una clave para el método de resumen:/ – LostMohican

+0

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

3

phpseclib usa el relleno de PSS más seguro de forma predeterminada. Java probablemente esté utilizando el relleno PKCS # 1. Así que si usted fuera a ir a la ruta phpseclib (que recomiendo hacer) ... hacer esto:

$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 
+0

¡No sé por qué, pero el resultado del signo de phpseclib cambió cada vez que lo intenté! – LostMohican

+0

Coinciden bien conmigo cuando el modo de firma se establece en CRYPT_RSA_SIGNATURE_PKCS1. Al usar el modo de firma predeterminado no coinciden, pero eso se debe a que ese modo tiene relleno aleatorio. –

Cuestiones relacionadas