无法使用AES/ECB/PKCS5P将加密方法从Java复制到PHP

无法使用AES/ECB/PKCS5P将加密方法从Java复制到PHP,java,php,encryption,aes,Java,Php,Encryption,Aes,我有以下Java代码 import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import j

我有以下Java代码

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class AESEncryption 
{
    public static final String AES_TRANSFORMATION = "AES/ECB/PKCS5Padding";
    public static final String AES_ALGORITHM = "AES";
    public static final int ENC_BITS = 256;
    public static final String CHARACTER_ENCODING = "UTF-8";

    private static Cipher ENCRYPT_CIPHER;
    private static Cipher DECRYPT_CIPHER;
    private static KeyGenerator KEYGEN; 

    static
    {
        try
        {
            ENCRYPT_CIPHER = Cipher.getInstance(AES_TRANSFORMATION);
            DECRYPT_CIPHER = Cipher.getInstance(AES_TRANSFORMATION);
            KEYGEN = KeyGenerator.getInstance(AES_ALGORITHM);
            KEYGEN.init(ENC_BITS);
        }
        catch(NoSuchAlgorithmException | NoSuchPaddingException e) 
        {
            e.printStackTrace();
        }
    }

    /**
     * This method is used to encode bytes[] to base64 string.
     * 
     * @param bytes
     *            : Bytes to encode
     * @return : Encoded Base64 String
     */

    private static String encodeBase64String(byte[] bytes) 
    {
         return new String(java.util.Base64.getEncoder().encode(bytes));
    }

    /**
    * This method is used to decode the base64 encoded string to byte[]
    * 
    * @param stringData
    *            : String to decode
    * @return : decoded String
    * @throws UnsupportedEncodingException
    */

    private static byte[] decodeBase64StringTOByte(String stringData) throws Exception 
    {
        return java.util.Base64.getDecoder().decode(stringData.getBytes(CHARACTER_ENCODING));
    }

    /**
    * This method is used to encrypt the string which is passed to it as byte[] and return base64 encoded
    * encrypted String
    * @param plainText
    *            : byte[]
    * @param secret
    *            : Key using for encrypt
    * @return : base64 encoded of encrypted string.
    * 
    */

    private static String encryptEK(byte[] plainText, byte[] secret)
    {
        try
        {
            SecretKeySpec sk = new SecretKeySpec(secret, AES_ALGORITHM);
            ENCRYPT_CIPHER.init(Cipher.ENCRYPT_MODE, sk);
            return Base64.encodeBase64String(ENCRYPT_CIPHER.doFinal(plainText));    
        }
        catch(Exception e)
        {
            e.printStackTrace();
            return "";
        }
    }

    /**
    * This method is used to decrypt base64 encoded string using an AES 256 bit key.
    * 
    * @param plainText
    *            : plain text to decrypt
    * @param secret
    *            : key to decrypt
    * @return : Decrypted String
    * @throws IOException
    * @throws InvalidKeyException
    * @throws BadPaddingException
    * @throws IllegalBlockSizeException
    */
    public static byte[] decrypt(String plainText, byte[] secret)
                throws InvalidKeyException, IOException, IllegalBlockSizeException,
                BadPaddingException,Exception 
    {
        SecretKeySpec sk = new SecretKeySpec(secret, AES_ALGORITHM);
        DECRYPT_CIPHER.init(Cipher.DECRYPT_MODE, sk);       
        return DECRYPT_CIPHER.doFinal(Base64.decodeBase64(plainText));
    }

    public static void main(String args[])throws Exception
    {
        String encKey = ""; 

        //client asp_secret
        String asp_secret="";   


        byte[] enc_key = decrypt(encKey, asp_secret.getBytes());

        String enc_asp_secret=encryptEK(asp_secret.getBytes(), decodeBase64StringTOByte(encodeBase64String(enc_key)));

        System.out.println("asp secret encrypted:");
        System.out.println(enc_asp_secret);     
    }
}
我碰巧在StackOverflow上看到一个非常类似的帖子,没有答案

标记为复制到另一个不同的问题

我已经尝试了一些PHP代码,但没有成功

我会为这个加上赏金,因为我尝试了很久

免责声明:使用了与上述问题相同的代码片段,因为这个问题更清楚

添加我尝试过的PHP代码

class AtomAES {

public function encrypt($data = '', $key = NULL, $salt = "") {
    if($key != NULL && $data != "" && $salt != ""){

        $method = "AES-256-CBC";

        //Converting Array to bytes
        $iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
        $chars = array_map("chr", $iv);
        $IVbytes = join($chars);


        $salt1 = mb_convert_encoding($salt, "UTF-8"); //Encoding to UTF-8
        $key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8

        //SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
        $hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha1'); 

        $encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);

        return bin2hex($encrypted);
    }else{
        return "String to encrypt, Salt and Key is required.";
    }
}

public function decrypt($data="", $key = NULL, $salt = "") {
    if($key != NULL && $data != "" && $salt != ""){
        $dataEncypted = hex2bin($data);
        $method = "AES-256-CBC";

        //Converting Array to bytes
        $iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
        $chars = array_map("chr", $iv);
        $IVbytes = join($chars);

        $salt1 = mb_convert_encoding($salt, "UTF-8");//Encoding to UTF-8
        $key1 = mb_convert_encoding($key, "UTF-8");//Encoding to UTF-8

        //SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
        $hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha1'); 

        $decrypted = openssl_decrypt($dataEncypted, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
        return $decrypted;
    }else{

        return "Encrypted String to decrypt, Salt and Key is required.";

    }
}

}
我无法使用此PHP解密使用java生成的字符串

更新

Plain text: The quick brown fox jumps over the lazy dog
Encrypted text (base64 encoded) with Java: /XjXJc5dNk6p/h2HL8MVmmWG8Vd0Ud2x1QQWwmIQr9OG/PXZ0AzsIIMV1YmvMJho
Decrypted text with PHP: The quick brown fox jumps over the lazy dog
Plain text: The quick brown fox jumps over the lazy dog
Encrypted text (base64 encoded) with PHP:  /XjXJc5dNk6p/h2HL8MVmmWG8Vd0Ud2x1QQWwmIQr9OG/PXZ0AzsIIMV1YmvMJho
Decrypted text with Java: The quick brown fox jumps over the lazy dog
下面是我使用上述java代码尝试加密的文本和密钥

Random generated text (asp_secret)  : DTosv9G179D0cY1985Uh2eF6ND80C95L
Random generated Key used (encKey): VEMwcCYfFpsrXQVIFTDrA/2zP/5PYOY6JC1XEkEcLGSk/klt+HqHzGSr781Yznku
Encrypted string using above java code (enc_asp_secret): zAnTcjmAezfdzrWGixyfwmb8cM0otrsmwJ8+cNDs48Axh9hYgBtCJyeSE9tCvEBz

由于您对加密字符串的解密感兴趣,其中加密是使用Java
encryptEK
-方法完成的,而解密应该使用PHP
decrypt
-方法完成(反之亦然),因此我忽略了
main
-方法的代码(我不太清楚)我重点介绍了将两种Java方法,
encryptEK
decrypt
移植到PHP方法

Java
encryptEK
-方法将纯文本和密钥作为字节数组,使用AES(256-ECB)加密纯文本,并使用Base64编码对加密文本进行编码。一种可能的PHP对应物是:

public function encrypt($data = '', $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-256-ECB";
        $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA);
        $result = base64_encode($encrypted);
        return $result;
    }else{
        return "String to encrypt, Key is required.";
    }
}
注意:ECB模式不使用IV

Java
decrypt
-方法获取base64编码的字符串,对其进行解码,然后对其进行解密。PHP的一个可能对应项是

public function decrypt($data="", $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-256-ECB";
        $dataDecoded = base64_decode($data);
        $decrypted = openssl_decrypt($dataDecoded, $method, $key, OPENSSL_RAW_DATA);
        return $decrypted;
    }else{
        return "Encrypted String to decrypt, Key is required.";
    }
}
Java方法
encryptEK
decodeBase64StringTOByte
不使用
Java.util.Base64
-类的两个Java方法
encryptEK
decrypt
。相反,使用了
org.apache.commons.codec.binary.Base64
-类(例如)的相应方法。因此,我不再进一步注意这两种方法

在Java参考代码中,示例性地生成了256bit AES密钥,但通常以以下方式生成随机密钥:

KEYGEN.init(256);
SecretKey secretKey = KEYGEN.generateKey();
byte[] key = secretKey.getEncoded();
在PHP中,这是通过

$key = random_bytes(32);
对于两侧的混合加密/解密测试(例如Java/PHP),必须使用相同的密钥。例如,该密钥是用Java提供的:

byte[] key = "This is a 256 bits = 32 byte key".getBytes(Charsets.UTF_8);
在PHP中:

$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
测试1:使用Java加密/解密(使用随机生成的密钥)

测试2:使用PHP加密/解密(使用随机生成的密钥)

可能的加密和解密部分:

$key = random_bytes(32);
echo bin2hex($key);
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
$decrypt = $atomAES->decrypt($encrypt, $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$decrypt = $atomAES->decrypt("/XjXJc5dNk6p/h2HL8MVmmWG8Vd0Ud2x1QQWwmIQr9OG/PXZ0AzsIIMV1YmvMJho", $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
测试3:用Java加密/用PHP解密(使用上面的具体密钥)

可能的解密部分:

$key = random_bytes(32);
echo bin2hex($key);
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
$decrypt = $atomAES->decrypt($encrypt, $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$decrypt = $atomAES->decrypt("/XjXJc5dNk6p/h2HL8MVmmWG8Vd0Ud2x1QQWwmIQr9OG/PXZ0AzsIIMV1YmvMJho", $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
测试4:用PHP加密/用Java解密(使用上面的具体密钥)

可能的加密部分:

$key = random_bytes(32);
echo bin2hex($key);
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
$decrypt = $atomAES->decrypt($encrypt, $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$decrypt = $atomAES->decrypt("/XjXJc5dNk6p/h2HL8MVmmWG8Vd0Ud2x1QQWwmIQr9OG/PXZ0AzsIIMV1YmvMJho", $key);
echo $decrypt;
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("The quick brown fox jumps over the lazy dog", $key);
echo $encrypt; 
编辑:

与main方法中的代码相对应的是(结合您的示例):

注意:PHP表达式
base64\u decode(base64\u encode($enc\u key))
相当于
$enc\u key
,因此您也可以用当前注释掉的行替换它。我编写它的唯一原因是因为它也是用Java代码编写的。这里
decodeBase64StringTOByte(encodeBase64String(enc_键)
是等效的 这是因为一种方法与另一种方法相反

如果运行上述代码,则输出为

asp secret encrypted:
zAnTcjmAezfdzrWGixyfwmb8cM0otrsmwJ8+cNDs48Axh9hYgBtCJyeSE9tCvEBz
您也可以定义
AtomAES
-类的第三种方法:

public function main(){
    $encKey = mb_convert_encoding("VEMwcCYfFpsrXQVIFTDrA/2zP/5PYOY6JC1XEkEcLGSk/klt+HqHzGSr781Yznku", "UTF-8");
    $asp_secret = mb_convert_encoding("DTosv9G179D0cY1985Uh2eF6ND80C95L", "UTF-8");

    $enc_key = $this->decrypt($encKey, $asp_secret);
    $enc_asp_secret = $this->encrypt($asp_secret, base64_decode(base64_encode($enc_key)));
    //$enc_asp_secret = $this->encrypt($asp_secret, $enc_key);

    echo "asp secret encrypted:\n".mb_convert_encoding($enc_asp_secret, "UTF-8")."\n"; 
}
可以用

$atomAES = new AtomAES();
$atomAES->main();

是的,我在链接上尝试了解决方案。这就是我没有在问题中发布的原因。等等,老板。让我添加它。我不明白为什么我应该否决你。我在寻找答案。可能是。没有问题。我已经用我用java代码得到的加密字符串更新了问题。我试图用给定的php代码解密它。但我得到的是'false'r很遗憾,我无法用提供的Java代码从您的示例中复制加密字符串。我尝试了Java main方法,使用encKey和asp_secret分配示例的字符串输入值(“随机生成的文本”和“使用随机生成的密钥”).我还直接尝试了Java encryptEK方法,其中明文和机密是字节数组。我使用了Java decodeBase64StringTOByte方法,还通过getBytes()使用了简单的UTF-8编码从示例的字符串输入值生成字节数组。在这两种情况下,我尝试了所有可能的组合,但根本无法再现结果。因此,您能否解释一下如何获得结果,即使用哪些方法以及输入值是什么?抱歉,提供的加密字符串不正确。我已更新了用上面给定的密钥和字符串加密后得到的实际字符串提问。没问题。我已经将Java
main
-方法移植到PHP。这段代码现在生成了预期的结果。