Search code examples
phppowershellencryptionopensslaes

PHP Decrypt Powershell AES 192 Encrypted String


The test code from Powershell:

$theKey = (21,123,21,3,141,13,14,253,151,13,11,241,36,21,18,17,61,11,21,9,5,21,17,28)
$theString = "Test String"
$Secure = ConvertTo-SecureString -String $theString -AsPlainText -Force
$encrypted = ConvertFrom-SecureString -SecureString $Secure -Key $theKey

How do I use openssl to decrypt the string? Or is there other better method? Sample PHP i tried:

$encrypted_string ="76492d1116743f0423413b16050a5345MgB8AHAAMwBnAE4AMwBsADcASQBLAEIANQBPAFAAKwBaAGgAUgBXAGwAaQBoAGcAPQA9AHwAZQA4ADUAOAA3ADEAOABhADMAOQBlADcAMABlADEAZAAzAGMAMgBjADEANQA3ADMANABjAGQAZgA4ADcAMwAyAGQANQBmAGIAMAA5ADUAYwA2ADcAOQBiADIAMAA3ADQANAA3ADYAMAAwAGIAYgA2AGQAZgAwAGYAMgBkADUANgA=";
$cipher = "aes-192-cbc";
$iv_size = openssl_cipher_iv_length($cipher); 
$iv = openssl_random_pseudo_bytes($iv_size);
$theKey = (21,123,21,3,141,13,14,253,151,13,11,241,36,21,18,17,61,11,21,9,5,21,17,28);
$decrypted_data = openssl_decrypt($encrypted_string, $cipher, $theKey, 0, $iv);

Solution

  • $encrypted from the Powershell code has the following format and encoding (from this post):

    • The encrypted data consists of the concatenation of a 16 bytes hex encoded prefix followed by a Base64 encoded string:

      76492d1116743f0423413b16050a5345 MgB8AHAAMwBnAE4AMwBsADcASQBLAEIANQBPAFAAKwBaAGgAUgBXAGwAaQBoAGcAPQA9AHwAZQA4ADUAOAA3ADEAOABhADMAOQBlADcAMABlADEAZAAzAGMAMgBjADEANQA3ADMANABjAGQAZgA4ADcAMwAyAGQANQBmAGIAMAA5ADUAYwA2ADcAOQBiADIAMAA3ADQANAA3ADYAMAAwAGIAYgA2AGQAZgAwAGYAMgBkADUANgA=
      

      The prefix is not needed for decryption. The Base64 encoded string corresponds (after Base64 decoding) to a UTF-16LE encoded byte sequence.

    • Decoding of the UTF-16LE encoded byte sequence gives the following string:

      2|p3gN3l7IKB5OP+ZhRWlihg==|e858718a39e70e1d3c2c15734cdf8732d5fb095c679b207447600bb6df0f2d56
      

      This string consists of three parts, separated by |. The first part is not needed for decryption, the second part is the Base64 encoded IV, the third part is the hex encoded ciphertext.

    After separating IV and ciphertext the ciphertext can be decrypted with the IV and the 24 bytes key using AES-192.
    The decrypted plaintext corresponds to the UTF-16LE encoded original plaintext string.

    A possible PHP implementation is:

    <?php
    // Decode key
    $keyArr = [21,123,21,3,141,13,14,253,151,13,11,241,36,21,18,17,61,11,21,9,5,21,17,28];
    $key = pack('C*', ...$keyArr);
    
    // Decode data
    $dataFromPS = '76492d1116743f0423413b16050a5345MgB8AHAAMwBnAE4AMwBsADcASQBLAEIANQBPAFAAKwBaAGgAUgBXAGwAaQBoAGcAPQA9AHwAZQA4ADUAOAA3ADEAOABhADMAOQBlADcAMABlADEAZAAzAGMAMgBjADEANQA3ADMANABjAGQAZgA4ADcAMwAyAGQANQBmAGIAMAA5ADUAYwA2ADcAOQBiADIAMAA3ADQANAA3ADYAMAAwAGIAYgA2AGQAZgAwAGYAMgBkADUANgA==';
    $dataPayloadB64 = substr($dataFromPS, 32);
    $dataPayloadUtf16le = base64_decode($dataPayloadB64);
    $dataPayloadUtf8 = mb_convert_encoding($dataPayloadUtf16le, 'utf-8', 'utf-16le');
    
    // Separate IV and ciphertext
    $dataPayloadArr = explode('|', $dataPayloadUtf8);
    $ivB64 = $dataPayloadArr[1];
    $ctHex = $dataPayloadArr[2];
    $iv = base64_decode($ivB64);
    $ct = hex2bin($ctHex);
    
    // Decrypt
    $cipher = "aes-192-cbc";
    $decryptedDataUtf16le = openssl_decrypt($ct, $cipher, $key, OPENSSL_RAW_DATA, $iv);
    $decryptedDataUtf8 = mb_convert_encoding($decryptedDataUtf16le, 'utf-8', 'utf-16le');
    
    // Output
    print("Payload, UTF-16LE:   " . $dataPayloadUtf16le . "\n");
    print("Payload, UTF-8:      " . $dataPayloadUtf8 . "\n");
    print("IV, Base64:          " . $ivB64 . "\n");
    print("Ciphertext, hex:     " . $ctHex . "\n");
    print("Decrypted, UTF-16LE: " . $decryptedDataUtf16le . "\n");
    print("Decrypted, UTF-8:    " . $decryptedDataUtf8 . "\n");
    ?>
    

    The PHP code gives the following output:

    Payload, UTF-16LE:   2 | p 3 g N 3 l 7 I K B 5 O P + Z h R W l i h g = = | e 8 5 8 7 1 8 a 3 9 e 7 0 e 1 d 3 c 2 c 1 5 7 3 4 c d f 8 7 3 2 d 5 f b 0 9 5 c 6 7 9 b 2 0 7 4 4 7 6 0 0 b b 6 d f 0 f 2 d 5 6 
    Payload, UTF-8:      2|p3gN3l7IKB5OP+ZhRWlihg==|e858718a39e70e1d3c2c15734cdf8732d5fb095c679b207447600bb6df0f2d56
    IV, Base64:          p3gN3l7IKB5OP+ZhRWlihg==
    Ciphertext, hex:     e858718a39e70e1d3c2c15734cdf8732d5fb095c679b207447600bb6df0f2d56
    Decrypted, UTF-16LE: T e s t   S t r i n g
    Decrypted, UTF-8:    Test String