4

I am trying to create a UUID on my server, and for some reason openssl_enrypt is initializing an empty string. This would be a different conversation if it was returning false, but it's not, it's returning a string, just one that's empty.

Here is all of my code I'm using to build the encrypted string I want:

$key = hash_hmac("sha512", "You can decrypt this all day long, won't get you closer to the truth", "myKey");
$iv = openssl_random_pseudo_bytes(16);
$adminVal = filter_var($userData['is_admin'], FILTER_VALIDATE_BOOLEAN);
$userName = $userData["name"];
$dataEncrypt = $adminVal.$userName;
$encrypted = openssl_encrypt($dataEncrypt, "AES-256-XTS", $key, 0, $iv);

I have var_dumped $key, $iv, and $dataEncrypt and they all return correct values.

jww
  • 97,681
  • 90
  • 411
  • 885
Adam McGurk
  • 186
  • 1
  • 19
  • 54
  • 1
    It seems to be the method you're using `AES-256-XTS`. If you change that to `aes128` or `AES-128-CBC` for example, you'll see a result. Consult the documentation http://php.net/manual/en/function.openssl-encrypt.php - There is no `AES-256-XTS` listed in the manual. – Funk Forty Niner Oct 19 '17 at 01:29
  • @Fred-ii- You're absolutely right, thank you! I can't believe I didn't see that...I would love to give you the answer! – Adam McGurk Oct 19 '17 at 01:32
  • You're most welcome Adam, *cheers* – Funk Forty Niner Oct 19 '17 at 01:33
  • This looks like it could be dangerous: `filter_var($userData['is_admin'], FILTER_VALIDATE_BOOLEAN)`. Is it being retrieved from a client? – jww Oct 19 '17 at 02:18
  • @jww no, that is getting retrieved from the database – Adam McGurk Oct 19 '17 at 02:19
  • 2
    Another thing @AdamMcGurk can you add the following line in your script `var_dump(openssl_get_cipher_methods());` and see if `AES-256-XTS` is in fact listed? – Funk Forty Niner Oct 19 '17 at 12:59
  • @Fred-ii- yes, I just dumped the function and `AES-256-XTS` is listed! – Adam McGurk Oct 19 '17 at 16:38
  • 1
    @AdamMcGurk Thanks Adam. I'm still investigating/further testing this. So far, you've an empty string and that is the part I'm trying to figure out, being the "why" it is empty. I've managed to get a test script going using the `AES-256-XTS` cipher method, and to compare those two in finding the differences. – Funk Forty Niner Oct 19 '17 at 16:40
  • @Fred-ii- Right, and that's what confused me the most, because had it thrown an exception or returned false, it would have been a different question, but it was just an empty string. Thanks for looking into this Fred!! – Adam McGurk Oct 19 '17 at 16:41
  • 1
    @AdamMcGurk I made an edit to the answer. I hope this sheds more light on the subject. – Funk Forty Niner Oct 19 '17 at 17:42

2 Answers2

4

@Fred-ii- You're absolutely right, thank you! I can't believe I didn't see that...I would love to give you the answer!

As requested:

It seems to be the method you're using AES-256-XTS. If you change that to aes128 or AES-128-CBC for example, you'll see a result. Consult the documentation http://php.net/manual/en/function.openssl-encrypt.php - There is no AES-256-XTS listed in the manual.

Edit: I removed the bug report from a previous edit which I will investigate this further as to why this ended up producing an empty result.

Since the (cipher) method does (in fact) exist when running a var_dump(openssl_get_cipher_methods());, it may also depend on openssl; as pulled/taken from a comment left in the bug report.

I will update my answer if/once I can hopefully get results/an explanation as to why the OP's and my own tests came up as empty and to get more information from the OP.


Edited:

After doing more research, I stumbled upon this link and that code worked "right out of the box" using the "AES-256-XTS" cipher method (note; consult the commented line note in the source script near the end).

In looking at that code and comparing it with the OP, I noticed that it was the data/message that required to be encrypted.

  • The message was hashed "as the key" which in turn made the string empty. Only hash the key and not both key and data/message, as you were trying to encrypt both an existing hashing method with the message and key "as the key".

The resulting script came out being the following:

Sidenote: The commented lines just below, also work with their respective parts; just don't use both at the same time.

$plaintext = 'The secret message in plain text';
$password = '3sc3RLrpd17';
$key = substr(hash('sha256', $password, true), 0, 32);

$iv = openssl_random_pseudo_bytes(16);
$method = "aes-256-xts";
$userName = "JOHN";
$encrypted = base64_encode(openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv));
// $encrypted = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);

    echo "<br>";
    var_dump($iv);
    echo "<br>";
    var_dump($userName);
    echo "<br>";
    var_dump($encrypted);
    echo "<hr>";

$decrypted = openssl_decrypt(base64_decode($encrypted), $method, $key, OPENSSL_RAW_DATA, $iv);
// $decrypted = openssl_decrypt($encrypted, $method, $key, OPENSSL_RAW_DATA, $iv);
    echo 'decrypted to: ' . $decrypted . "\n\n";

Special note: I also had some help in picking Jay Blanchard's brain and testing; two heads are often better than one, so Jay deserves credit for this also.

NOTE: More than one source indicates it ("AES-256-XTS") is for file systems / disk encryption. You could say "AES-256-XTS and AES-128-XTS" methods really intended for file system encryption and therefore are not suitable for text.

Source code pulled from this link:

<?php

$plaintext = 'My secret message 1234';
$password = '3sc3RLrpd17';
$method = 'aes-256-cbc'; // I replaced aes-256-cbc with aes-256-xts during testing

// Must be exact 32 chars (256 bit)
$password = substr(hash('sha256', $password, true), 0, 32);
echo "Password:" . $password . "\n";

// IV must be exact 16 chars (128 bit)
$iv = chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0);

// av3DYGLkwBsErphcyYp+imUW4QKs19hUnFyyYcXwURU=
$encrypted = base64_encode(openssl_encrypt($plaintext, $method, $password, OPENSSL_RAW_DATA, $iv));

// My secret message 1234
$decrypted = openssl_decrypt(base64_decode($encrypted), $method, $password, OPENSSL_RAW_DATA, $iv);

echo 'plaintext=' . $plaintext . "\n";
echo 'cipher=' . $method . "\n";
echo 'encrypted to: ' . $encrypted . "\n";
echo 'decrypted to: ' . $decrypted . "\n\n";
Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141
  • 1
    For a list of available cipher methods, use [openssl_get_cipher_methods()](http://php.net/manual/en/function.openssl-get-cipher-methods.php). – Funk Forty Niner Oct 19 '17 at 01:41
  • 1
    Forgive my ignorance... How is it PHP (or PHP-OpenSSL) does not indicate failure by returning false or throwing an exception? It seems kind of broke to me. – jww Oct 19 '17 at 02:01
  • 1
    @jww It is quite odd. I tested this using `AES-256-XTA` replacing the "C" with an "A" from the OP's code and that threw a warning. But, the "C" did not. Same thing goes for just using an "X" or "aaa". This may be worthy of a bug report. – Funk Forty Niner Oct 19 '17 at 10:23
  • 1
    @jww I made a typo in my comment above and didn't have time to edit, I meant replacing the "S" with a "C". Either way, both threw a warning. – Funk Forty Niner Oct 19 '17 at 10:30
  • 1
    @jww The following bug report has been submitted https://bugs.php.net/bug.php?id=75407 – Funk Forty Niner Oct 19 '17 at 11:49
  • 2
    Note: The bug report is now marked as "closed". I will try and investigate this further. – Funk Forty Niner Oct 19 '17 at 13:14
  • 1
    Wow!! That was really good information! I really appreciated the info about AES-256-XTS being for disk encryption and not necessarily text! Thanks for doing all the research!! – Adam McGurk Oct 19 '17 at 17:52
  • 2
    @AdamMcGurk You're most welcome Adam. I felt I needed to further my research on this in order to be as accurate as I could. In simply replacing a cipher method (for another) works, but it originally did not explain why it failed/produced an empty result to start with. The question deserved it. IMHO. – Funk Forty Niner Oct 19 '17 at 17:54
1

I had an issue where openssl_encrypt() kept returning an empty string on my client's site, while it worked flawlessly on my dev site. If it had returned FALSE, then openssl_error_string() might have helped me troubleshoot, but apparently openssl_encrypt() was not actually failing - simply returning the empty string.

Long story short, the issue turned out to be that my dev server was running PHP 7.1 while my client's server was running 5.6. My fix was to remove the $tag parameter from openssl_encrypt() (it's optional in PHP 7.1+ anyway, but I had been following the php.net manual's example).

phpversion()

Anazul
  • 231
  • 2
  • 6