0
<?php
    # --- ENCRYPTION ---

    # the key should be random binary, use scrypt, bcrypt or PBKDF2 to
    # convert a string into a key
    # key is specified using hexadecimal

    $length = 16;
    $key = openssl_random_pseudo_bytes($length);
    // echo $key;

    // $key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
    echo $key."<br/>";

    echo "<br/>";
    # show key size use either 16, 24 or 32 byte keys for AES-128, 192
    # and 256 respectively
    $key_size =  strlen($key);
    echo "Key size: " . $key_size;
    echo "<br/>";

    $plaintext = "This string was AES-256 / CBC / ZeroBytePadding encrypted.";

    # create a random IV to use with CBC encoding
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    # creates a cipher text compatible with AES (Rijndael block size = 128)
    # to keep the text confidential 
    # only suitable for encoded input that never ends with value 00h
    # (because of default zero padding)
    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
                                 $plaintext, MCRYPT_MODE_CBC, $iv);

    # prepend the IV for it to be available for decryption
    $ciphertext = $iv . $ciphertext;

    # encode the resulting cipher text so it can be represented by a string
    $ciphertext_base64 = base64_encode($ciphertext);

    echo  "ENCRYPTED DATA =". $ciphertext_base64;
    echo "<br/>";

    # === WARNING ===

    # Resulting cipher text has no integrity or authenticity added
    # and is not protected against padding oracle attacks.

    # --- DECRYPTION ---

    $ciphertext_dec = base64_decode($ciphertext_base64);

    # retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
    $iv_dec = substr($ciphertext_dec, 0, $iv_size);

    # retrieves the cipher text (everything except the $iv_size in the front)
    $ciphertext_dec = substr($ciphertext_dec, $iv_size);

    # may remove 00h valued characters from end of plain text
    $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,
                                    $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

    echo  "DECRYPTED TEXT = ".$plaintext_dec;
?>

JAVA :-

public static String decryptWithIV(byte[] key, String encrypted)
        throws GeneralSecurityException {

    if (key.length != 16) {
        throw new IllegalArgumentException("Invalid key size.");
    }
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
            new byte[16]));
    byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted
            .getBytes()));

    return new String(original);
}

When I run the PHP code I get below 2 details which I copied to my java code.

public static final String KEY = "œ8[,#BÌüïmÕe-<Æ   1^Ž—½R™t3§¡ÚI";
    public static final String ENCRYPTED_DATA = "ASfLnSMyfp9vHN2UTO4TRilUIRywzVfJfrfkrp4gPsP0+lENwEHJ3/YzstfuIESgVFfpkxHGTxuiO+aWZObG5aPoZfrcoIDQLVXeRiysA4s=";

The issue is my key already in byte (When run on localhost), but in my java code its again trying to convert it into byte. I would like to know How can I initialize byte array as I have the key with me from localhost as of now.

3
  • You use CBC mode in PHP but ECB in Java as well as different padding. Commented Apr 13, 2015 at 10:25
  • @ArtjomB. Sorry for all caps, I just wanted my comments to readable. Commented Apr 13, 2015 at 10:27
  • @AlexK. I am new in Security, can you please guide me in right direction to resolve this. Commented Apr 13, 2015 at 10:28

1 Answer 1

2

There are some problems with your code.

  • Your key in Java is only 31 characters long and not 32. Bytes cannot be always represented as a string, because there are sometimes non-prinable characters. You can print your key as hex with bin2hex() or as base64 with base64_encode() and reverse the process in Java like this (hex) or with Base64.decodeBase64().
  • Use the same mode of operation and padding like in PHP. That is use "AES/CBC/NoPadding". Since PHP uses ZeroPadding, you will then need to remove the zero bytes at the end after decryption.
  • The IV is prepended to the ciphertext in PHP, but you don't slice the IV off in Java. Also, you provide a zero byte IV.
public static String decryptWithIV(byte[] key, String encrypted)
        throws GeneralSecurityException {
    if (key.length != 16) {
        throw new IllegalArgumentException("Invalid key size.");
    }

    byte[] ciphertextBytes = Base64.decodeBase64(encrypted.getBytes());
    IvParameterSpec iv = new IvParameterSpec(ciphertextBytes, 0, 16);
    ciphertextBytes = Arrays.copyOfRange(ciphertextBytes, 16,
            ciphertextBytes.length);

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
    byte[] original = cipher.doFinal(ciphertextBytes);

    // remove zero bytes at the end
    int lastLength = original.length;
    for (int i = original.length - 1; i > original.length - 16; i--) {
        if (original[i] == (byte) 0) {
            lastLength--;
        } else {
            break;
        }
    }

    return new String(original, 0, lastLength);
}
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for the response, but my KEY is already in byte. The issue is currently I am working on local server, where first I run the PHP code and get the symmetric key and encrypted data. From there I copy and paste both in java strings. I think the problem is my KEY is already in byte as I am using openssl_random_pseudo_bytes PHP function which returns random bytes.
Yes, you should encode it first into hex or base64.
String hex = Long.toHexString(Long.parseLong( "·ñ+«r–àA‘ªNdàηAo§‹µå[üú΄d6‹:", 2)); - This is giving me number format exception. I think its not recognizing the bytes as valid format.
You need to encode the key into hex/base64 on the php side, copy it to the Java program and then decode it back into a byte array.
Thank you so much for the help. Just last thing, I got my decrypted string but it has some added data on start and end. RESULT - ””Íè7}?Vÿª¼MaÎAgThis string was AES-256 / CBC / ZeroBytePadding encrypted. I have updated the decryption function as well.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.