首页 > 解决方案 > Android 相当于 PHP 中的 AES-256-CBC-HMAC-SHA256

问题描述

我在 PHP 中完成了以下加密:

openssl_encrypt($data, "AES-256-CBC-HMAC-SHA256", $key, OPENSSL_RAW_DATA, $iv));

我可以在我的 Android 应用程序中以 JSON 格式接收该 $data。

我必须在应用程序中解密该 $data。

我正在使用如下结构:

private static final String engine = "AES";
private static final String crypto = "AES/CBC/PKCS5Padding";
[...]

public byte[] cipher(byte[] data, int mode, String key, String iv2) throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException {        
    SecretKeySpec sks = new SecretKeySpec(key.getBytes(), engine);
    IvParameterSpec iv = new IvParameterSpec(iv2.getBytes());
    Cipher c = Cipher.getInstance(crypto);
    c.init(mode, sks, iv);
    return c.doFinal(data);
}

public byte[] decrypt(byte[] data,  String key, String iv) throws InvalidKeyException,
        NoSuchAlgorithmException, NoSuchPaddingException,
        IllegalBlockSizeException, BadPaddingException,
        InvalidAlgorithmParameterException {
    return cipher(data, Cipher.DECRYPT_MODE,key,iv);
}

所以我用所需的密钥和所需的 iv 调用解密。

但是将引擎定义为“AES”并将加密定义为“AES/CBC/PKCS5Padding”会引发错误,因为它不等同于来自服务器的那个。

另一方面,将加密函数与该密码函数一起使用并随后对其进行解密确实有效,因为加密和解密是使用相同的密钥 iv、引擎和加密完成的。

哪个是 PHP 中 AES-256-CBC-HMAC-SHA256 的引擎和加密等效项?

标签: javaphpandroidencryption

解决方案


我正在回答你的问题,但我很困惑......你会看到:-)。

首先,我设置了一个带有 2 个加密/解密函数的简单 PHP 程序,它们使用以下算法:

$algorithm = "aes-256-cbc-hmac-sha256";
$algorithm2 = "aes-256-cbc";

代码:

<?php
// https://stackoverflow.com/questions/63135041/android-equivalent-to-aes-256-cbc-hmac-sha256-in-php
$key = "!mysecretkey#9^5usdk39d&dlf)03sL";
$iv = "Cfq84/46Qjet3EEQ1HUwSg==";
$plaintext = "The quick brown fox jumps over the lazy dog";

$algorithm = "aes-256-cbc-hmac-sha256";
echo 'encryption with algorithm: ' . $algorithm . PHP_EOL;
// encryption
$ciphertext = openssl_encrypt($plaintext, $algorithm, $key, $options = OPENSSL_RAW_DATA, base64_decode($iv));
echo 'ciphertext : ' . base64_encode($ciphertext) . PHP_EOL;
// decryption
$decryptedtext = openssl_decrypt($ciphertext, $algorithm, $key, $options = OPENSSL_RAW_DATA, base64_decode($iv));
echo 'cbc-256-hmac decrypt : ' . $decryptedtext . PHP_EOL . PHP_EOL;

$algorithm2 = "aes-256-cbc";
echo 'encryption with algorithm: ' . $algorithm2 . PHP_EOL;
$ciphertext2 = openssl_encrypt($plaintext, $algorithm2, $key, $options = OPENSSL_RAW_DATA, base64_decode($iv));
echo 'ciphertext2: ' . base64_encode($ciphertext2) . PHP_EOL;
// decryption
$decryptedtext2 = openssl_decrypt($ciphertext2, $algorithm2, $key, $options = OPENSSL_RAW_DATA, base64_decode($iv));
echo 'cbc-256 decrypt      : ' . $decryptedtext2 . PHP_EOL;
?>

两者都做得很好但是 - 这让我感到困惑 - 给出相同的输出(这里用 Base64 编码):

encryption with algorithm: aes-256-cbc-hmac-sha256
ciphertext : sdFQ/X0YdAlyTe8ICtQSb3aHRGzsAdyXRlUGdocGZS9sckqa2seeYaVD10vYu5wV
cbc-256-hmac decrypt : The quick brown fox jumps over the lazy dog

encryption with algorithm: aes-256-cbc
ciphertext2: sdFQ/X0YdAlyTe8ICtQSb3aHRGzsAdyXRlUGdocGZS9sckqa2seeYaVD10vYu5wV
cbc-256 decrypt      : The quick brown fox jumps over the lazy dog

在使用算法的简单Java解密方法中使用密文字符串作为输入

AES/CBC/PKCS5Padding

加密消息成功解密。因此,也许我们的一位“加密专家”能够“指出”为什么两种不同的算法会给出相同的输出。

这是Java结果:

decryptedtext: The quick brown fox jumps over the lazy dog

和Java代码:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class Main {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        System.out.println("https://stackoverflow.com/questions/63135041/android-equivalent-to-aes-256-cbc-hmac-sha256-in-php");

        String key = "!mysecretkey#9^5usdk39d&dlf)03sL";
        String iv = "Cfq84/46Qjet3EEQ1HUwSg==";
        String ciphertext = "sdFQ/X0YdAlyTe8ICtQSb3aHRGzsAdyXRlUGdocGZS9sckqa2seeYaVD10vYu5wV";

        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(Base64.getDecoder().decode(iv));
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] decryptedtextByte = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
        String decryptedtext = new String(decryptedtextByte);
        System.out.println("decryptedtext: " + decryptedtext);
    }
}

推荐阅读