aes-gcm-256 php加密 java解密成功 java php有区别!!

我在公司折腾了很久,php加密,java端解密不成功,翻墙后找到了解决问题的关键。

下面是外网答案:

使用 AES GCM 模式的 PHP 和 Java 之间的跨平台加密正在运行。有一些细节可能会阻止你成功。

首先:在 PHP 端,openssl_encrypt 返回一个 base64 编码的密文,当将密文与版本、iv 和标签连接时,该密文再次被 base64 编码。为了避免这种情况,我将 OPENSSL 选项设置为“OPENSSL_RAW_DATA”。

第二:在Java端,标签被附加到密文中,因此“密文|标签”可以直接被使用。

请注意:我的示例只是展示了 PHP 端的加密和 Java 端的解密将如何工作,但可能与您的源代码无关(Java 端特别) - 我懒得采用我的例子: -)

这是 PHP 端的输出:

AES GCM in PHP/Java
ciphertext: djAx/kMbxfJI5Zx7lTWeDbw601cD2wkjBvuKeVBbKOZHll98GstPNfi1xHvyRlBwJDQ6YWvpymsk76kwbBbD0cBsOzzK/tH8UpA=

将密文复制到Java程序并让它运行:

AES GCM in PHP/Java
decryptedtext: The quick brown fox jumps over the lazy dog

您可以在下面找到这两个程序的源代码。安全警告:代码使用固定和硬编码的密钥 - 不要这样做。这些程序没有任何异常处理,仅用于教育目的。

该代码在 PHP > 7.2 和 Java 11+ 上运行。

PHP代码:

<?php
function encrypt($key, $textToEncrypt){
    $cipher = 'aes-256-gcm';
    $iv_len = 12;
    $tag_length = 16;
    $version_length = 3;
    $version = "v01";
    $iv = openssl_random_pseudo_bytes($iv_len);
    $tag = ""; // will be filled by openssl_encrypt
    $ciphertext = openssl_encrypt($textToEncrypt, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag, "", $tag_length);
    $encrypted = base64_encode($version.$iv.$ciphertext.$tag);
    return $encrypted;
}

echo 'AES GCM in PHP/Java' . PHP_EOL;
// ### security warning: never use hardcoded keys in source ###
$key = '12345678901234567890123456789012';
$plaintext = 'The quick brown fox jumps over the lazy dog';
$ciphertext = encrypt($key, $plaintext);
echo 'ciphertext: ' . $ciphertext . PHP_EOL;
?>

Java代码:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;

public class SO_final {
    public static void main(String[] args) throws NoSuchPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        System.out.println("AES GCM in PHP/Java");
        // https://stackoverflow.com/questions/65001817/aes-gcm-in-php-java
        String ciphertext = "djAx/kMbxfJI5Zx7lTWeDbw601cD2wkjBvuKeVBbKOZHll98GstPNfi1xHvyRlBwJDQ6YWvpymsk76kwbBbD0cBsOzzK/tH8UpA=";
        // ### security warning: never use hardcoded keys in source ###
        byte[] key = "12345678901234567890123456789012".getBytes(StandardCharsets.UTF_8);
        String decryptedtext = decryptGcmBase64(key, ciphertext);
        System.out.println("decryptedtext: " + decryptedtext);
    }

    public static String decryptGcmBase64(byte[] key, String ciphertextBase64) throws
            NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
            InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
        byte[] ciphertextComplete = Base64.getDecoder().decode(ciphertextBase64);
        // split data
        // base64 encoding $encrypted = base64_encode($version.$iv.$ciphertext.$tag);
        byte[] version = Arrays.copyOfRange(ciphertextComplete, 0, 3); // 3 bytes
        byte[] iv = Arrays.copyOfRange(ciphertextComplete, 3, 15); // 12 bytes
        byte[] ciphertextWithTag = Arrays.copyOfRange(ciphertextComplete, 15, ciphertextComplete.length);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * 8, iv);
        Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");//NOPadding
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
        return new String(cipher.doFinal(ciphertextWithTag), StandardCharsets.UTF_8);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值