Search code examples
phprsabouncycastlepublic-key-encryptionphpseclib

Encryption PHP, Decryption Java


I have a web-service in php that generates a keypair to encrypt a message, and one application in java that retrives the privatekey and decrypt the message.

For php I'm using http://phpseclib.sourceforge.net/ and have this two files:

keypair.php

<?php

set_time_limit(0);
if( file_exists('private.key') )
{
    echo file_get_contents('private.key');
}
else
{
    include('Crypt/RSA.php');
    $rsa = new Crypt_RSA();
    $rsa->createKey();
    $res = $rsa->createKey();

    $privateKey = $res['privatekey'];
    $publicKey  = $res['publickey'];

    file_put_contents('public.key', $publicKey);
    file_put_contents('private.key', $privateKey);
}

?>

encrypt.php

<?php

include('Crypt/RSA.php');

//header("Content-type: text/plain");

set_time_limit(0);
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->loadKey(file_get_contents('public.key')); // public key

$plaintext = 'Hello World!';
$ciphertext = $rsa->encrypt($plaintext);

echo base64_encode($ciphertext);

?>

and in java I have this code:

package com.example.app;

import java.io.DataInputStream;
import java.net.URL;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;

public class MainClass {

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        try {
            BASE64Decoder decoder   = new BASE64Decoder();
            String b64PrivateKey    = getContents("http://localhost/api/keypair.php").trim();
            String b64EncryptedStr  = getContents("http://localhost/api/encrypt.php").trim();

            System.out.println("PrivateKey (b64): " + b64PrivateKey);
            System.out.println(" Encrypted (b64): " + b64EncryptedStr);

            SecretKeySpec privateKey    = new SecretKeySpec( decoder.decodeBuffer(b64PrivateKey) , "AES");
            Cipher cipher               = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            byte[] plainText            = decoder.decodeBuffer(b64EncryptedStr);

            System.out.println("         Message: " + plainText);
        }
        catch( Exception e )
        {
            System.out.println("           Error: " + e.getMessage());
        }

    }

    public static String getContents(String url)
    {
        try {
            String result = "";
            String line;
            URL u = new URL(url);
            DataInputStream theHTML = new DataInputStream(u.openStream());
            while ((line = theHTML.readLine()) != null)
                result = result + "\n" + line;

            return result;
        }
        catch(Exception e){}

        return "";
    }
}

My questions are:

  1. Why I'm having a exception saying "not an RSA key!"?
  2. How can I improve this code? I have used base64 to avoid encoding and comunication errors between Java and PHP.
  3. This concept is correct? I mean, I'm using it correctly?

Solution

  • With the help of above answer, I got that SecretKeySpec is used wrong, and I found that PEM file from OpenSSL isn't a 'standart format', so I need to use the PEMReader to convert it to PrivateKey class.

    Here is my working class:

    package com.example.app;
    
    import java.io.BufferedReader;
    import java.io.DataInputStream;
    import java.io.StringReader;
    import java.net.URL;
    import java.security.KeyPair;
    import java.security.PrivateKey;
    import java.security.Security;
    
    import javax.crypto.Cipher;
    
    import org.bouncycastle.openssl.PEMReader;
    
    import sun.misc.BASE64Decoder;
    
    public class MainClass {
    
        /**
         * @param args
         */
        public static void main(String[] args)
        {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    
            try {
                BASE64Decoder decoder   = new BASE64Decoder();
                String b64PrivateKey    = getContents("http://localhost/api/keypair.php").trim();
                String b64EncryptedStr  = getContents("http://localhost/api/encrypt.php").trim();
    
                System.out.println("PrivateKey (b64): " + b64PrivateKey);
                System.out.println(" Encrypted (b64): " + b64EncryptedStr);
    
                byte[] decodedKey           = decoder.decodeBuffer(b64PrivateKey);
                byte[] decodedStr           = decoder.decodeBuffer(b64EncryptedStr);
                PrivateKey privateKey       = strToPrivateKey(new String(decodedKey));
    
                Cipher cipher               = Cipher.getInstance("RSA/None/OAEPWithSHA1AndMGF1Padding", "BC");
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
    
    
                byte[] plainText            = cipher.doFinal(decodedStr);
    
                System.out.println("         Message: " + new String(plainText));
            }
            catch( Exception e )
            {
                System.out.println("           Error: " + e.getMessage());
            }
    
        }
    
        public static String getContents(String url)
        {
            try {
                String result = "";
                String line;
                URL u = new URL(url);
                DataInputStream theHTML = new DataInputStream(u.openStream());
                while ((line = theHTML.readLine()) != null)
                    result = result + "\n" + line;
    
                return result;
            }
            catch(Exception e){}
    
            return "";
        }
    
        public static PrivateKey strToPrivateKey(String s)
        {
            try {
                BufferedReader br   = new BufferedReader( new StringReader(s) );
                PEMReader pr        = new PEMReader(br);
                KeyPair kp          = (KeyPair)pr.readObject();
                pr.close();
                return kp.getPrivate();
            }
            catch( Exception e )
            {
    
            }
    
            return null;
        }
    }
    

    Here is my keypair.php

    <?php
    
    set_time_limit(0);
    if( file_exists('private.key') )
    {
        echo base64_encode(file_get_contents('private.key'));
    }
    else
    {
        include('Crypt/RSA.php');
    
        $rsa = new Crypt_RSA();
        $rsa->setHash('sha1');
        $rsa->setMGFHash('sha1');
        $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
        $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
        $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
    
        $res = $rsa->createKey(1024);
    
        $privateKey = $res['privatekey'];
        $publicKey  = $res['publickey'];
    
        file_put_contents('public.key', $publicKey);
        file_put_contents('private.key', $privateKey);
    
        echo base64_encode($privateKey);
    }
    
    ?>
    

    and my encrypt.php

    <?php
        include('Crypt/RSA.php');
        set_time_limit(0);
    
        $rsa = new Crypt_RSA();
        $rsa->setHash('sha1');
        $rsa->setMGFHash('sha1');
        $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
    
        $rsa->loadKey(file_get_contents('public.key')); // public key
    
        $plaintext  = 'Hello World!';
        $ciphertext = $rsa->encrypt($plaintext);
        $md5        = md5($ciphertext);
        file_put_contents('md5.txt', $md5);
        file_put_contents('encrypted.txt', base64_encode($ciphertext));
    
        echo base64_encode($ciphertext);
    
    ?>
    

    I hope it helps anyone and thanks.