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?
For compatibility with the PHP code, in the Java code:
IvParameterSpec
(or if no user-defined IV is applied, the automatically generated IV must be retrieved with cipher.getIV()
, as this is required for decryption).In addition, for security reasons:
getBytes()
. Otherwise, a platform-dependent default encoding is used (at least in earlier Java versions).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
)
*/
?>