0

I inherited a project that was coded back in the PHP 5.X days. The site is running on PHP 7.1 right now and using the MCRYPT library for it's encryption and decryption functions.

I need to upgrade to PHP 7.2, which means bye bye MCRYPT!

Not being familiar with encryption is causing issues with trying to convert to OPENSSL

Below is the code that is currently in place.

function decrypt($encryptedText)
{
    $key = pack('H*', 'NOTHINGTOSEEHERE');
    $enc = base64_decode($encryptedText);
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $enc, MCRYPT_MODE_ECB, $key), "\x80");
}
function encrypt($plaintext)
{
    $key = pack('H*', 'NOTHINGTOSEEHERE');

    $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
    $inputLength = strlen($plaintext);
    $blockCount = floor($inputLength / $blockSize);
    $padding = ($blockCount + 1) * $blockSize - $inputLength;
    $paddedPlainText = str_pad($plaintext, $inputLength + $padding, "\x80", STR_PAD_RIGHT);

    $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $paddedPlainText, MCRYPT_MODE_ECB, $key);
    return base64_encode($enc);
}

I have looked over several other StackOverflow posts that go over this exact topic of converting from MCRYPT to OPENSSL, and based on everything I have read, I came up with the following code, which doesn't work.

function decrypt($encryptedText)
{
    $key = pack('H*', 'NOTHINGTOSEEHERE');

    $ivsize = openssl_cipher_iv_length('AES-128-ECB');
    $iv = openssl_random_pseudo_bytes($ivsize);

    $enc = base64_decode($encryptedText);

    return trim(openssl_decrypt($enc, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
}

function encrypt($plaintext)
{
    $key = pack('H*', 'NOTHINGTOSEEHERE');

    $ivsize = openssl_cipher_iv_length('AES-128-ECB');
    $iv = openssl_random_pseudo_bytes($ivsize);

    $enc = openssl_encrypt($plaintext, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);

    return base64_encode($enc);
}

I am not sure, but I have a feeling the issue has to do with the padding of the text in the old encryption function this is causing the new code not to work. I don't know how to integrate that into the OPENSSL functions, if that is indeed the problem.

$blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$inputLength = strlen($plaintext);
$blockCount = floor($inputLength / $blockSize);
$padding = ($blockCount + 1) * $blockSize - $inputLength;
$paddedPlainText = str_pad($plaintext, $inputLength + $padding, "\x80", STR_PAD_RIGHT);

Again, not being familiar with encryption, any/all help is appreciated so I can figure out and understand what I am doing wrong.

unu
  • 195
  • 1
  • 3
  • 13
  • What exactly is your definition of "doesn't work"? Do you mean that the code has an error when it runs? Or do you mean that the new code is unable to decrypt content that was encrypted with the old code? – Patrick Q Jan 30 '20 at 13:53
  • The new code doesn't decrypt content that was encrypted with the old code – unu Jan 30 '20 at 13:55
  • 3
    Or [this](http://stackoverflow.com/q/42696657/608639) or [this](https://stackoverflow.com/questions/31520311/decrypt-mcrypt-with-openssl). I will also throw out one inelegant option: Fetch all your encrypted text, decrypt it with mcrypt, and then encrypt it with openssl, then re-store it. Depending on how sensitive this data is and what industry you're in, there may be regulations that wouldn't be happy with that, not really sure. – Patrick Q Jan 30 '20 at 13:59
  • right that's roughly exactly what i was saying :-P – delboy1978uk Jan 30 '20 at 14:15
  • Let me add a vote for @PatrickQ inelegant solution. Just figure the right way to do this using the newer openssl interface, and then decrypt with mcrypt and re-encrypt with the openssl API. This will save you from trying to chase down every little idiosyncrasy in MCRYPT encryption and trying to duplicate it with the openssl API. Plus a great deal of MCRYPT code is flawed from a security perspective and really should not be preserved for another generation using the openssl API. – President James K. Polk Jan 31 '20 at 02:56

1 Answers1

0

I've dealt with this when upgrading my user password encryption. In pseudologic, you just need something like this:

<?php

if ($whatever === $this->decryptNew($var)) {
    // business as usual
} elseif ($whatever === $this->decryptOldWay($var)) {
    // encrypt as the new way!
    $encrypted = $this->encryptNew($whatever);
    // save!
    // Back to business as usual!
}

Here's my SSl class. Give it a try:

class Ssl
{
    private $cipher = "aes-128-gcm";
    private $options = 0;

    /**
     * @param string $plaintext
     * @return array
     */
    public function encrypt($plaintext)
    {
        $key = \openssl_random_pseudo_bytes(16);
        $ivlen = \openssl_cipher_iv_length($this->cipher);
        $iv = \openssl_random_pseudo_bytes($ivlen);
        $ciphertext = openssl_encrypt($plaintext, $this->cipher, $key, $this->options, $iv,$tag);

        return array(
            'key' => \bin2hex($key),
            'iv' => \bin2hex($iv),
            'tag' => \bin2hex($tag),
            'ciphertext' => $ciphertext,
        );
    }

    /**
     * @param string $json
     * @return false|string
     */
    public function decrypt($json, $key)
    {
        $data = \json_decode($json);
        $result = \openssl_decrypt($data->ciphertext, $this->cipher, \hex2bin($key), $this->options, \hex2bin($data->iv), \hex2bin($data->tag));

        return \json_decode($result, true);
    }
}
delboy1978uk
  • 12,118
  • 2
  • 21
  • 39
  • Could you maybe provide a sample showing that it can decrypt text encrypted with mcrypt? – Patrick Q Jan 30 '20 at 14:13
  • It has nothing to do with mcrypt. Keep your existing functions, add these, and try decrypting using the new stuff. If it fails, decrypt with the old stuff and re-encrypt with the new stuff. i d o a siomilar thing when updating user password field encryption, so next time a user logs in it updates itself – delboy1978uk Jan 30 '20 at 14:14
  • 1
    OP's whole question is how they can decrypt their existing encrypted text using openssl instead of mcrypt. "The new code doesn't decrypt content that was encrypted with the old code" – Patrick Q Jan 30 '20 at 14:15
  • how to decrypt an encrypted string using a different decryption algorithm? It can't be done. – delboy1978uk Jan 30 '20 at 14:16
  • The actual answer seems to be more along the lines of "it depends". See the questions/answers that I linked. Either way, OP isn't having trouble (based on what they said) encrypting new text with openssl, or decrypting text that was encrypted with openssl. They have code that works fine and as it should, OP just expects it to do _more_ than it should. – Patrick Q Jan 30 '20 at 14:19
  • 1
    Got it working... return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $enc, MCRYPT_MODE_ECB, $key), "\x80"); replaced with return trim(openssl_decrypt($enc, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $key), "\x80"); – unu Jan 30 '20 at 14:32
  • 1
    $enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $paddedPlainText, MCRYPT_MODE_ECB, $key); replaced with $enc = openssl_encrypt($paddedPlainText, 'AES-128-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $key); – unu Jan 30 '20 at 14:32