CryptoJS 和 openssl_decrypt 不产生相同的结果

如何解决CryptoJS 和 openssl_decrypt 不产生相同的结果

我正在尝试在 PHP 和 JavaScript 上使用字符串实现 AES 256 位加密。对于 jasvascript,我使用了 CryptoJS 和 PHP,我使用 openssl_decrypt/enecrypt。

下面是JS中的加解密代码

JavaScript

function aes_encrypt(str_to_encrypt){
  if(str_to_encrypt==null)
   return "";

   var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
   var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");


  var encrypted = CryptoJS.AES.encrypt(str_to_encrypt,key,{'mode': CryptoJS.mode.CBC,iv: iv});
  var encryptedString = encrypted.toString();
  return  encryptedString;
}

function aes_decrypt(str_to_decrypt){
  if(str_to_decrypt==null)
   return "";

   var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
   var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");

  var decrypted = CryptoJS.AES.decrypt(str_to_decrypt,iv: iv });
  var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
  return decryptedString;
}

PHP 中的代码

PHP

class Crypto_AES256
{
  public $key = "0123456789abcdef0123456789abcdef";
  public $iv =  "abcdef9876543210abcdef9876543210";


  public  $encrypt_method = 'AES-256-CBC';

  function __construct ()
  {
     $this->key = hex2bin($this->key);
     $this->iv = hex2bin($this->iv);
    
  }

  public function encrypt ( $string )
  {
    if ( $encrypted = base64_encode( openssl_encrypt ( $string,$this->encrypt_method,$this->key,$this->iv ) ) )
    {
      return $encrypted;
    }
    else
    {
      return false;
    }
  }
  public function decrypt ($string)
  {

    if ( $decrypted = openssl_decrypt ( base64_decode ( $string ),$this->iv ) )
    {
      return $decrypted;
    }
    else
    {
      return false;
    }
  }
}

但是JavaScript端的加密结果与PHP不同,我需要在JavaScript和PHP上产生相同的加密和加密结果。可能是什么问题。

解决方法

两个代码在两个方面不同:

  • PHP 代码采用 AES-256,但由于只使用了 16 字节的密钥(由于十六进制解码),PHP 会自动用 0 值将其填充到 32 字节的长度。在 CryptoJS 代码中,密钥长度决定了模式,因此应用了 AES-128。为了使两个代码产生相同的结果,密钥必须在 CryptoJS 代码中扩展为类似于 PHP 代码,或者必须在 PHP 代码中使用 AES-128。
  • PHP代码中,openssl_encrypt()返回的是默认Base64编码的密文,所以密文目前是Base64编码的两次。因此删除显式 base64_encode() 或使用 OPENSSL_RAW_DATA 作为第四个参数,以便返回原始数据。 openssl_decrypt() 也是如此。

修复这些问题后,两个代码在我的机器上提供相同的密文。请注意,静态 IV 是不安全的(另请参阅评论),但您可能只是出于测试目的才这样做。


示例:以下代码使用您未修改的 CryptoJS 代码,即 AES-128:

function aes_encrypt(str_to_encrypt){
    if(str_to_encrypt==null)
        return "";

    var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
    var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");

    var encrypted = CryptoJS.AES.encrypt(str_to_encrypt,key,{'mode': CryptoJS.mode.CBC,iv: iv});
    var encryptedString = encrypted.toString();
    return  encryptedString;
}

function aes_decrypt(str_to_decrypt){
    if(str_to_decrypt==null)
        return "";

    var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
    var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");

    var decrypted = CryptoJS.AES.decrypt(str_to_decrypt,iv: iv });
    var decryptedString = decrypted.toString(CryptoJS.enc.Utf8);
    return decryptedString;
}

var ciphertext = aes_encrypt('The quick brown fox jumps over the lazy dog');
var decrypted = aes_decrypt(ciphertext);
console.log(ciphertext.replace(/(.{56})/g,'$1\n'));
console.log(decrypted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

如果应用了 AES-128-CBC 并且 OPENSSL_RAW_DATA 标志设置为 openssl_encrypt()openssl_decrypt() 中的第 4 个参数,PHP 代码将返回相同的密文。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?