【问题标题】:java encryption aes value and javascript encryption value does not matchjava加密aes值和javascript加密值不匹配
【发布时间】:2018-01-09 18:30:48
【问题描述】:

我有 java 代码,可以为我生成 aes 加密代码,现在我正在尝试使用 crypto-js 在 javascript 上使用它,但是两个代码都提供了不同的密钥,我不知道为什么以及如何获得相同的密钥,这是我的代码

public static String encrypt(String text, byte[] iv, byte[] key)throws Exception{ 

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
    System.out.println("KEY SPECCCC: "+keySpec); 
    IvParameterSpec ivSpec = new IvParameterSpec(iv); 
    cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec); 
    byte [] results = cipher.doFinal(text.getBytes("UTF-8")); 
    BASE64Encoder encoder = new BASE64Encoder(); 
    return encoder.encode(results); 
} 

JavaScript 代码

  require(["crypto-js/core", "crypto-js/aes"], function (CryptoJS, AES) {
        ciphertext = CryptoJS.AES.encrypt(JSON.stringify(jsondata),
                        arr.toString(),arr.toString());
  });

字符串转为 utf-8

var utf8 = unescape(encodeURIComponent(key));
var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.push(utf8.charCodeAt(i));
}

【问题讨论】:

  • 如果您只使用对称加密,您需要在服务器和客户端使用完全相同的密钥。如果您将加密密钥从服务器发送到客户端或其他方式,您需要加密您的对称加密密钥。最简单的方法是使用 TLS。如果你使用 TLS,那么数据和密钥都是加密的,所以你不需要自己加密。这不提供任何安全性,只是有点混淆。您应该阅读:nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/…
  • 您的代码不完整。您能否展示如何在 Java 和 JS 中解码您的密钥和 IV 以及实际值?
  • IV 必须是不可预测的(阅读:随机)。不要使用静态 IV 或与密钥相同的值,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定之前发送相同消息前缀的时间。 IV 不是秘密,因此您可以将其与密文一起发送。通常,它只是简单地添加到密文中,并在解密之前被切掉。

标签: javascript java encryption aes cryptojs


【解决方案1】:

Java 代码生成加密字符串,JavaScript 也生成相同的加密字符串,以下代码有效!

(function (CryptoJS) {
    var C_lib = CryptoJS.lib;
    // Converts ByteArray to stadnard WordArray.
    // Example: CryptoJS.MD5(CryptoJS.lib.ByteArray ([ Bytes ])).toString(CryptoJS.enc.Base64);
    C_lib.ByteArray = function (arr) {
        var word = [];
        for (var i = 0; i < arr.length; i += 4) {
            word.push (arr[i + 0] << 24 | arr[i + 1] << 16 | arr[i + 2] << 8 | arr[i + 3] << 0);
        }
        return C_lib.WordArray.create (word, arr.length);
    };
})(CryptoJS);


var IVstring = CryptoJS.lib.ByteArray(your IV bytearray).toString(CryptoJS.enc.Base64);
var keystring = CryptoJS.lib.ByteArray(your KEY bytearray).toString(CryptoJS.enc.Base64);
var text = 'texttobeencrypted';
var key = CryptoJS.enc.Base64.parse(keystring);
var iv  = CryptoJS.enc.Base64.parse(IVstring);
var encrypted = CryptoJS.AES.encrypt(text, key, {iv: iv});
console.log(encrypted.toString());

已编辑:删除了危险的第三方资源引用。

【讨论】:

  • 警告,在处理敏感数据时不要包含第三方脚本。上面粗心的链接引用可能会单独鼓励 mydashpay 的开发人员链接到该资源,导致最近大约 50 万个 dash 被盗。 twitter.com/Dashpay/status/1149552764923465735
【解决方案2】:

首先,即使您的代码工作得很好,您也无法正确解密它,因为当您在 Java 中创建 AES 密码时,您使用的是 CBC 密码,并且您正在实施 PKCS5Padding 的填充算法。 因此,您的 java 代码执行以下操作; 当它获得输入时,它首先将其划分为 16 位块,然后如果您的输入未划分为 16 个整体,则将填充提醒以填充具有相同数量的提醒的块。您可以通过以下内容了解我的意思图片。

所以它将在 java 端使用填充密码进行加密,但在 Javascript 部分中,您既没有声明 Aes 将使用哪种类型的模式,也没有声明它应该使用哪种类型的 Padding。因此,您应该将这些值添加到您的代码中。您可以搜索以下代码部分。

                        mode:CryptoJS.mode.CBC,
                        padding: CryptoJS.pad.Pkcs7

关于它发生的不同密钥,因为您将 Byte[] 发送到您的 Encrypt 方法,然后在创建密钥时使用这个未知的 Byte[]。您没有提到为什么您的加密方法将用于您的程序,但您应该在这两种方法中以相同的方式创建“字节 [] 密钥”。例如,您可以参考以下代码作为生成该代码的示例,但它不是生成密钥的安全方式我刚刚添加它是为了向您展示我意思是您应该以相同的方式生成两个密钥。

    //DONT USE THIS IMPLEMENTATION SINCE IT IS NOT SAFE!
    byte[] key = (username + password).getBytes("UTF-8");

【讨论】:

  • CryptoJS 默认使用 CBC 模式和 PKCS#7 填充。问题是“密钥”可能是 CryptoJS 将其视为密码并从中派生密钥的字符串。
猜你喜欢
  • 2013-07-20
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多