Unable to replicate an encryption method from Java to PHP using AES/ECB/PKCS5Padding

后端 未结 1 1862
醉酒成梦
醉酒成梦 2021-02-06 18:29

I have the following Java code

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.sec         


        
1条回答
  •  既然无缘
    2021-02-06 18:54

    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.

    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. A possible PHP-counterpart is:

    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.

    The Java decrypt-method takes a base64 encoded string, decodes it and then decrypts it. A possible PHP-counterpart is

    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. Instead of that, the corresponding methods of the org.apache.commons.codec.binary.Base64-class (e.g. https://commons.apache.org/proper/commons-codec/download_codec.cgi) are consumed. 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:

    KEYGEN.init(256);
    SecretKey secretKey = KEYGEN.generateKey();
    byte[] key = secretKey.getEncoded();
    

    In PHP this is done with

    $key = random_bytes(32);
    

    For a mixed encryption/decryption-testing (e.g. Java/PHP) on both sides the same key has to be used. E.g., this key is provided in Java:

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

    and in 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)

    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)

    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)

    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)

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

    $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. The only reason I coded it is because it is also coded in the Java code. Here decodeBase64StringTOByte(encodeBase64String(enc_key) is equivalent to enc_key. That's because the one method is the inverse of the other method.

    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:

    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();
    

    0 讨论(0)
提交回复
热议问题