Unable to replicate an encryption format from Java to PHP

后端 未结 1 652
谎友^
谎友^ 2020-12-19 16:52

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.sec         


        
相关标签:
1条回答
  • 2020-12-19 17:41

    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.";
        }
    }
    

    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.

    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.";
        }
    }
    

    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).

    Test case 1: Encrypt and Decrypt with 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; 
    

    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==
    

    and for $decrypt:

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

    Test case 2: Encrypt with Java, Decrypt with PHP

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

    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==
    

    and

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

    with the result for $decrypt:

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

    Test case 3: Encrypt with Java, Decrypt with PHP

    encryptedText = AES256.encrypt("This is a sample text","NEWENCTEST");
    System.out.println(encryptedText);
    
    1HO8iuSZf41RzP/gUleEJY3zhtLJVwFMnhZiphnoG0m9ss+g93Sj5SqQg0D7OsgSvUZCeX2Ck5QPpFrPxM0FE/yFE5s=
    

    and

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

    with the result for $decrypt:

     This is a sample text
    
    0 讨论(0)
提交回复
热议问题