无法将加密格式从Java复制到PHP [英] Unable to replicate an encryption format from Java to PHP

查看:116
本文介绍了无法将加密格式从Java复制到PHP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下Java代码,其中一个集成合作伙伴为其API加密共享

I have the following Java code which was shared by one of an integration partner for their API encryption

    import java.nio.ByteBuffer;
    import java.security.AlgorithmParameters;
    import java.security.SecureRandom;
    import java.security.spec.KeySpec;
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;
    import org.apache.commons.codec.binary.Base64;

public class AES256 {

    /**
     *
     * @param word
     * @param keyString
     * @return
     * @throws Exception
     */
    public static String encrypt(String word, String keyString) throws Exception {
        byte[] ivBytes;
        //String password = "zohokeyoct2017";
        /*you can give whatever you want for password. This is for testing purpose*/
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        byte[] saltBytes = bytes;
        System.out.println("salt enc:"+saltBytes.toString());
        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(keyString.toCharArray(), saltBytes, 65556, 256);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
        //encrypting the word
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
        byte[] encryptedTextBytes = cipher.doFinal(word.getBytes("UTF-8"));
        //prepend salt and vi
        byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
        System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
        System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
        System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
        return new Base64().encodeToString(buffer);
    }

    /**
     *
     * @param encryptedText
     * @param keyString
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptedText, String keyString) throws Exception {
        //String password = "zohokeyoct2017";
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //strip off the salt and iv
        ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
        byte[] saltBytes = new byte[20];
        buffer.get(saltBytes, 0, saltBytes.length);
        byte[] ivBytes1 = new byte[16];

        buffer.get(ivBytes1, 0, ivBytes1.length);
        byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes1.length];

        buffer.get(encryptedTextBytes);
        // Deriving the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(keyString.toCharArray(), saltBytes, 65556, 256);
        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes1));
        byte[] decryptedTextBytes = null;
        try {
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            System.out.println("Exception"+e);
        }

        return new String(decryptedTextBytes);
    }

    public static void main (String []args) throws Exception{
        String encryptedText;
        encryptedText = AES256.encrypt("106_2002005_9000000106","3264324");
        System.out.println("Encrypted Text:"+encryptedText);
        System.out.println("Decrypted Text:"+AES256.decrypt(encryptedText,"3264324"));

    }
}

我尝试了几个PHP代码我从stackoverflow或谷歌获得。 COuldnt使他们中的任何一个工作。

And I tried couple of PHP codes which I got from stackoverflow or google. COuldnt make any of them working.

我最近在PHP上尝试的代码低于

The code which I tried lately on PHP is below

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代码没有按预期工作。

This is the PHP code which I wanted to try but it doesnt work as expected as per the Java code.

Encrypted Text:1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=
Decrypted Text:This is a sample text
KEY: NEWENCTEST

尝试使用PHP代码和密钥解密上述java加密文本,如果是然后很棒。

Try decrypting the above java encrypted text using the PHP code and the key, if it works then great.

如果有人可以帮我这个,那将会有很大的帮助!

If someone can help me with this it will of a great help!

TIA!

推荐答案

Java 加密 -method (随机生成的)salt和IV字节与加密字节一起复制到单个字节数组中,该字节数组变为base64编码,然后返回。相反, PHP 加密 -method 仅返回加密字节的十六进制表示。因此,关于盐和IV的信息丢失并且解密不再可能(除非盐和IV以其他方式重建)。为了防止这种情况,您必须更改 PHP 加密 -method ,如下所示:

In the Java encrypt-method the (randomly generated) salt- and IV-bytes are copied together with the encryption-bytes in a single byte-array which becomes base64-encoded and which is returned then. In contrast, the PHP encrypt-method returns a hex-representation of the encryption bytes only. Thus, the information concerning the salt and IV get lost and decryption is no longer possible (unless salt and IV are reconstructed in other ways). In order to prevent this, you have to change the PHP encrypt-method as follows:

public function encrypt($data = '', $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-256-CBC";
        $key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8
        //Randomly generate IV and salt
        $salt1 = random_bytes (20); 
        $IVbytes = random_bytes (16); 
        //SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
        $hash = openssl_pbkdf2($key1,$salt1,'256','65556', 'sha1'); 
        // Encrypt
        $encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
        // Concatenate salt, IV and encrypted text and base64-encode the result
        $result = base64_encode($salt1.$IVbytes.$encrypted);            
        return $result;
    }else{
        return "String to encrypt, Key is required.";
    }
}

现在,参数 $ result 是一个base64编码的字符串,包含salt,IV和加密。顺便说一句,参数 $ salt1 $ IVbytes 现在也是随机生成的(类似于Java 加密 -method)。 Morover用于密钥生成的迭代计数已从65536更改为65556(类似于Java encrypt -method)。注意:通常,由于盐和IV的随机性,加密文本不可复制(即使在相同的纯文本和相同的密钥/密码的情况下)。

Now, the parameter $result is a base64-encoded string containing the salt, IV and the encryption. By the way, the parameters $salt1 and $IVbytes are also randomly generated now (analogous to the Java encrypt-method). Morover the iteration count used for the key generation has been changed from 65536 to 65556 (analogous to the Java encrypt-method). Note: Generally, the encrypted text isn't reproducible (even in the case of the same plain text, and the same key/password) due to the random nature of salt and IV.

Java 解密 -method 解码base64编码的字符串,然后确定三个部分,即salt-,IV-和加密 - 解密所需的字节数。 PHP 解密 -method 必须补充以下功能:

The Java decrypt-method decodes the base64-encoded string and then determines the three portions i.e. salt-, IV- and encryption-bytes which are necessary for decryption. The PHP decrypt-method has to be supplemented with these functionalities:

public function decrypt($data="", $key = NULL) {
    if($key != NULL && $data != ""){
        $method = "AES-256-CBC";
        $key1 = mb_convert_encoding($key, "UTF-8");//Encoding to UTF-8
        // Base64-decode data
        $dataDecoded = base64_decode($data);
        // Derive salt, IV and encrypted text from decoded data
        $salt1 = substr($dataDecoded,0,20); 
        $IVbytes = substr($dataDecoded,20,16); 
        $dataEncrypted = substr($dataDecoded,36); 
        // SecretKeyFactory Instance of PBKDF2WithHmacSHA1 Java Equivalent
        $hash = openssl_pbkdf2($key1,$salt1,'256','65556', 'sha1'); 
        // Decrypt
        $decrypted = openssl_decrypt($dataEncrypted, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
        return $decrypted;
    }else{
        return "Encrypted String to decrypt, Key is required.";
    }
}

现在,参数 $ dataDecoded 包含解码后的base64编码字符串salt-( $ salt1 ),IV-( $ IVbytes )和encryption-
$ dataEncrypted )字节。 Morover用于密钥生成的迭代计数已从65536更改为65556(类似于Java decrypt -method)。

Now, the parameter $dataDecoded contains the decoded base64-encoded string from which salt- ($salt1), IV- ($IVbytes) and encryption- ($dataEncrypted) bytes are derived. Morover the iteration count used for the key generation has been changed from 65536 to 65556 (analogous to the Java decrypt-method).

测试案例1:使用PHP加密和解密

$atomAES = new AtomAES();
$encrypt = $atomAES->encrypt("This is a text...This is a text...This is a text...", "This is the password");
echo $encrypt; 
$decrypt = $atomAES->decrypt($encrypt, "This is the password");
echo $decrypt; 

结果为 $ encrypt (其中由于盐和IV的随机性质,每种加密通常是不同的:

with the result for $encrypt (which is in general different for each encryption due to the random nature of salt and IV):

6n4V9wqgsQq87HOYNRZmddnncSNyjFZZb8nSSAi681+hs+jwzDVQCugcg108iTMZLlmBB2KQ4iist+SuboFH0bnJxW6+rmZK07CiZ1Ip+8XOv6UuJPjVPxXTIny5p3QptpBGpw==

$ decrypt

This is a text...This is a text...This is a text...

测试案例2:使用Java加密,使用PHP解密

encryptedText = AES256.encrypt("This is a text...This is a text...This is a text...","This is the password");
System.out.println(encryptedText);

结果为 encryptedText (这是一般为每个加密不同,由于盐的随机性和IV):

with the result for encryptedText (which is in general different for each encryption due to the random nature of salt and IV):

qfR76lc04eYAPjjqYiE1wXoraD9bI7ql41gSV/hsT/BLoJe0i0GgJnud7IXOHdcCljgtyFkXB95XibSyr/CazoMhwPeK6xsgPbQkr7ljSg8H1i17c8iWpEXBQPm0nij9qQNJ8A==

$decrypt = $atomAES->decrypt("qfR76lc04eYAPjjqYiE1wXoraD9bI7ql41gSV/hsT/BLoJe0i0GgJnud7IXOHdcCljgtyFkXB95XibSyr/CazoMhwPeK6xsgPbQkr7ljSg8H1i17c8iWpEXBQPm0nij9qQNJ8A==", "This is the password");
echo $decrypt; 

结果为 $ decrypt

This is a text...This is a text...This is a text...

测试案例3:使用Java加密,使用PHP解密

encryptedText = AES256.encrypt("This is a sample text","NEWENCTEST");
System.out.println(encryptedText);

1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=

$decrypt = $atomAES->decrypt("1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=", "NEWENCTEST");
echo $decrypt; 

结果为 $ decrypt

 This is a sample text

这篇关于无法将加密格式从Java复制到PHP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆