Page 1 of 1

AES 128 CBC Encryption to PHP Interface

Posted: Mon Jul 14, 2014 10:51 pm
by dcpbarrington
Forum,

I'm interfacing a LiveCode Mobil App with a Web Application that is developed in PHP. Part of the interface require that I send an AES-128-cbc encrypted string as a token to verify that it is a valid request. I need to generate a token on LiveCode and Decode it on the web site. The following is the Livecode Function that is being used and the PHP function that is being used on the web site. LiveCode is using OpenSSL and PHP is using mcrypt.

I've also tried to go to several OnLine AES sites to test the output, but haven't been able to decode the

Code: Select all

function CreateToken pTokenText
   
   encrypt pTokenText using "aes-128-cbc" with password "TESTKEY"
   put it into tTokenValue
   return base64Encode( tTokenValue )
   
end CreateToken
The interface is using the following PHP Function to evaluate the token.

Code: Select all

 /**
     * AES decryption in CBC mode. This is the standard mode.
     *
     * Supports AES-128, AES-192 and AES-256. It supposes that the last 4 bytes
     * contained a little-endian unsigned long integer representing the unpadded
     * data length.
     *
     * @since 3.0.1
     * @author Nicholas K. Dionysopoulos
     *
     * @param string $ciphertext The data to encrypt
     * @param string $password Encryption password
     * @param int $nBits Encryption key size. Can be 128, 192 or 256
     * @return string The plaintext
     */
    public static function AESDecryptCBC($ciphertext, $password, $nBits = 128)
    {
        if (!($nBits==128 || $nBits==192 || $nBits==256)) return false;  // standard allows 128/192/256 bit keys
        if(!function_exists('mcrypt_module_open')) return false;

        // Try to fetch cached key/iv or create them if they do not exist
        $lookupKey = $password.'-'.$nBits;
        if(array_key_exists($lookupKey, self::$passwords))
        {
            $key    = self::$passwords[$lookupKey]['key'];
            $iv        = self::$passwords[$lookupKey]['iv'];
        }
        else
        {
            // use AES itself to encrypt password to get cipher key (using plain password as source for
            // key expansion) - gives us well encrypted key
            $nBytes = $nBits/8;  // no bytes in key
            $pwBytes = array();
            for ($i=0; $i<$nBytes; $i++) $pwBytes[$i] = ord(substr($password,$i,1)) & 0xff;
            $key = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
            $key = array_merge($key, array_slice($key, 0, $nBytes-16));  // expand key to 16/24/32 bytes long
            $newKey = '';
            foreach($key as $int) { $newKey .= chr($int); }
            $key = $newKey;

            // Create an Initialization Vector (IV) based on the password, using the same technique as for the key
            $nBytes = 16;  // AES uses a 128 -bit (16 byte) block size, hence the IV size is always 16 bytes
            $pwBytes = array();
            for ($i=0; $i<$nBytes; $i++) $pwBytes[$i] = ord(substr($password,$i,1)) & 0xff;
            $iv = self::Cipher($pwBytes, self::KeyExpansion($pwBytes));
            $newIV = '';
            foreach($iv as $int) { $newIV .= chr($int); }
            $iv = $newIV;

            self::$passwords[$lookupKey]['key'] = $key;
            self::$passwords[$lookupKey]['iv'] = $iv;
        }

        // Read the data size
        $data_size = unpack('V', substr($ciphertext,-4) );

        // Decrypt
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
        mcrypt_generic_init($td, $key, $iv);
        $plaintext = mdecrypt_generic($td, substr($ciphertext,0,-4));
        mcrypt_generic_deinit($td);

        // Trim padding, if necessary
        if(strlen($plaintext) > $data_size)
        {
            $plaintext = substr($plaintext, 0, $data_size);
        }

        return $plaintext;
    }
}
I'm using a simple password, do I need to define the SALT and IV when I encode the TokenText?
I don't see a way to turn off the SALT, so it is automatically generated.

Would it be better to define a specific Key and IV for both sides to use? Each system may be generating the Key and IV differently.

Is there a better way to encrypt on LiveCode and decrypt on PHP?

Any direction or ideas would be helpful as I'm pulling out my hair on this one. I know the setup needs to be exact on both systems.
Thanks
dcpbarrington

Re: AES 128 CBC Encryption to PHP Interface

Posted: Tue Jul 15, 2014 6:04 am
by Simon
Hi dcpbarrington,
I don't see a way to turn off the SALT, so it is automatically generated.
I think this is it, was a long time ago:

Code: Select all

encrypt pTokenText using "aes-128-cbc" with password "TESTKEY" and salt empty
Simon

Re: AES 128 CBC Encryption to PHP Interface

Posted: Wed Jul 16, 2014 1:00 am
by dcpbarrington
Thanks Simon,

I found when you set salt to Empty, the output is the following: Salted__ (then encrypted text)

So the Empty salt is still in the output.

I'm first going to define a 128 bit Key and IV and not mess around with the Password and Salt. That way there is no difference between the two systems in how they create the Key and IV from the Password and Salt.

I'll let you know how that works.
dcpbarrington

Re: AES 128 CBC Encryption to PHP Interface

Posted: Sat Nov 22, 2014 12:43 pm
by keithglong
Hi dcpbarrington,

Did you ever get this working? It would be awesome if you could post an example.

Thanks,

- Boo

Re: AES 128 CBC Encryption to PHP Interface

Posted: Mon Nov 24, 2014 6:57 pm
by dcpbarrington
I was able to get the encryption working between LiveCode handing off to a PHP application.

The big problem was to get exactly the same HEX key and IV value on both systems and to make sure that the key value was the 128 bit value and not a byte string value.

Code: Select all

function CreateToken pTokenText
   local tHex, tKeyHex
   
   put "FFFFFFFFFFFFDDCC" into tKeyHex
   put "FFFFFFFFFFFFDDCC" into tIVHex
   encrypt pTokenText using "aes-128-cbc" with key tKeyHex and IV tIVHex at 128 bit
   put it into tTokenValue
   if the result is Empty then
      return base64Encode( tTokenValue )
   else
      return "Error:" && the result
   end if
   
end CreateToken
I tried to get the PHP system to convert the text string to a bit string without success, so I just kept using the text string on both system.

Hope that helps.
dcpbarrington

Re: AES 128 CBC Encryption to PHP Interface

Posted: Tue Nov 25, 2014 12:20 am
by keithglong
Hi dcpbarrington,

Thanks for the feedback. I'll give it a whirl...

Warmest regards,

- Boo