[英]Unable to replicate an encryption method from Java to PHP using AES/ECB/PKCS5Padding
I have the following Java code 我有以下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);
}
}
I happened to see a very similar post in StackOverflow with no answers 我碰巧在StackOverflow中看到了一个非常相似的帖子而没有答案
Cannot replicate an AES 256 encryption code from Java to PHP [duplicate] 无法将AES 256加密代码从Java复制到PHP [重复]
which is marked duplicate to another question which is different. 与另一个不同的问题标记为重复。
I have tried a couple of PHP codes but it didn't work out. 我已经尝试了几个PHP代码,但它没有成功。
I will add up bounty for this as im trying this for ages. 我会为此加起来,因为我多年来一直试着这个。
Disclaimer : Used the same code snippet from the above question as this one is more clear. 免责声明:使用上述问题中的相同代码片段,因为这个代码片段更清晰。
Adding the PHP code I tried 添加我试过的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.";
}
}
}
I am not able to decrypt a string generated using java using this PHP 我无法使用此PHP解密使用java生成的字符串
Update 更新
here is the text and key that i tried for encryption using the above java code 这是我尝试使用上面的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
Since you are interested in the decryption of an encrypted string in which the encryption was done with the Java encryptEK
-method and the decryption should be done with the PHP decrypt
-method (or vice versa) I ignore the code of the main
-method (which isn't very clear to me) and I focus on the porting of the both Java-methods, encryptEK
and decrypt
, to PHP-methods. 由于您对加密字符串的解密感兴趣,其中使用Java
encryptEK
-method进行加密,并且解密应该使用PHP decrypt
-method(反之亦然),我忽略了main
-method的代码(这对我来说不是很清楚)我专注于将两种Java方法, encryptEK
和decrypt
移植到PHP方法。
The Java encryptEK
-method takes a plain text and a key as byte array, encrypts the plain text using AES (256-ECB) and encodes the encrypted text using Base64 encoding. Java
encryptEK
-method将纯文本和密钥作为字节数组,使用AES(256-ECB)加密纯文本,并使用Base64编码对加密文本进行编码。 A possible PHP-counterpart is: 可能的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.";
}
}
Note: The ECB-mode doesn't use an IV. 注意:ECB模式不使用IV。
The Java decrypt
-method takes a base64 encoded string, decodes it and then decrypts it. Java
decrypt
-method采用base64编码的字符串,对其进行解码然后对其进行解密。 A possible PHP-counterpart is 一个可能的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.";
}
}
The both Java-methods, encodeBase64String
and decodeBase64StringTOByte
, which use the java.util.Base64
-class are not consumed by the Java-methods encryptEK
and decrypt
. 两个Java的方法,
encodeBase64String
和decodeBase64StringTOByte
,其使用java.util.Base64
-class不是由Java的方法消耗encryptEK
和decrypt
。 Instead of that, the corresponding methods of the org.apache.commons.codec.binary.Base64
-class (eg https://commons.apache.org/proper/commons-codec/download_codec.cgi ) are consumed. 取而代之的是,使用
org.apache.commons.codec.binary.Base64
-class的相应方法(例如https://commons.apache.org/proper/commons-codec/download_codec.cgi )。 For this reason, I do not take any further notice of both methods. 因此,我不会进一步注意这两种方法。
In the Java reference code no 256bit-AES key is examplarily generated, but a random key is typically generated in the following way: 在Java参考代码中,没有生成256bit-AES密钥,但通常以下列方式生成随机密钥:
KEYGEN.init(256);
SecretKey secretKey = KEYGEN.generateKey();
byte[] key = secretKey.getEncoded();
In PHP this is done with 在PHP中,这是完成的
$key = random_bytes(32);
For a mixed encryption/decryption-testing (eg Java/PHP) on both sides the same key has to be used. 对于双方的混合加密/解密测试(例如Java / PHP),必须使用相同的密钥。 Eg, this key is provided in Java:
例如,这个密钥是用Java提供的:
byte[] key = "This is a 256 bits = 32 byte key".getBytes(Charsets.UTF_8);
and in PHP: 在PHP中:
$key = mb_convert_encoding("This is a 256 bits = 32 byte key", "UTF-8");
Test 1: Encrypt/Decrypt with Java (using a random generated key) 测试1:使用Java加密/解密(使用随机生成的密钥)
Plain text: The quick brown fox jumps over the lazy dog
Randomly generated key (hex): 20e9c191374b688e74e68ab6c969109e84c5c8e059d84f16f2beb07a7545cbc8
Encrypted text (base64 encoded): ZWOnSYErRxRRtqoVFTLVQMT329pOFHzN1gPDMuiZt0zFpt4n2TF/L54RB21zhVUa
Decrypted text: The quick brown fox jumps over the lazy dog
Test 2: Encrypt/Decrypt with PHP (using a random generated key) 测试2:使用PHP加密/解密(使用随机生成的密钥)
Plain text: The quick brown fox jumps over the lazy dog
Randomly generated key (hex): eecd40c21e2a395f3aa3baeac19bfc8dcee04ea6e07f02dca7069397a487824f
Encrypted text (base64 encoded): 8wjusOED9TTXHjyEqvmGExLATVlvhg3hXEBHQ6Ku3Fos2OrYKbF+4XdO6cD9JJA5
Decrypted text: The quick brown fox jumps over the lazy dog
Possible encryption and decryption portion: 可能的加密和解密部分:
$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;
Test 3: Encrypt with Java/Decrypt with PHP (using the concrete key above) 测试3:用PHP加密Java / Decrypt(使用上面的具体键)
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
Possible decryption portion: 可能的解密部分:
$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;
Test 4: Encrypt with PHP/Decrypt with Java (using the concrete key above) 测试4:使用Java加密PHP / Decrypt(使用上面的具体键)
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
Possible encryption portion: 可能的加密部分:
$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;
EDIT: 编辑:
The counterpart to the code in the main-method is (in combination with your sample): main方法中代码的对应部分(与您的示例结合):
$encKey = mb_convert_encoding("VEMwcCYfFpsrXQVIFTDrA/2zP/5PYOY6JC1XEkEcLGSk/klt+HqHzGSr781Yznku", "UTF-8");
$asp_secret = mb_convert_encoding("DTosv9G179D0cY1985Uh2eF6ND80C95L", "UTF-8");
atomAES = new AtomAES();
$enc_key = $atomAES->decrypt($encKey, $asp_secret);
$enc_asp_secret = $atomAES->encrypt($asp_secret, base64_decode(base64_encode($enc_key)));
//$enc_asp_secret = $atomAES->encrypt($asp_secret, $enc_key);
echo "asp secret encrypted:\n".mb_convert_encoding($enc_asp_secret, "UTF-8")."\n";
Note: The PHP expression base64_decode(base64_encode($enc_key))
is equivalent to $enc_key
, thus you can also replace it with the line currently commented out. 注意:PHP表达式
base64_decode(base64_encode($enc_key))
等同于$enc_key
,因此您也可以将其替换为当前已注释掉的行。 The only reason I coded it is because it is also coded in the Java code. 我编写它的唯一原因是因为它也在Java代码中编码。 Here
decodeBase64StringTOByte(encodeBase64String(enc_key)
is equivalent to enc_key
. That's because the one method is the inverse of the other method. 这里
decodeBase64StringTOByte(encodeBase64String(enc_key)
等同于enc_key
。这是因为一个方法是另一个方法的反转。
If you run the above code the output is 如果你运行上面的代码输出是
asp secret encrypted:
zAnTcjmAezfdzrWGixyfwmb8cM0otrsmwJ8+cNDs48Axh9hYgBtCJyeSE9tCvEBz
You can alternatively define a third method of the AtomAES
-class: 您也可以定义
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";
}
which can be called with 可以调用
$atomAES = new AtomAES();
$atomAES->main();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.