Rewrite PHP Rijndael algorithm to Java (Android)
Asked Answered
S

2

3

I need to encode a string in Java and php where the result must be the same.

The following conditions are given:

  1. algorithm: RIJNDAEL-128
  2. key: 5P443m2Q1R9A7f5r3e1z08642
  3. mode: ECB
  4. initialization vector: N/A (Since we're using ECB, IV's are ignored)

String to encode: 201412181656005P443m2Q1R9A7f5r3e1z08642

PHP

 <?php
        class Cipher
        {
            private $securekey, $iv;

            function __construct($textkey)
            {
                $this->securekey = $textkey;
                $this->iv = mcrypt_create_iv(32);
            }

            function encryptR($input)
            {
                $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->securekey, $input, MCRYPT_MODE_ECB, $this->iv);
                return base64_encode($enc);
            }

            function decryptR($input)
            {
                return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->securekey, base64_decode($input), MCRYPT_MODE_ECB, $this->iv));
            }
        }

        $raw_text = '201412181656005P443m2Q1R9A7f5r3e1z08642';
        $secretKey = '5P443m2Q1R9A7f5r3e1z08642';

        $cipher = new Cipher($secretKey);
        $encrypted = $cipher->encryptR($raw_text);     
?>

Output: MbDHhIanWgySlMTOX+ItgVKudVLXbtj7ig2GMQacVM9JhyAPvVQxLJnHpEj/vhqW

JAVA

encrypted = encrypt("201412181656005P443m2Q1R9A7f5r3e1z08642","5P443m2Q1R9A7f5r3e1z08642");

public class Crypt {

    private final String characterEncoding = "UTF-8";
    private final String cipherTransformation = "AES/ECB/PKCS5Padding";
    private final String aesEncryptionAlgorithm = "AES";

    public  byte[] decrypt(byte[] cipherText, byte[] key) throws Exception
    {
        Cipher cipher = Cipher.getInstance(cipherTransformation);
        SecretKeySpec secretKeySpecy = new SecretKeySpec(key, aesEncryptionAlgorithm);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpecy);
        cipherText = cipher.doFinal(cipherText);
        return cipherText;
    }

    public byte[] encrypt(byte[] plainText, byte[] key) throws Exception
    {
        Cipher cipher = Cipher.getInstance(cipherTransformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, aesEncryptionAlgorithm);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        plainText = cipher.doFinal(plainText);
        return plainText;
    }

    private byte[] getKeyBytes(String key) throws UnsupportedEncodingException{
        byte[] keyBytes= new byte[16];
        byte[] parameterKeyBytes= key.getBytes(characterEncoding);
        System.arraycopy(parameterKeyBytes, 0, keyBytes, 0, Math.min(parameterKeyBytes.length, keyBytes.length));
        return keyBytes;
    }

    @SuppressLint("NewApi")
    public String encrypt(String plainText, String key) throws Exception {
        byte[] plainTextbytes = plainText.getBytes(characterEncoding);
        byte[] keyBytes = getKeyBytes(key);
        // Log.i("iv", ""+keyBytesIV);
        return Base64.encodeToString(encrypt(plainTextbytes,keyBytes), Base64.DEFAULT);
    }

    @SuppressLint("NewApi")
    public String decrypt(String encryptedText, String key) throws Exception {
        byte[] cipheredBytes = Base64.decode(encryptedText, Base64.DEFAULT);
        byte[] keyBytes = getKeyBytes(key);

        return new String(decrypt(cipheredBytes, keyBytes), characterEncoding);
    }

}

Output: wd0FHYpLbgdpHhcSql7VVCiKWJWN5hvP0W9F4sgKWAWeDcSjvfKWTM5LHBCZJSRw

Updated:

I changed the padding from NoPadding to PKCS5Padding

Is this correct? I'm not sure, cause if you look at the PHP code. There wasn't any padding specified(my own assumption based on syntax).

Info on Mcrypt

Additional Insight:

Read this document regarding padding(No Padding). Must've been related to the issue.

Steven answered 13/1, 2015 at 11:28 Comment(4)
When I try to run your code, I have the following exception : javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1016)Sandon
AES/Rijndael compatibility between platforms is difficult indeed. Be careful of of the block size, you'll need to pad it and make sure it's padded to the closest divisible value of 16.Ary
Note that you are creating a 32-byte iv when AES iv size is 16-bytes.Morality
It is best not to use mcrypt, it is abandonware, has not been updated in years and does not support standard PKCS#7 (née PKCS#5) padding, only non-standard null padding that can't even be used with binary data. mcrypt had many outstanding bugs dating back to 2003.. Instead consider using defuse, it is being maintained and is correct.Morality
A
3

Looks like your PHP version uses AES-128, which by definition, uses 128-bit (16-byte) keys. However looks like you passed in a 25-byte key (5P443m2Q1R9A7f5r3e1z08642), which I'm not sure what PHP does when that happens.

Your Java version's getKeyBytes() method only returns the first 16 bytes of the supplied key, so it encrypts with only that.

Try truncating the key in your PHP version to 5P443m2Q1R9A7f5r and you'd get the same result. Except the end part which may be different. At that point, the issue then would be the padding. You can apply the pkcs5_pad PHP function on your plaintext so it matches your Java version.

All that said, if this was just for learning purposes, it's ok. Otherwise, for actual use it's important that you do not use ECB cipher mode.

Anastigmatic answered 6/2, 2015 at 18:45 Comment(0)
P
0

I changed byte[] keyBytes= new byte[16]; to byte[] keyBytes= new byte[32]; in getKeyBytes method then it worked fine.

Polarization answered 17/11, 2015 at 8:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.