Browse Source

Use mb_* throughout crypto classes.

The str* functions can easily do the wrong thing when the string
functions are overloaded. By using the mbstring functions we can ensure
stable byte counting and byte slicing.

Refs #6139
Mark Story 11 years ago
parent
commit
615707e57f
3 changed files with 17 additions and 16 deletions
  1. 9 8
      src/Utility/Crypto/Mcrypt.php
  2. 2 2
      src/Utility/Crypto/OpenSsl.php
  3. 6 6
      src/Utility/Security.php

+ 9 - 8
src/Utility/Crypto/Mcrypt.php

@@ -40,14 +40,14 @@ class Mcrypt
         $mode = MCRYPT_MODE_CBC;
         $ivSize = mcrypt_get_iv_size($algorithm, $mode);
 
-        $cryptKey = substr($key, 0, 32);
+        $cryptKey = mb_substr($key, 0, 32, '8bit');
 
         if ($operation === 'encrypt') {
             $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
             return $iv . '$$' . mcrypt_encrypt($algorithm, $cryptKey, $text, $mode, $iv);
         }
-        $iv = substr($text, 0, $ivSize);
-        $text = substr($text, $ivSize + 2);
+        $iv = mb_substr($text, 0, $ivSize, '8bit');
+        $text = mb_substr($text, $ivSize + 2, null, '8bit');
         return rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0");
     }
 
@@ -72,7 +72,7 @@ class Mcrypt
         $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
 
         // Pad out plain to make it AES compatible.
-        $pad = ($ivSize - (strlen($plain) % $ivSize));
+        $pad = ($ivSize - (mb_strlen($plain, '8bit') % $ivSize));
         $plain .= str_repeat(chr($pad), $pad);
 
         return $iv . mcrypt_encrypt($algorithm, $key, $plain, $mode, $iv);
@@ -92,18 +92,19 @@ class Mcrypt
         $mode = MCRYPT_MODE_CBC;
         $ivSize = mcrypt_get_iv_size($algorithm, $mode);
 
-        $iv = substr($cipher, 0, $ivSize);
-        $cipher = substr($cipher, $ivSize);
+        $iv = mb_substr($cipher, 0, $ivSize, '8bit');
+        $cipher = mb_substr($cipher, $ivSize, null, '8bit');
         $plain = mcrypt_decrypt($algorithm, $key, $cipher, $mode, $iv);
 
         // Remove PKCS#7 padding or Null bytes
         // Newer values will be PKCS#7 padded, while old
         // mcrypt values will be null byte padded.
-        $padChar = substr($plain, -1);
+        $padChar = mb_substr($plain, -1, null, '8bit');
         if ($padChar === "\0") {
             return trim($plain, "\0");
         }
         $padLen = ord($padChar);
-        return substr($plain, 0, -$padLen);
+        $result = mb_substr($plain, 0, -$padLen, '8bit');
+        return $result === '' ? false : $result;
     }
 }

+ 2 - 2
src/Utility/Crypto/OpenSsl.php

@@ -77,9 +77,9 @@ class OpenSsl
         $method = 'AES-256-CBC';
         $ivSize = openssl_cipher_iv_length($method);
 
-        $iv = substr($cipher, 0, $ivSize);
+        $iv = mb_substr($cipher, 0, $ivSize, '8bit');
 
-        $cipher = substr($cipher, $ivSize);
+        $cipher = mb_substr($cipher, $ivSize, null, '8bit');
         return openssl_decrypt($cipher, $method, $key, true, $iv);
     }
 }

+ 6 - 6
src/Utility/Security.php

@@ -146,7 +146,7 @@ class Security
         if (empty($operation) || !in_array($operation, ['encrypt', 'decrypt'])) {
             throw new InvalidArgumentException('You must specify the operation for Security::rijndael(), either encrypt or decrypt');
         }
-        if (strlen($key) < 32) {
+        if (mb_strlen($key, '8bit') < 32) {
             throw new InvalidArgumentException('You must use a key larger than 32 bytes for Security::rijndael()');
         }
         $crypto = static::engine();
@@ -174,7 +174,7 @@ class Security
             $hmacSalt = static::$_salt;
         }
         // Generate the encryption and hmac key.
-        $key = substr(hash('sha256', $key . $hmacSalt), 0, 32);
+        $key = mb_substr(hash('sha256', $key . $hmacSalt), 0, 32, '8bit');
 
         $crypto = static::engine();
         $ciphertext = $crypto->encrypt($plain, $key);
@@ -192,7 +192,7 @@ class Security
      */
     protected static function _checkKey($key, $method)
     {
-        if (strlen($key) < 32) {
+        if (mb_strlen($key, '8bit') < 32) {
             throw new InvalidArgumentException(
                 sprintf('Invalid key for %s, key must be at least 256 bits (32 bytes) long.', $method)
             );
@@ -219,12 +219,12 @@ class Security
         }
 
         // Generate the encryption and hmac key.
-        $key = substr(hash('sha256', $key . $hmacSalt), 0, 32);
+        $key = mb_substr(hash('sha256', $key . $hmacSalt), 0, 32, '8bit');
 
         // Split out hmac for comparison
         $macSize = 64;
-        $hmac = substr($cipher, 0, $macSize);
-        $cipher = substr($cipher, $macSize);
+        $hmac = mb_substr($cipher, 0, $macSize, '8bit');
+        $cipher = mb_substr($cipher, $macSize, null, '8bit');
 
         $compareHmac = hash_hmac('sha256', $cipher, $key);
         if (!static::_constantEquals($hmac, $compareHmac)) {