Como RSA verificar uma assinatura em java que foi gerada em php

Estamos usando o phpseclib para assinatura de dados de chave pública e o java android é usado para verificação de chave pública. Mas falhou repetidamente.

Código PHP Para gerar chaves e assinar por chave privada

 include_once("phpseclib/autoload.php");

 function getKeys($keysize=2048){

        $rsa = new Crypt_RSA();
        //$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
        //$rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
        $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
        $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
        $d = $rsa->createKey($keysize);
        return array("publickey"=>$d['publickey'], "privatekey"=>$d['privatekey']);

    }

    function encryptdata($message, $encryptionKey){

        $rsa = new Crypt_RSA();
        //$rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
        $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
        $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);

        //$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
        $rsa->loadKey($encryptionKey); // public key
        return $rsa->encrypt($message);
    } 

    function decryptdata($message, $decryptionKey){

        $rsa = new Crypt_RSA();
//        $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
//        $rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
        $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
        $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);

        $rsa->loadKey($decryptionKey); // private key
        return $rsa->decrypt($message);

    }    

    $keys = getKeys();
    file_put_contents("key.pub", $keys["publickey"]);
    file_put_contents("key.priv", $keys["privatekey"]);

    $publickey = file_get_contents("key.pub");
    $privatekey = file_get_contents("key.priv");

    //print_r($keys);
    $string = "Hi I m here";
    $hash = hash("sha256", $string);

    $encdata = encryptdata($hash, $privatekey);
    echo $base_encdata  = base64_encode($encdata);

Código JAVA

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.lang.String;
class PubCheck {
    public static boolean verify(String message, String signature, PublicKey publicKey) throws SignatureException{
    try {
        Signature sign = Signature.getInstance("SHA1withRSA");
        sign.initVerify(publicKey);
        sign.update(message.getBytes("UTF-8"));
        return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
    } catch (Exception ex) {
        throw new SignatureException(ex);
    }
    }

    public static void main(String[] args) 
    throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, SignatureException 
    {
    String plainData = "Hi I m here";
    String pkey = "MIIBCgKCAQEA2tF2g/muNw9xKTVcIkjUMvMhygtIW49yo1PgbwqDQ/w9MSfEARtYYF6Tenfz0twaR/eI14GXmlIffflORe4eaSuMBhwQFOIKU/1+v1BV3RLqGGblvHTVaMVm49AGiqxNnh1LBbcSrC5UhMqlL/HGiku0oYsbjLzwcLc5ac6aBQVD60wWGNm1g26lRQGRbCLqxVfcWKT3AMvEQK3cEx/En7/5Vg1V8xnJraNMrO8UGnaX8LLJFzYJiSCEShh7F+pMHbf4MaBekw7Aaf5hPJtczNsR137R92Be3OP4idI5NLmTV+Pi1DWlxhjEhswKH88SP+gsW31gS7B/ddECUqewQwIDAQAB";

    String data = "aP0nuYYA1hE5odsCkR/DcdRbBvO2Z8IOlqXf/bKZJiG8HELIop90Vno1dKC1qyHEAOXy0gtH7GtJamzoBjDZmHPT6eto9EZP/xE7xZ8L05kjp0z2thLqO7on4C6DrG++TK1j+E3T7V0UeU874WIB0AEVzu1XUKFW6aeuU67a/gdn8N2n7N/WXtlyNSVZXg8f4PeUhGvFJrhINZT7BuMMZj1gZs4wMJPAICwfvVeg02RPH0N3Ybf2iVgRuZlmtQXGTyBlCxe9ybdHzuQM6nXghpLNmaOzCypb+yVs3Da7E0b3/fKQ7JqPSquWex2ERZbIMSTC6oCzc1rOF6iKVAd92Q==";

    byte[] encodedPublicKey = pkey.getBytes( "utf-8" );
    //System.out.println(new String(encodedPublicKey, "UTF-8") + "\n");

    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( encodedPublicKey );
    //PKCS8EncodedKeySpec publicKeySpec = new PKCS8EncodedKeySpec(encodedPublicKey);

    KeyFactory keyFactory = KeyFactory.getInstance( "RSA" );

    PublicKey publicKey = keyFactory.generatePublic( publicKeySpec );

    boolean retvar = verify(plainData, data, publicKey);

    // 3 - verifying content with signature and content :
    /*Signature sig = Signature.getInstance( "SHA256withRSA" );
    sig.initVerify( publicKey );
    sig.update( data.getBytes( ) );
    ret = sig.verify( sign.getBytes( ) );*/

    //byte[] decoded = Base64.decodeBase64(data);
    }
}

Eu compilei o código java por

javac -cp commons-codec-1.10.jar:. PubCheck.java
java -cp commons-codec-1.10.jar:. PubCheck

Em seguida, encontrou a seguinte exceção

Exception in thread "main"   java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at PubCheck.main(PubCheck.java:67)
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.x509.X509Key.decode(X509Key.java:387)
at sun.security.x509.X509Key.decode(X509Key.java:403)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:83)
at  sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
... 2 more

Disclaimer: Eu tenho zero conhecimento sobre java. todo o código que eu tento encontrado da net.

ATUALIZAÇÃO: problema finalmente resolvido e o código java capaz de verificar com a ajuda de Maarten Bodewes. O código que ele forneceu funciona com uma alteração. Preciso passar o PKCS1 do phpseclib. Então mudei

Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");

para

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

O código PHP precisa de alterações para usar o sinal em vez de criptografar / hash manualmente.

function getKeys($keysize=2048){

    $rsa = new Crypt_RSA();
    $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
    $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
    $d = $rsa->createKey($keysize);
    return array("publickey"=>$d['publickey'], "privatekey"=>$d['privatekey']);

}


$string = "Hi I m here";
/*
$keys = getKeys();
file_put_contents("key1.pub", $keys["publickey"]);
file_put_contents("key1.priv", $keys["privatekey"]);
die;*/

$publickey = file_get_contents("key1.pub");
$privatekey = file_get_contents("key1.priv");

$hash = new Crypt_Hash('sha256');
$rsa = new Crypt_RSA();    
$rsa->loadKey($privatekey);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');

$signature = $rsa->sign($string);
echo base64_encode($signature);

questionAnswers(2)

yourAnswerToTheQuestion