简体   繁体   中英

Encrypting and Decrypting AES 256 in both php and vb.net

I have a need to be able to encrypt and decrypt strings in both php and vb.net. PHP needs to be able to decrypt strings encrypted in vb.net and vb.net needs to be able to decrypt string encrypted in php.

I have working code in both environments that work within that environment, but they do not work with each other.

I've done alot of searching on this one and I believe that this is to do with the openssl implementation of AES256 and the way it salts with the IV or something along those lines.

The vb implementation is generating a random GUID for the IV and prepending it to the encrypted string before base64 encoding it.

My vb.net code is like so...

Imports System.IO
Imports System.Text
Imports System.Security.Cryptography


Public Class tbSecurity

Public Shared enckey = "00000000000000000000000000000000"
Public Shared Function AESEncryptStringToBase64(strPlainText As String) As String
    Dim Algo As RijndaelManaged = RijndaelManaged.Create()

    With Algo
        .BlockSize = 128
        .FeedbackSize = 128
        .KeySize = 256
        .Mode = CipherMode.CBC
        .IV = Guid.NewGuid().ToByteArray()
        .Key = Encoding.ASCII.GetBytes(enckey)
    End With

    Using Encryptor As ICryptoTransform = Algo.CreateEncryptor()
        Using MemStream As New MemoryStream
            Using CryptStream As New CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)
                Using Writer As New StreamWriter(CryptStream)
                    Writer.Write(strPlainText)
                End Using

                AESEncryptStringToBase64 = Convert.ToBase64String(Algo.IV.Concat(MemStream.ToArray()).ToArray())
            End Using
        End Using
    End Using
End Function

Public Shared Function AESDecryptBase64ToString(strCipherText As String) As String
    Dim arrSaltAndCipherText As Byte() = Convert.FromBase64String(strCipherText)

    Dim Algo As RijndaelManaged = RijndaelManaged.Create()

    With Algo
        .BlockSize = 128
        .FeedbackSize = 128
        .KeySize = 256
        .Mode = CipherMode.CBC
        .IV = arrSaltAndCipherText.Take(16).ToArray()
        .Key = Encoding.ASCII.GetBytes(enckey)
    End With

    Using Decryptor As ICryptoTransform = Algo.CreateDecryptor()
        Using MemStream As New MemoryStream(arrSaltAndCipherText.Skip(16).ToArray())
            Using CryptStream As New CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read)
                Using Reader As New StreamReader(CryptStream)
                    AESDecryptBase64ToString = Reader.ReadToEnd()
                End Using
            End Using
        End Using
    End Using
End Function

End Class

PHP code is like so...

<?php
$inputstr = $_GET['str'];
 
$ky = '00000000000000000000000000000000'; // 32 * 8 = 256 bit key
$iv = '1234567890123456'; // 32 * 8 = 256 bit iv

echo "<hr>";
echo "Input Str = " . $inputstr;
echo "<hr>";
echo "Decrypted Str = " . decryptRJ256($ky,$iv,$inputstr);

function decryptRJ256($key,$iv,$string_to_decrypt)
{
    $string_to_decrypt = base64_decode($string_to_decrypt);
    $rtn = openssl_decrypt($string_to_decrypt, "aes-256-cbc", $key,0,$iv); 
    $rtn = rtrim($rtn, "\0\4");
    return($rtn);
}

function encryptRJ256($key,$iv,$string_to_encrypt)
{
    $rtn = openssl_decrypt($string_to_encrypt, "aes-256-cbc", $key,0,$iv); 
    $rtn = base64_encode($rtn);
    return($rtn);
}    
?>

I've come across a 'working' example of code that uses AES128 and the mcrypt extension for PHP, however I'm using PHP8 and Mcrypt is deprecated and unsupported, so I really don't want to take that route.

Is anyone able to point me in the right direction for either making strings encrypted in PHP using the openssl implementation of AES256 decryptable in vb.net or the other way round? I don't care which environment I have to amend, or even if its both.

Many thanks in advance

AESEncryptStringToBase64() in the VB code encrypts a plaintext with AES in CBC mode with PKCS7 padding. The key size determines the AES variant, eg 32 bytes for AES-256. During encryption a GUID is generated which acts as IV. After encryption, the IV and ciphertext are concatenated and Base64 encoded.

A possible implementation in PHP is:

function encrypt($key, $plaintext){
    $iv = random_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
    $ivCiphertext = $iv . $ciphertext;
    $ivCiphertextB64 = base64_encode($ivCiphertext);
    return $ivCiphertextB64;
}

Note:

  • In the PHP code a cryptographically secure IV, see CSPRNG , is generated instead of a GUID. This is at least as secure as the GUID used in the VB code, see Is Microsoft's GUID generator cryptographically secure? .
  • In the PHP code AES-256 is specified and therefore a 32 bytes key is required. In the VB code, therefore, a 32 bytes key must also be used for compatibility. In case of a different key size in the VB code, the AES variant in the PHP code must be adapted accordingly, eg aes-128-cbc for a 16 bytes key.

AESDecryptBase64ToString() in the VB code is the counterpart and therefore uses the same algorithm, mode and padding. The encrypted data is first Base64 decoded. The first 16 bytes are the IV, the rest is the ciphertext which is then decrypted.

A possible implementation in PHP is:

function decrypt($key, $ivCiphertextB64){
    $ivCiphertext  = base64_decode($ivCiphertextB64);
    $iv = substr($ivCiphertext, 0, 16);
    $ciphertext = substr($ivCiphertext, 16);
    $decryptedData = openssl_decrypt($ciphertext, "aes-256-cbc", $key, OPENSSL_RAW_DATA, $iv); 
    return $decryptedData;
}

Tests:

// Test 1:
$key = '00000000000000000000000000000000'; 
$plaintext = 'The quick brown fox jumps over the lazy dog';
$ivCiphertextB64 = encrypt($key, $plaintext);
$decrypted = decrypt($key, $ivCiphertextB64);
print("Test 1 - Ciphertext: " . $ivCiphertextB64 . PHP_EOL);
print("Test 1 - Decrypted:  " . $decrypted . PHP_EOL);

// Test 2: Decrypt ciphertext from VB
$ivCiphertextB64 = '6z4IGlnv5UOd+MWUOfP5m4ymJ/XUp+VijU0D4xBLRr/T1JWAsxRApW6aJgptmN4q2f0seibD/2jktvkDydz33g==';
$decrypted = decrypt($key, $ivCiphertextB64);
print("Test 2 - Decrypted:  " . $decrypted . PHP_EOL);

// Test 3: Encrypt plaintext for VB
$plaintext = 'The quick brown fox jumps over the lazy dog';
$ivCiphertextB64 = encrypt($key, $plaintext);
print("Test 3 - Encrypted:  " . $ivCiphertextB64 . PHP_EOL);

with the following possible output:

Test 1 - Ciphertext: cadDJ82W94xKz4MQlvZ4IPBYvytpJezgbAY+ZYi76Z/zcGieUFDZLzEsjenolbEP2pR9JTHOHnG+ylJCXZd45g==
Test 1 - Decrypted:  The quick brown fox jumps over the lazy dog
Test 2 - Decrypted:  The quick brown fox jumps over the lazy dog
Test 3 - Encrypted:  Teo0qUA553EJ9y9O0lb0gjVzWHE8+EQyklnbq6v8ziK5SXNAhX6HdyfdtHkyQUKAWXmFazWx2bEkIDwqjM+aQA==

Test 1 shows that a ciphertext encrypted with encrypt() can be decrypted with decrypt() . Test 2 decrypts a ciphertext encrypted with the VB code. Test 3 generates a ciphertext that can be decrypted with the VB code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM