AES 128 CBC Encryption to PHP Interface

Anything beyond the basics in using the LiveCode language. Share your handlers, functions and magic here.

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
dcpbarrington
Posts: 87
Joined: Tue Nov 13, 2007 6:40 pm

AES 128 CBC Encryption to PHP Interface

Post by dcpbarrington » Mon Jul 14, 2014 10:51 pm

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

Simon
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3901
Joined: Sat Mar 24, 2007 2:54 am

Re: AES 128 CBC Encryption to PHP Interface

Post by Simon » Tue Jul 15, 2014 6:04 am

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
I used to be a newbie but then I learned how to spell teh correctly and now I'm a noob!

dcpbarrington
Posts: 87
Joined: Tue Nov 13, 2007 6:40 pm

Re: AES 128 CBC Encryption to PHP Interface

Post by dcpbarrington » Wed Jul 16, 2014 1:00 am

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

keithglong
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 348
Joined: Sun Jul 03, 2011 2:04 am

Re: AES 128 CBC Encryption to PHP Interface

Post by keithglong » Sat Nov 22, 2014 12:43 pm

Hi dcpbarrington,

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

Thanks,

- Boo

dcpbarrington
Posts: 87
Joined: Tue Nov 13, 2007 6:40 pm

Re: AES 128 CBC Encryption to PHP Interface

Post by dcpbarrington » Mon Nov 24, 2014 6:57 pm

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

keithglong
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 348
Joined: Sun Jul 03, 2011 2:04 am

Re: AES 128 CBC Encryption to PHP Interface

Post by keithglong » Tue Nov 25, 2014 12:20 am

Hi dcpbarrington,

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

Warmest regards,

- Boo

Post Reply