phpseclib decrypt with PBKD2

Get help with using the PHP Secure Communications Library.

Moderator: Nuxius

Forum rules
The purpose of this forum is to provide support for phpseclib, a pure PHP SSH / SFTP / RSA library.

Posts by new users are held in a moderation queue and are not publicly visible until the post is approved.

phpseclib decrypt with PBKD2

Postby alee » Wed Nov 20, 2013 6:48 pm

hi,

i am using android java to encrypt some data in AES 256. i am using the PBDK2 standard to convert a passcode(32 charlong string) and a randomly generated salt to derive a key. i also generate a random IV(initialization vector) and then encrypt this data using AES256/CBC/PKCS5Padding and send it to a php script, sending the salt, iv and ciphertext delimited by "]"..... however after trying for three days straight i am unable to decrypt it.....decrypt function returns "false"

below is my code.....
Code: Select all
            $EData = $_POST['Data'];
            $temp = array('success' => $EData);
           
            //split the data into salt, iv and cipher using delimiter "]"
            $result = explode(']', $EData);
            $salt = base64_decode($result[0]);
            $iv = base64_decode($result[0]);
            $ciphertext = base64_decode($result[1]);

            //key same as java
            $AESKey = "afd043e5b38dc169d031e72a1647974a";

            $cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
            $cipher->setPassword($AESKey, 'pbkdf2', 'sha1', $salt, 1000, 256 / 8);
            $cipher->setIV($iv);
            $cipher->enablePadding();

            $decipherText = $cipher->decrypt($ciphertext);
         
            echo json_encode(array('success' => $decipherText));



the above code yields {"success":false}.....

could someone please point me in right direction... should i send the key or the salt or the iv in some other format......

thanks
alee
Traveler
 
Posts: 5
Joined: Wed Nov 20, 2013 12:17 pm

Re: phpseclib decrypt with PBKD2

Postby TerraFrost » Wed Nov 20, 2013 8:59 pm

I'll try to take a look at this as time permits within the next few days. I've spent half the day doing phpseclib stuff and need to get back to work lol.
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: phpseclib decrypt with PBKD2

Postby alee » Thu Nov 21, 2013 11:45 am

thanks
alee
Traveler
 
Posts: 5
Joined: Wed Nov 20, 2013 12:17 pm

Re: phpseclib decrypt with PBKD2

Postby TerraFrost » Thu Nov 21, 2013 6:14 pm

So I found this post containing an example of how to do AES in Java here:

http://stackoverflow.com/a/992413/569976

Quoting from the code example:

Code: Select all
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));

I guess the salt, iteration count and key length are optional parameters, per this:

http://docs.oracle.com/javase/7/docs/ap ... ySpec.html

I'm not sure what the defaults are. In lieu of seeing your Java code I don't know if knowing what the default values are is necessary or not.

Also, as a sanity check I'd check to see if strlen($iv) * 8 == 128 (ie. the block size of AES).

Additionally, have you tried disabling padding?

Something else that might be worth a shot: see if you can get the key generated by PBKDF2 in Java and try that with phpseclib / setKey().
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: phpseclib decrypt with PBKD2

Postby alee » Fri Nov 22, 2013 6:17 am

hi TerraFrost,

thanks for getting back to me.... my java code is almost identical to what you have posted....only difference being that i am using 1000 iteration instead of the 65535 iterations used in your posted code.....

my iv length seems to be fine....because if i switch off the pbkd2 mode and just use the password as the key(and do the appropriate changes to java code)....i am able to decrypt. that is to say, simply use cipher->setKey(Password) works....instead of cipher->setPassword(Password, 'pbkd2', salt, 100, 256/8 )...

also to add....using the pbkdf2 standard i am able to encrypt and decrypt in java, its only in php that i am unable to decrypt.....
alee
Traveler
 
Posts: 5
Joined: Wed Nov 20, 2013 12:17 pm

Re: phpseclib decrypt with PBKD2

Postby alee » Fri Nov 22, 2013 2:02 pm

Hi....

after much loss of sleep, i have finally managed to get my code working, not the way i would have preferred it to work....but i will take it anyway....

i narrowed down the possiblities and finally found that the hash generated by the bouncy castle library in java and the one calculated by the phpsec libraries were not the same even though they both were seeded by the same salt and the same password....i figured that changing the bouncy castle library would be too much trouble....so i looked for some php implementations of PBKDF2 with sha1....i found that from php5.5 they have introduced a php port to this native function, however i was using 5.4.1 so tough luck....anyway i found a pure php implementation of that same function that check if the port is available for native manipulation otherwise does it in php..... below is the full class..... the function that we are interested in is the last function in the class...all in all a quite usefull class...

Code: Select all
<?php
/*
 * Password Hashing With PBKDF2 (http://crackstation.net/hashing-security.htm).
 * Copyright (c) 2013, Taylor Hornby
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTE_SIZE", 24);
define("PBKDF2_HASH_BYTE_SIZE", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTE_SIZE, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" .
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTE_SIZE,
            true
        ));
}

function validate_password($password, $correct_hash)
{
    $params = explode(":", $correct_hash);
    if(count($params) < HASH_SECTIONS)
       return false;
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0;
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
    if($count <= 0 || $key_length <= 0)
        trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);

    if (function_exists("hash_pbkdf2")) {
        // The output length is in NIBBLES (4-bits) if $raw_output is false!
        if (!$raw_output) {
            $key_length = $key_length * 2;
        }
        return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
    }

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}


using the function in this class i was able to replicate the exact same hashed_password as my java code.....below is a sample of my php code using this class and then entering the key in the phpseclib api....

Code: Select all
           $AESKey = ("a password string"); // this password should be 32 bytes for aes256...
            require_once 'pbkdf2.php';
            $pbkdf2 = new PBKDF2();
            $key = $pbkdf2->hash("sha1", $AESKey, ($salt), 1000, 256/8, false);
            $key = hex2bin($key);
            $cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
            //$cipher->setPassword($AESKey, 'pbkdf2', 'sha1', $salt, 1000, 256/8); //phpsec lib method for hashing with PBKDF2, which did not work for me
            $cipher->setKey(($key)); // loading the key
            $cipher->setIV(($iv));
            $cipher->enablePadding();
            echo "\n\n salt:\n\n" . bin2hex($salt) . "\n\n\n\n\n\n";
            echo "\n\n key \n\n" . $key . "\n\n\n\n\n\n";
            echo "\n\n iv:\n\n" . bin2hex($iv) . "\n\n\n\n\n\n";
            $decipherText = $cipher->decrypt(($ciphertext));
            //$cipher->disablePadding();
            //$cipherEncoded = $cipher->encrypt("ciphertext"));
            //$sendpacket = $salt
            echo json_encode(array('success' => $decipherText));



as for the future it would be great if you guys could look into what is the difference between the stock phpseclibfunction(Crypt/Rigndael.php->setPassword()) and the function as offered by this class i have posted...thanks for the support
alee
Traveler
 
Posts: 5
Joined: Wed Nov 20, 2013 12:17 pm

Re: phpseclib decrypt with PBKD2

Postby TerraFrost » Fri Nov 22, 2013 8:28 pm

Looking at your code and at the code of the library you're using.... I have a few thoughts...

From your code:
Code: Select all
            $key = $pbkdf2->hash("sha1", $AESKey, ($salt), 1000, 256/8, false);
            $key = hex2bin($key);

So I guess you made a few changes to the code you posted in your first code block because that code isn't a class - it's just a bunch of functions.

Anyway, using the code you posted...

Code: Select all
$password = "a password string";;
$salt = 'b';

$key = pbkdf2("sha1", $password, $salt, 1000, 256/8, false);
$key = hex2bin($key);
echo bin2hex($key) . "\r\n";

$key = pbkdf2("sha1", $password, $salt, 1000, 256/8, true);
echo bin2hex($key) . "\r\n";

include('Crypt/AES.php');

$aes = new Crypt_AES();
$aes->setPassword($password, 'pbkdf2', 'sha1', $salt, 1000, 256/8);
echo bin2hex($aes->key);

They all yield the same results for me on PHP 5.4.7 and PHP 5.5.3.

Do they yield the same output for you?

I'd test it with your salt but I don't know what you're using as the salt.

Also...

Code: Select all
           $AESKey = ("a password string"); // this password should be 32 bytes for aes256...

That's not really a requirement. If you were using a key it'd need to be of the appropriate length but passwords don't need to be. That's why it's called password-based key-derivation. Passwords don't need to meet the same criteria that a key ought to be meeting.
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: phpseclib decrypt with PBKD2

Postby alee » Sun Nov 24, 2013 9:00 pm

all i can say is weird....as soon as i get time i will recheck this.....

and yes the string has to be 32 bytes for aes 256 or it will reduce the key space making it easier to crack ....

thanks for your support and your valuable time....

regards
alee
Traveler
 
Posts: 5
Joined: Wed Nov 20, 2013 12:17 pm


Return to phpseclib support

Who is online

Users browsing this forum: No registered users and 1 guest

cron