节点crypto与crypto-js加解密的兼容性

Jes*_*lla 3 javascript encryption node.js cryptojs node-crypto

如何使用crypto模块(服务器端)和crypto-js(客户端,react-native)正确加密/解密node.js之间的数据?

注意:我在 react-native 项目中使用了 cryptojs,因此我不能在客户端上使用加密。更换加密服务器端对我来说不是一个选择。

服务端代码:

var Crypto = require("crypto");

var Cipher = {
  pass: "0123456789abcdef0123456789abcdef",
  iv: "0123456789abcdef",
  encript: function (msg) {
    try {
      var cipher = Crypto.createCipheriv("aes-256-cbc", this.pass, this.iv);
      var hash = cipher.update(msg, 'utf8', "hex");
      var hex = hash + cipher.final("hex");
      return hex;
    } catch (err) {
      console.error(err);
      return "";
    }
  },
  decript: function (hex){
    try {
      var decipher = Crypto.createDecipheriv("aes-256-cbc", this.pass, this.iv);
      var dec = decipher.update(hex, "hex", 'utf8');
      return dec + decipher.final('utf8');
    } catch (err) {
      console.error(err);
      return "";
    }
  }
}
Cipher.encript("i have an apple"); // 577267026f88f82ea286baf6bf089acb
Cipher.decript("577267026f88f82ea286baf6bf089acb"); // i have an apple
Run Code Online (Sandbox Code Playgroud)

客户端代码

var CryptoJS = require("crypto-js");
var Cipher = {
  pass: CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef"),
  iv: CryptoJS.enc.Hex.parse("0123456789abcdef"),
  encript: function (msg) {
    try {
      var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
      var json = CryptoJS.AES.encrypt(msg, this.pass, options);
      return json.ciphertext.toString(CryptoJS.enc.Hex);
    } catch (err) {
      console.error(err);
      return "";
    }
  },
  decript: function (hex){
    try {
      // ???????????????????????????????????
      // ???????????????????????????????????

    } catch (err) {
      console.error(err);
      return "";
    }
  }
}

Cipher.encript("i have an apple"); // 405552d9a77ea9e29442057d27cd7aee
Cipher.decript(?????);  // I have no Idea
Run Code Online (Sandbox Code Playgroud)

Art*_* B. 5

您的“密码”(它用作密钥而不是密码)在客户端和服务器端有两种不同的编码。在客户端,您将其解析为十六进制,但在服务器上,您将其作为二进制字符串传递,按原样使用。

您要么需要在服务器上解析它(现在它是 AES-128 而不是 AES-256):

pass: new Buffer("0123456789abcdef0123456789abcdef", "hex"),
Run Code Online (Sandbox Code Playgroud)

或者更改客户端上的编码(从 AES-128 到 AES-256):

pass: CryptoJS.enc.Utf8.parse("0123456789abcdef0123456789abcdef"),
Run Code Online (Sandbox Code Playgroud)
  encript: function (msg) {
    try {
      var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
      var json = CryptoJS.AES.encrypt(msg, this.pass, options);
      return json.ciphertext.toString(CryptoJS.enc.Hex);
    } catch (err) {
      console.error(err);
      return "";
    }
  },
  decript: function (hex){
    try {
      var options = { mode: CryptoJS.mode.CBC, iv: this.iv};
      var json = CryptoJS.AES.decrypt({
        ciphertext: CryptoJS.enc.Hex.parse(hex)
      }, this.pass, options);
      return json.toString(CryptoJS.enc.Utf8);
    } catch (err) {
      console.error(err);
      return "";
    }
  }
Run Code Online (Sandbox Code Playgroud)

您仍然有安全问题:

  • 必须为相同密钥下的每个加密随机选择 IV,以实现语义安全。它不必是秘密的,因此您可以简单地将其与密文一起发送。通常将其添加到密文并在解密之前将其切片。

  • 最好验证您的密文,以便像填充预言机攻击这样的攻击是不可能的。这可以通过像 GCM 或 EAX 这样的认证模式来完成,或者使用具有强 MAC的加密然后 MAC方案,如 CryptoJS 提供的 HMAC-SHA256。