2

I've been trying to implement the exact same function in PHP as the one in C. However, I have not seen the exact same outcome. I think the problem is with the "count" or iteration that I still do not totally understand.

Function definition:

int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, 
       const unsigned char *salt, const unsigned char *data, int datal,
       int count, unsigned char *key, unsigned char *iv)

Here is the link to the C function implementation: evp_key.c.

Here is what I found on Stack Overflow, which is close, but without the "count" that the author briefly mentioned: Encrypting data in Cocoa, decoding in PHP. The key lines as provided by user myztikjenz are here:

$cipher = MCRYPT_TRIPLEDES;
$cipherMode = MCRYPT_MODE_CBC;

$keySize   = mcrypt_get_key_size( $cipher, $cipherMode );
$ivSize    = mcrypt_get_iv_size( $cipher, $cipherMode );

$rawKey = "ThisIsMyKey";
$genKeyData = '';
do
{
    $genKeyData = $genKeyData.md5( $genKeyData.$rawKey, true );
} while( strlen( $genKeyData ) < ($keySize + $ivSize) );

$generatedKey = substr( $genKeyData, 0, $keySize );
$generatedIV  = substr( $genKeyData, $keySize, $ivSize );

$output = mcrypt_decrypt( $cipher, $generatedKey, $encodedData, $cipherMode, $generatedIV );

echo "output (hex)" . bin2hex($output);`

However I still do not know where the "count" would go.

Any help is greatly appreciated.

jww
  • 97,681
  • 90
  • 411
  • 885
Kevin N
  • 21
  • 2
  • If I'm not mistaken, the count by default is set to 1. Not much of a count :) – Maarten Bodewes Feb 27 '14 at 06:39
  • Sorry i didnt make it clear enough. What I meant was where and what that count loop would do. I know its an iteration of some kind to make sure something generated to be highly random. I read somewhere that the count should be large, but too large would make it slow. – Kevin N Feb 27 '14 at 06:58
  • The count is there to make the function slow - both for an attacker as well as for the user. The idea is that the attacker has to try many passwords so an attacker has N times the delay / CPU cycles, while the user has a fixed delay / CPU cycles. The count is known in similar functions as the "cost" which makes its use a tad more clear. – Maarten Bodewes Feb 27 '14 at 16:38
  • I did try and will post my code if necessary. Basically i still could not come up with the similar output that the C openssl lib produces (the man page you referred to) – Kevin N Feb 28 '14 at 07:22
  • Thanks. I have got this to work already. – Kevin N Mar 05 '14 at 02:45
  • @KevinN - how have you got it to work ? thanks – arty Jan 18 '15 at 14:13
  • [OpenSSL 1.1.0c changed the digest algorithm](http://stackoverflow.com/q/39637388/608639) used in some internal components. Formerly, MD5 was used, and 1.1.0 switched to SHA256. Be careful the change is not affecting you in both `EVP_BytesToKey` and commands like `openssl enc`. – jww Jan 26 '17 at 16:12

1 Answers1

3

Below mimics the openssl EVP_BytesToKey in php - The only problem I have is to get the key length correctly so for now it is fixed to 32 bytes (amend to suit your needs) iv is get from the cypher used. (salt is not implemented, but easy to add)

$arr = bytestokey($hash,5,"aes-256-cbc","sha1");

$plain = openssl_decrypt($encrypted, "aes-256-cbc", $arr["key"], $options=0, $arr["iv"]);

function bytestokey($data,$count,$cipher,$digest) {
            $ivlen  = openssl_cipher_iv_length($cipher);
            $keylen = 32;
            $hash  = "";
            $hdata = "";
            while(strlen($hash) < $keylen+$ivlen) {
                $hdata .= $data;
                $md_buf = openssl_digest($hdata, $digest);
                //
                for ($i = 1; $i < $count; $i++) {
                    $md_buf = openssl_digest ( hex2bin($md_buf),$digest);
                }
                $hdata = hex2bin($md_buf);
                $hash .= $hdata;
            }
            //
            $key = substr($hash,0,$keylen);
            $iv  = substr($hash,$keylen,$ivlen);
            //
            return array('key' => $key, 'iv' => $iv);
        }
Willem E.
  • 31
  • 4
  • I have implemented this code (thanks for the great foundation btw), but I fear I've come across an issue. I notice that the `$iv` being generated off the same `$data` value is always the same result. Now I'm certainly no expert on this stuff but from what I've been reading, the `$iv` should be different with every single encryption. @Will Do you have any ideas how to get the `$iv` to generate a different result with each method call? – Chad Dec 14 '19 at 20:50
  • The idea is to generate a key and iv from a password, so the outcome should always be the same for the same password. It is mimics the C function provided by the openssl library ... – Willem E. Jun 24 '20 at 08:37