javaphpencryptionaes

Encrypt a string with Java for decryption using PHP


I am writing a program using Java 1.6 that should generate a message of the format:

"Your invoice #123 for 100.00 is at https://my.site.com/documents/invoice?p=xxxxxxxxxxx"

with xxxxx containing an encrypted JSON string. The website at my.site.com runs PHP. It would open the URL with the invoice info:

<?php
$cipher = "AES-128-CTR";
$encryption_iv = "1234567891011121";
$encryption_key = "MyPassword";
$encryption_options = 0;
$enrypted_parm = urldecode( $this->input->get('p') );
$iv_length = openssl_cipher_iv_length( $cipher );
$decrypted_parm = openssl_decrypt( $enrypted_parm, $cipher, $encryption_key, $encryption_options, $encryption_iv );
$parms = json_decode($decrypted_parm);

echo "id=" . $parms->id . "&db=" . $parms->db . "&archived=" . $parms->archived;
?>

To generate the message from Java, I have tried this:

encryption_key = "MyPassword";
JsonObject joParms = new JsonObject();
joParms.addProperty("id", invoiceId);
joParms.addProperty("db", db);
joParms.addProperty("archived", isArchive);

SecretKeySpec secretKeySpec = new SecretKeySpec(encryption_key.concat("           ").substring(0,16).getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteEncryptedString = cipher.doFinal(joParms.toString().getBytes());
String encodedString = Base64.encodeBase64String(byteEncryptedString);

String message = messageTemplate.replace("{INVNO}", invNo).replace("{AMOUNT}", amount).concat(" ").concat(siteUrl).concat("?p=").concat(encodedString);

The encrypted string generated thus does not get decrypted by PHP. I think the two don't quite match in specs. Can someone help?


Solution

  • For compatibility with the PHP code, in the Java code:

    In addition, for security reasons:

    Sample code for Java 1.6:

    import java.net.URLEncoder;
    import java.util.Arrays;
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import org.apache.commons.codec.binary.Base64;
    
    ...
    
    String encryption_key = "MyPa§sword";
    String iv = "1234567891011121"; 
    String plaintext = "{\"key1\":\"value1\",\"key2\":\"value2\"}"; // some JSON string
    String utf8 = "UTF8";
    
    SecretKeySpec secretKeySpec = new SecretKeySpec(Arrays.copyOf(encryption_key.getBytes(utf8), 16), "AES"); // pad/truncate key 
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); // specify mode and padding 
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv.getBytes(utf8))); // specify IV
    byte[] byteEncryptedString = cipher.doFinal(plaintext.getBytes(utf8));
    String encodedString = URLEncoder.encode(Base64.encodeBase64String(byteEncryptedString), utf8); // add Url encoding
    
    System.out.println(encodedString); // JxTY7z6mhpSTP46W0bkoJ%2BfDes0%2Fts7HWK5BBlwjTLZH
    

    which can be decrypted with the following PHP code:

    <?php
    $ciphertext = "JxTY7z6mhpSTP46W0bkoJ%2BfDes0%2Fts7HWK5BBlwjTLZH";
    $cipher = "AES-128-CTR";
    $encryption_iv = "1234567891011121";
    $encryption_key = "MyPa§sword";
    $encryption_options = 0;
    $enrypted_parm = urldecode($ciphertext);
    $iv_length = openssl_cipher_iv_length( $cipher );
    $decrypted_parm = openssl_decrypt( $enrypted_parm, $cipher, $encryption_key, $encryption_options, $encryption_iv );
    $parms = json_decode($decrypted_parm);
    print_r($parms); /* stdClass Object
                        (
                            [key1] => value1
                            [key2] => value2
                        )
                     */
    ?>