3

node.js と crypto モジュール (サーバー側) と crypto-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

クライアント側コード

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
4

2 に答える 2

5

「パスワード」(パスワードの代わりにキーとして使用されます) には、クライアント側とサーバー側で 2 つの異なるエンコーディングがあります。クライアントでは、16 進数として解析していますが、サーバーでは、そのまま使用されるバイナリ文字列として渡しています。

サーバーで解析する必要があります(現在はAES-256ではなくAES-128です):

pass: new Buffer("0123456789abcdef0123456789abcdef", "hex"),

または、クライアントのエンコーディングを (AES-128 から AES-256 に) 変更します。

pass: CryptoJS.enc.Utf8.parse("0123456789abcdef0123456789abcdef"),

  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 "";
    }
  }

まだセキュリティ上の問題があります:

  • IV は、セマンティック セキュリティを実現するために、同じキーの下ですべての暗号化に対してランダムに選択する必要があります。秘密にする必要はないので、暗号文と一緒に送信するだけでかまいません。それを暗号文の先頭に追加し、復号化する前にスライスするのが一般的です。

  • パディングオラクル攻撃などの攻撃が不可能になるように、暗号文を認証することをお勧めします。これは、GCM や EAX などの認証モード、またはCryptoJS が提供する HMAC-SHA256 などの強力な MAC を使用した暗号化後 MACスキームを使用して実行できます。

于 2016-02-21T09:47:44.983 に答える