>백엔드 개발 >PHP 튜토리얼 >PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

不言
不言원래의
2018-07-04 14:10:382223검색

이 글에서는 주로 PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법을 소개합니다. 이제 특정 참고 가치가 있으므로 필요한 친구들이 참고할 수 있습니다.

openssl을 사용하여 PHP7에서 mcrypt를 대체하세요. 1

PHP 개발에서는 mcrypt 관련 기능을 사용하여 AES 암호화 및 복호화 작업을 쉽게 수행할 수 있습니다. 그러나 PHP7.1에서는 mcrypt 확장이 지원되지 않으므로 다른 구현을 찾아야 합니다. mcrypt를 openssl로 바꾸는 것은 이미 마이그레이션 매뉴얼에서 지적되었지만 구체적인 예는 제공되지 않습니다. 대부분의 시나리오를 대체할 수 있는 많은 예가 온라인에 있지만 자세한 내용은 설명되지 않습니다. 마찬가지로, 단순히 온라인 예제를 사용하면 특정 코드 시나리오에서 코드 교체 전후에 호환성 문제가 발생할 수 있습니다. 아래에서 구체적인 코드와 이유에 대해 이야기해 보겠습니다.

먼저 대체 코드를 직접 제공한 후, 코드에서 문제를 분석합니다. (이 글에서 분석한 알고리즘은 AES-128-CBC입니다.)

대체 예시

이 예시에서는 주로 padding의 차이로 인해 mcrypt를 사용하는 두 가지 방법을 보여줍니다. (padding에 대해서는 아래에서 설명하겠습니다.) . 전체 암호화 및 암호 해독 과정에서 더 완전한 코드는 자동으로 채우기 및 채우기 제거를 구현하고 간단한 코드는 채우기를 직접 무시하지만 두 방법 모두 실제 개발(7.1 이전 버전)에서는 정상적으로 실행될 수 있으므로 권장됩니다. 패딩을 추가합니다. 다음 구체적인 예를 참조하세요.

  1. 패딩이 없는 mcrypt

  • mcrypt 암호화:

      $key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; 
      $iv = 'aaaaaaaaaaaaaaaa';
      $data = 'dataString';
    
      $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
      mcrypt_generic_init($cipher, $key, $iv);
      $cipherText256 = mcrypt_generic($cipher, $data);
      mcrypt_generic_deinit($cipher);
    
      return bin2hex($cipherText256);
  • 동일한 기능에 대한 openssl 암호화 코드:

      $key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; 
      $iv = 'aaaaaaaaaaaaaaaa';
      $data = 'dataString';
    
      $data = $data . str_repeat("\x00", 16 - (strlen($data) % 16)); // 双引号可以解析asc-ii码\x00
    
      return bin2hex(openssl_encrypt($data, "AES-256-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv));
  • mcrypt with padding

    • 엠크립트 암호화 :

        $key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; 
        $iv = 'aaaaaaaaaaaaaaaa';
        $data = 'dataString';
      
        // 填充(移除填充反着移除即可)
        $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
      
        $pad = $block - (strlen($data) % $block);
        if ($pad <= $block) {
            $char = chr($pad);
            $data .= str_repeat($char, $pad);
        }
      
        $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, &#39;&#39;, MCRYPT_MODE_CBC, &#39;&#39;);
        mcrypt_generic_init($cipher, $key, $iv);
        $cipherText256 = mcrypt_generic($cipher, $data);
        mcrypt_generic_deinit($cipher);
      
        return bin2hex($cipherText256);
    • 동일한 기능에 대한 openssl 암호화 코드:

        $key = &#39;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&#39;; 
        $iv = &#39;aaaaaaaaaaaaaaaa&#39;;
        $data = &#39;dataString&#39;;
      
        return bin2hex(openssl_encrypt($data, &#39;AES-256-CBC&#39;, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv));

    위 예제는 모두 성공적으로 실행됩니다. 첫 번째 예제(패딩을 사용하지 않고 openssl에서 패딩을 사용함)와 두 번째 예제(패딩 사용, openssl에서는 패딩이 사용되지 않습니다. 교체 전과 교체 후 출력이 동일하며 호환성 문제가 없습니다. 코드의 다양한 충전 방법에 따라 다양한 교체 솔루션을 선택할 수 있지만 세 가지 세부 사항을 설명해야 합니다

    1. 왜 충전이 있나요?

    2. openssl로 교체한 후 알고리즘 이름이 다른 이유는 무엇인가요?

    다음은 채우기알고리즘에 대한 자세한 분석입니다.

    Padding

    패딩이 있는 이유는 암호화 알고리즘에서 시작됩니다. AES-128-CBC 알고리즘에서는 암호화할 문자열이 길이가 16바이트마다 세그먼트로 분할되고 단계별로 계산되므로 16바이트 미만의 세그먼트가 채워지기 때문입니다. 따라서 두 가지 유형의 예제가 제공됩니다. 하나는 기본 채우기를 사용하는 것이고 다른 하나는 독립적 채우기를 사용하는 것입니다. openssl로 대체할 때 패딩 구성표를 선택하려면 mcrypt 및 openssl의 기본 및 자율 패딩에 대한 이해가 필요합니다.

    • mcrypt는 기본적으로 채워져 있습니다

      php 소스코드를 보면 기본적으로 x00으로 채워져 있는 것을 볼 수 있는데, 실제로는 x00에서 16비트 빈 문자열이 먼저 적용되는 것을 소스코드에서 확인할 수 있으므로 실제로는 초기화 시 각 바이트가 <code>x00라고 할 수 있습니다. 패딩은 없지만 원래 x00이므로 기본 패딩을 사용하여 얻은 암호화된 문자열은 다음 형식을 따릅니다.
      mcrypt는 기본적으로 패딩됩니다.x00进行填充,事实上,并非是以x00进行填充,从源码中可以发现,首先申请了一个16位的空字符串,所以初始化时每位字节均为x00, 实际上可以说其中并没有填充,只是它本来就是x00 ,使用默认填充得到的加密字符串会是如下形式:
      PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

      所以解密时则要移除多余的x00。当然也可以懒一点,不移除x00。 因为在php中字符串"stringx00"与字符串"string"除了长度不一样外,其他表现均一致,所以看起来并无区别,如下代码:

         // 尾部包含若干个`\x00` 均可功输出true
         if ("string\x00" == "string") { // 用双引号可解析\x00
             echo true;
         }

      x00填充后的示例:(请注意字符串的长度,由此可见用x00填充会影响长度)
      PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

    • mcrypt自主填充

      填充算法需以如下算法进行:

      • 加入填充

          /**
           * 填充算法
           * @param string $source
           * @return string
           */
          function addPKCS7Padding($source)
          {
              $source = trim($source);
              $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        
              $pad = $block - (strlen($source) % $block);
              if ($pad <= $block) {
                  $char = chr($pad);
                  $source .= str_repeat($char, $pad);
              }
              return $source;
          }

        加入填充后字符串实际上如下形式:
        PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

      • 移除填充

          /**
           * 移去填充算法
           * @param string $source
           * @return string
           */
          function stripPKSC7Padding($source)
          {
              $source = trim($source);
              $char = substr($source, -1);
              $num = ord($char);
              if ($num == 62) return $source;
              $source = substr($source, 0, -$num);
              return $source;
          }
    • openssl默认填充

      其默认方式与标准的mcrypt的自主填充方式一致,所以在第二个示例中,对于使用了如上的填充算法后, 可直接使用openssl_encrypt替换,不会产生兼容问题。填充后的加密字符串如下形式:

      PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개

      需注意的是在openssl_encryptopenssl_decrypt따라서 해독할 때 추가 x00를 제거해야 합니다. 물론 게으른 상태에서 x00을 제거하지 않을 수도 있습니다. 왜냐하면 php에서는 "stringx00"이라는 문자열과 "string"이라는 문자열이 길이가 다른 것 외에는 성능이 같기 때문에 차이가 없는 것 같습니다. 다음 코드는

         // if we want to manage our own padding
        $padded_data = $data . str_repeat(&#39; &#39;, 16 - (strlen($data) % 16));
        $encrypted = openssl_encrypt($padded_data, $method,     $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
        $output = openssl_decrypt($encrypted, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
        var_dump(rtrim($output));
    • x00 입니다. 예: (문자열 길이에 주의하세요. x00로 패딩하면 길이에 영향을 미치는 것을 볼 수 있습니다.)
      PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개
    • 🎜mcrypt의 독립 패딩 🎜🎜패딩 알고리즘은 다음 알고리즘에 따라 수행되어야 합니다. 🎜🎜
        🎜🎜Add padding🎜rrreee🎜padding을 추가한 후 문자열은 실제로 다음과 같습니다.
        표준 패딩🎜🎜🎜🎜패딩 제거🎜rrreee🎜🎜🎜🎜openssl 기본 패딩🎜🎜기본 방법은 표준 mcrypt 자율 패딩 방법과 일치하므로 두 번째 예에서는 위의 패딩 알고리즘을 사용한 후 호환성 문제 없이 openssl_encrypt로 직접 대체할 수 있습니다. 패딩된 암호화 문자열은 다음 형식입니다. 🎜🎜 🎜🎜🎜패딩 및 패딩 제거 기능은 openssl_encryptopenssl_decrypt에 내장되어 있으므로 패딩을 독립적으로 구현해야 하는 경우가 아니면 직접 사용할 수 있습니다. , 고려할 필요가 없습니다. Filling🎜🎜🎜🎜🎜openssl 자율 채우기🎜

        openssl_encrypt提供了option参数以支持自主填充,但在查阅php源码中openssl的测试用例代码才找到正确用法:

           // if we want to manage our own padding
          $padded_data = $data . str_repeat(&#39; &#39;, 16 - (strlen($data) % 16));
          $encrypted = openssl_encrypt($padded_data, $method,     $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
          $output = openssl_decrypt($encrypted, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
          var_dump(rtrim($output));

        (备注:如上,OPENSSL_ZERO_PADDING 并非是为0填充的意思)
        由此,我们就可以解释,在第一个示例中openssl_encrypt之前加入了自主点充\x00的代码原因了

    从以上的加、解密针对填充逻辑不同,针对上文中的示例可以很好地解释:

    • 示例1:
      mcrypt加密时未使用填充,故以\x00进行了填充,所以在替换成openssl,需要自主实现\x00填充。

    • 示例2:
      mcrypt加密时使用了标准的填充,同时openssl的填充方式也为PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개,故直接使用即可。

    分析到这,可以发现,无论是何种填充策略都需注意在加密时加入填充,在解密时则必须要移除填充。至此,上文中示例中的填充相关则分析完成了,接下来我们再看看如何选择替换后的算法。

    选择算法

    在以上的示例中,有一个问题在于,mcrypt中的AES-128-CBC算法,在openssl中怎么替换成了AES_256?
    关于这一点, 我也未找到合理的解释,查看源码一时半会也没找到原因(能力有限~),但通过以下资料,还是完成了功能

    • openssl 解密 mcrypt AES 数据不兼容问题

    • Convert mcrypt_generic to openssl_encrypt Ask Question

    若是有同学找到原因,欢迎给我留言,谢谢。

    总结

    对于使用mcrypt AES 进行加密密的部分,若是在替换过程中问题, 可以从算法替换或填充这两方面着手考虑下。同时还是一必须满足的条件是根据不同的填充方式选择, 替换最重要的就要考虑兼容问题,保证替换后不发生任何改变。 虽然只是只是有细微的差别----尾部几个字符串的不同,但若是在多平台中同时进行修改也是一件麻烦事,但变动越少风险越小。

    本文只是针对AES算法进行了简单说明,对于其他算法是否适用还有待研究。

    以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

    相关推荐:

    PHP Excel导入数据到MySQL数据库的方法

    wordpress添加文章固定字段的介绍

    위 내용은 PHP7.1에서 mcrypt를 대체하기 위해 openssl을 사용하는 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.