【问题标题】:Java AES Encrypt in Javascript using CryptoJS使用 CryptoJS 在 Javascript 中进行 Java AES 加密
【发布时间】:2016-08-05 19:51:00
【问题描述】:

我正在尝试使用 Javascript 和 CryptoJS 复制 Java 应用程序中使用的加密。我不太确定我应该如何复制 SecretKeySpec,因为 CryptoJS 似乎需要一个字符串作为密钥。

这是我需要在 JS 中复制的 Java 加密代码:

public byte[] encrypt(byte[] origin)
    {
        String key = "testkey";
        SecretKeySpec sks = new SecretKeySpec(convertAESKey(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = new byte[16];
        cipher.init(Cipher.ENCRYPT_MODE, sks, new IvParameterSpec(iv));
        return cipher.doFinal(origin);
    }

private byte[] convertAESKey(String key)
   {
        byte[] keyBytes;
        keyBytes = key.getBytes("UTF-8");
        byte[] keyBytes16 = new byte[16];
        System.arraycopy(keyBytes, 0, keyBytes16, 0,
                Math.min(keyBytes.length, 16));
        return keyBytes16;
    }
}

到目前为止我的 JS 代码:

var iv = new Uint8Array(16);
var key = "testkey";

var encrypted = CryptoJS.AES.encrypt(
    someByteArray,
    key,
    {
        iv: iv,
        mode: CryptoJS.mode.CBC
    }
);

另外,cipher 的最终输出是一个加密的字节数组。 CryptoJS 的最终输出似乎是一个带有密文的对象。有没有办法将输出作为字节数组?

我现在唯一能想到的是将加密的响应转换为字符串,然后将其转换为字节数组,但这似乎与 Java 加密的输出不匹配。

【问题讨论】:

  • 使用开箱即用的加密对我来说没问题。问题是复制 Java 加密,因为当前的实现是客户端(Java)到服务器(Java),我需要将它设置为客户端(Javascript)到服务器(Java)。服务器代码无法更改,因此能够准确匹配加密非常重要。

标签: javascript java encryption cryptography cryptojs


【解决方案1】:

CryptoJS 默认不处理Uint8Array,所以我不会使用它,而是使用默认的WordArray 来表示二进制数据。

var iv = CryptoJS.lib.WordArray.create([0, 0, 0, 0]);
var key = "testkey";

key = CryptoJS.enc.Utf8.parse(key);
for (var i = key.words.length; i < 4; i++) {
    key.words[i] = 0;
}
key.sigBytes = 16;
key.clamp();

var encrypted = CryptoJS.AES.encrypt(
    someByteArray,
    key,
    {
        iv: iv,
        mode: CryptoJS.mode.CBC
    }
);
console.log(encrypted.ciphertext.toString(CryptoJS.enc.Hex));

这将给出一个十六进制字符串,可以很容易地与 Java 生成的密文进行比较。


这段代码不是很安全:

  • IV 必须是不可预测的(阅读:随机)。不要使用静态 IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定之前发送相同消息前缀的时间。 IV 不是秘密,因此您可以将其与密文一起发送。通常,它只是简单地添加到密文中,并在解密之前被切掉。

  • 密钥必须是随机的(阅读:看起来像随机噪声)。文本看起来不是随机的,如果(错误地)使用密码作为密钥,您会严重降低安全性。如果您有密码,那么您需要使用 PBKDF2、bcrypt、scrypt 或 Argon2 等具有高迭代次数/成本因素的东西从中派生密钥。

  • 您应该验证您的密文以检测(恶意)操纵。如果您不这样做,那么这可能容易受到填充预言机攻击。身份验证可以使用经过身份验证的操作模式(如 GCM 或 EAX)来完成,也可以使用具有强 MAC 的 encrypt-then-MAC 方案(如 HMAC-SHA256)来完成。

【讨论】:

  • 谢谢你,我正在尝试使用它,我得到“未定义不是对象(评估'e.length')”
  • 你还没有说someByteArray是什么,所以我假设它要么是一个字符串,要么是一个WordArray。如果是Uint8Array,则可以包含 lib-typedarrays.js 文件以获得支持。
  • 我已经尝试包含 lib-typedarrays.js 文件,但仍然收到相同的错误。我尝试编码的数组是 Uint8Array[120, 156, 203, 72, 205, 201, 201 , 7, 0, 6, 44, 2, 21]
  • 您在此处显示的数组太短而不能成为有效的密文。无论如何,您可能需要自己将其从 Uint8Array 转换为 WordArray。包含 lib-typedarrays.js 然后用someByteArray = CryptoJS.lib.WordArray.create(someByteArray); 转换
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多