AES 256加密Java到PHP

发布于 2025-01-22 12:59:10 字数 1513 浏览 2 评论 0 原文

我有一个基于数据加密AES256的源代码,但是此代码是Java,我想转换为PHP,我正在尝试此示例,但不正确。 PHP中的示例使用随机IV,但我要求它们为零。

private String encryptAES(String strToEncrypt) {
    
    try {
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
        return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
    } catch (Exception e) {
        log.error("Error while encrypting: " + e.toString());
    }
    return null;
}

我尝试了

function encrypt($data){
    $method = "AES-256-CBC";
    $salt = 'vzQ8p=z';
    $key =  '!5&3usT';

    $iv = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
    $chars = array_map("chr", $iv);
    $IVbytes = join($chars);

    $hash = openssl_pbkdf2($key,$salt,'256','65536', 'sha1');
    $encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
    return base64_encode($encrypted);
}

I have a source code for data encryption aes256 based, but this code is Java and I want transform to PHP, I was trying with this example, but isn't correct. The examples in PHP use random IV but I require them to be zeros.

private String encryptAES(String strToEncrypt) {
    
    try {
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
        return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
    } catch (Exception e) {
        log.error("Error while encrypting: " + e.toString());
    }
    return null;
}

I tried this

function encrypt($data){
    $method = "AES-256-CBC";
    $salt = 'vzQ8p=z';
    $key =  '!5&3usT';

    $iv = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
    $chars = array_map("chr", $iv);
    $IVbytes = join($chars);

    $hash = openssl_pbkdf2($key,$salt,'256','65536', 'sha1');
    $encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
    return base64_encode($encrypted);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

独孤求败 2025-01-29 12:59:10

最明显的缺陷是,尽管两者都使用PBKDF2,但您将HMAC-SHA2-256用作Java代码中的PRF(即伪随机函数,即Hash算法),而SHA1则用作PHP中的PRF。当然,这将产生两个不同的键(就像您通过SHA1和SHA2-256运行相同的字符串一样),因此您的文本将被加密到两个不同的密文,并且在每种情况下都需要相应的键来解密它。

您还需要检查您在两种情况下都使用相同的密码和填充方案。您在PHP中明确指定AES-256-CBC,但没有指定填充;您可以在Java中明确指定AES/CBC/PKCS5,但不是AES密钥大小。在实践中,我怀疑这是正确的(通过256位键时,Java可能会生成256位AES密钥,而PHP openssl_encrypt 使用 AES-256-CBC 可能会生成256位键。默认情况下使用PKCS5),但您不应该留下任何未指定的东西。

其他想法:

  • 为什么使用PBE/PBKDF2?除非 secret_key / $ key 是一个用户途径的值,否则没有理由每次都这样做。这是浪费CPU时间。
  • 如果“键”实际上是硬编码(如示例中的),那甚至更糟。在硬编码的“键”(密码)和盐上运行PBKDF2不仅是完全毫无意义的,而且使用硬编码键(或键的硬编码派生过程)是一个可怕的主意系统,任何看到您的代码或反复编译的人都会知道该系统曾经触摸的每个数据都已加密。
  • 使用欧洲央行而不是CBC完全糟糕,但确实仍然非常糟糕。如果您实际上需要使用始终为零的IV,那么有人搞砸了。
  • 此加密没有完整性保护。 CBC中的轻弹攻击并不像Steam Ciphers或类似流的操作模式那样糟糕,但它们仍然是一个真正的威胁。您需要通过使用身份验证的加密(并在解密时验证身份验证标签)来保护消息完整性。
  • 没有查看解密代码,我们无法确定这是否是问题,但是PKCS5可能容易受到填充甲骨文攻击的影响。取决于解密过程如何处理错误的填充方式,攻击者可以尝试解密相同的消息(加上攻击者选择的修改)多次可能能够解密消息而不知道键本身(尽管通常这是一个毫无意义的点您将密钥编码)。

The most obvious flaw is that while both use PBKDF2, you're using HMAC-SHA2-256 as the PRF (pseudo-random function, i.e. hash algorithm) in the Java code, and SHA1 as the PRF in the PHP. That will of course produce two different keys (just as if you ran the same string through SHA1 and SHA2-256), so your text will get encrypted to two different ciphertexts and need the corresponding key in each case to decrypt it.

You also need to check that you're using the same cipher and padding scheme in both cases. You explicitly specify AES-256-CBC in PHP, but not the padding; you explicitly specify AES/CBC/PKCS5 in Java, but not the AES key size. In practice I suspect that it's correct here (Java probably generates a 256-bit AES key when passed a 256-bit KeySpec, and PHP openssl_encrypt with AES-256-CBC probably uses PKCS5 by default), but you shouldn't leave anything unspecified.

Other thoughts:

  • Why use PBE/PBKDF2? Unless the SECRET_KEY/$key is a user-memorized value, there's no reason to do this every time; it's a waste of CPU time.
  • If the "key" is actually hardcoded (as it is in the example), that's even worse. Not only is it totally pointless to run PBKDF2 on a hardcoded "key" (password) and salt, it's a terrible idea to use a hardcoded key (or hardcoded derivation process for a key) because everything will get encrypted with that same key on every system, and anybody who sees your code or decompiles the app will know what key every bit of data this system ever touched was encrypted with.
  • As @foreverska's comment points out, you should never reuse an IV, and should definitely never hardcode one. Using a zero IV is not quite as bad as outright using ECB instead of CBC, but it's still very bad indeed. If you actually need to use an always-zero IV, somebody has screwed up very badly.
  • There's no integrity protection on this encryption. Bit-flipping attacks in CBC aren't quite as bad as in steam ciphers or stream-like modes of operation, but they're still a real threat. You need to protect the message integrity, ideally by using authenticated encryption (and verifying the authentication tag when decrypting).
  • Without looking at the decryption code we can't say for sure if this is a problem, but PKCS5 is potentially vulnerable to padding oracle attacks. Depending on how exactly the decryption process handles incorrect padding, an attacker who can try to decrypt the same message (plus attacker-chosen modification) many times may be able to decrypt the message without knowing the key themselves (though that's generally a moot point if you hardcode the key).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文