0

I am using phpseclib to encode the contents of a json file using a random key as follows:

$plainkey = openssl_random_pseudo_bytes(32); 
$iv = openssl_random_pseudo_bytes(16);

$payload_plain = file_get_contents("file.json");

$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(256);
$cipher->setKey($plainkey);
$cipher->setIV($iv);

$enc_payload = $cipher->encrypt($payload_plain);

At this point, $enc_payload contains the ciphertext, and calling $cipher->decode on it returns the plaintext, as expected. So far so good.

The problem arises when i write this encrypted data to a file and then try to decrypt it using openssl, using a command such as the one below:

openssl enc -d -aes-256-cbc -iv 17741abad138acc10ab340aaa7c4b790 -K d96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf -in encrypted.txt -out plain.txt

whereby the values for -iv and -K have been obtained by using bin2hex on the random byte values obtained in the script above.

Running that command gives me an error and plain.txt contains a half correct / half scrambled version of the original json string. Error:

bad decrypt
13124:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:.\crypto\evp\evp_enc.c:323:

What am i missing? I am thinking maybe the part where i use bin2hex on the key / iv is incorrect, but I have tried using the byte strings directly without any success. How is this done normally? Or am i missing anything obvious?

Thanks

jww
  • 97,681
  • 90
  • 411
  • 885
user3816703
  • 129
  • 1
  • 4
  • 2
    FIrst check that the encrypted data is an exact multiple og the block size (16-bytes for AES). There could be different padding being used. Check what the default padding is. For debugging decrypt with no padding specified, see if the decryption is without errors, if so it is the padding. Then look at the last block of decrypted data to determine the padding. – zaph Jul 07 '17 at 13:13
  • 1
    This is probably not the padding. Can you show the ciphertext? – Artjom B. Jul 07 '17 at 18:09
  • 3
    In your PHP code you are using random Keys and IV's. In your OpenSSL command, you are using a fixed Key and IV. It looks like `EVP_BytesToKey` is a usual suspect. Perhaps you should use a fixed Key and IV for both examples to get you to a baseline. Also see [Encrypt (cryptojs) - Decrypt (erlang)](https://stackoverflow.com/q/34542736/608639). – jww Jul 08 '17 at 02:39
  • @zaph I tried to disable padding during encryption, results are exactly the same so i am guessing that's not it. – user3816703 Jul 10 '17 at 01:53
  • @jww Tried with fixed key / iv, still no sugar (exact same error) I just thought of something though, openssl command asks for hex values for the key / iv parameters, so for debugging purposes, for each run of the encryption script i am calling bin2hex on the random key / iv, and writing the results to 2 files. these are the values i am passing to openssl in the cli. do you think this might have something to do with it? – user3816703 Jul 10 '17 at 02:00
  • debugging **de**crypt with no padding – zaph Jul 10 '17 at 02:05
  • @zaph ok, i added `$cipher->disablePadding()` to my php, and added the `-nopad` option to my CLI call to openssl, and the error message changes, now getting `bad decrypt 15812:error:0606508A:digital envelope routines:EVP_DecryptFinal_ex:data not multiple of block length:.\crypto\evp\evp_enc.c:313:`. meaning the ciphertext's length is not a multiple of 16 as it should be? – user3816703 Jul 10 '17 at 06:14
  • 1
    The point is to encrypt with padding and decrypt without padding sop you can examine the last 8 bytes of the decrypted data to examine the paddig that was added. You weill be able to tell what type of padding was added or is it is not a valid padding the decryption failed. – zaph Jul 10 '17 at 14:03

1 Answers1

1

It worked fine for me. My code (adapted from yours):

<?php
include('Crypt/AES.php');

$plainkey = pack('H*', 'd96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf'); 
$iv = pack('H*', '17741abad138acc10ab340aaa7c4b790');

$payload_plain = file_get_contents('plaintext.txt');

$cipher = new Crypt_AES(CRYPT_AES_MODE_CBC);
$cipher->setKeyLength(256);
$cipher->setKey($plainkey);
$cipher->setIV($iv);

$enc_payload = $cipher->encrypt($payload_plain);

file_put_contents('ciphertext.txt', $enc_payload);

I decrypted with this:

openssl enc -d -aes-256-cbc -iv 17741abad138acc10ab340aaa7c4b790 -K d96ab4a30d73313d4c525844fce61d9f925e119cf178761b27ad0deab92a32bf -nosalt -p -in encrypted.txt -out plaintext.txt

The difference is that I have -p and -nosalt. -p just prints the keys out but maybe -nosalt is what you need.

Or maybe the problem is simpler than even this. In the code snippet you posted you're not echo'ing or saving the key / iv anywhere. Maybe you're not outputting the right values.

I got the OpenSSL parameters from http://phpseclib.sourceforge.net/interop.html#aes,p1openssl,p2phpseclib

neubert
  • 15,947
  • 24
  • 120
  • 212
  • Hello, thank you for your reply. Is this exactly the code you used? i copied it verbatim (minus a small change in the openssl command, `ciphertext.txt` instead of `encrypted.txt`, and i am still getting that `wrong final block length` error in openssl :/ – user3816703 Jul 10 '17 at 07:05
  • Aaaaand an update, it works if `plaintext.txt` contains a short string like "hello world", i'm guessing it is either the length of my plaintext or its contents that are causing the error, still digging. Thanks again for the pointer though :) – user3816703 Jul 10 '17 at 07:14
  • @user3816703 - the plaintext I tested it out on was 18KB. I'll try using various engines instead of the default engine when I get home from work and see if that enables me to reproduce your issue. In the mean time... what version of phpseclib are you using? – neubert Jul 10 '17 at 12:34
  • I am using phpseclib v1.0.7. while tinkering I did notice something strange though, on my dev setup (vanilla xampp on windows) everything works as expected, but on the server (a shared ovh server) the padding+encryption seems to work well, until the message length reaches 160 bytes. then it works only for multiples of 32 bytes. I'm trying to think of what could cause the discrepancy but still no clue :/ – user3816703 Jul 14 '17 at 10:23
  • @user3816703 - well I tried it out with every single engine (OpenSSL, mcrypt, internal) and each of them worked. My code: https://pastebin.com/KiMthj1y My phpinfo: https://pastebin.com/hFp16BKL As my phpinfo shows, I'm running Windows 10 as well (altho I'm not running the PHP script in the context of XAMPP). The message length is 18,047 bytes as well. ie. it's not a multiple of 32 bytes. The only other thing I can think of (short of giving me RDC access to your computer lol) would be to post your phpinfo... – neubert Jul 16 '17 at 14:59