简体   繁体   English

在 php 和 vb.net 中加密和解密 AES 256

[英]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.我需要能够加密和解密 php 和 vb.net 中的字符串。PHP 需要能够解密在 vb.net 中加密的字符串,而 vb.net 需要能够解密在 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.我已经对这个做了很多搜索,我相信这与 AES256 的 openssl 实现以及它与 IV 或类似的东西一起加盐的方式有关。

The vb implementation is generating a random GUID for the IV and prepending it to the encrypted string before base64 encoding it. vb 实现为 IV 生成一个随机 GUID,并在 base64 对其进行编码之前将其添加到加密字符串之前。

My vb.net code is like so...我的 vb.net 代码是这样的......

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 代码是这样的...

<?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.我遇到了一个使用 AES128 和 PHP 的 mcrypt 扩展的代码的“工作”示例,但是我使用的是 PHP8,Mcrypt 已被弃用且不受支持,所以我真的不想走那条路。

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?有谁能给我指出正确的方向,使字符串在 PHP 中加密,使用 vb.net 中可解密的 AES256 的 openssl 实现,或者反过来? 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. VB 代码中的AESEncryptStringToBase64()使用 PKCS7 填充的 CBC 模式中的 AES 加密明文。 The key size determines the AES variant, eg 32 bytes for AES-256.密钥大小决定了 AES 变体,例如 AES-256 为 32 字节。 During encryption a GUID is generated which acts as IV.在加密期间生成一个 GUID 作为 IV。 After encryption, the IV and ciphertext are concatenated and Base64 encoded.加密后,IV和密文串接,编码为Base64。

A possible implementation in PHP is: PHP 中的一个可能实现是:

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.在 PHP 代码中,生成了加密安全 IV,而不是 GUID,请参阅CSPRNG This is at least as secure as the GUID used in the VB code, see Is Microsoft's GUID generator cryptographically secure?这至少与 VB 代码中使用的 GUID 一样安全,请参阅Is Microsoft's GUID generator cryptographically secure? . .
  • In the PHP code AES-256 is specified and therefore a 32 bytes key is required.在 PHP 代码中指定了 AES-256,因此需要一个 32 字节的密钥。 In the VB code, therefore, a 32 bytes key must also be used for compatibility.因此,在 VB 代码中,还必须使用 32 字节的密钥以实现兼容性。 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.如果 VB 代码中的密钥大小不同,则必须相应地调整 PHP 代码中的 AES 变体,例如aes-128-cbc用于 16 字节密钥。

AESDecryptBase64ToString() in the VB code is the counterpart and therefore uses the same algorithm, mode and padding. VB 代码中的AESDecryptBase64ToString()是对应的,因此使用相同的算法、模式和填充。 The encrypted data is first Base64 decoded.加密后的数据先进行Base64解码。 The first 16 bytes are the IV, the rest is the ciphertext which is then decrypted.前 16 个字节是 IV,rest 是密文,然后解密。

A possible implementation in PHP is: PHP 中的一个可能实现是:

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:具有以下可能的 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() .测试 1 显示使用encrypt()加密的密文可以使用decrypt() Test 2 decrypts a ciphertext encrypted with the VB code.测试 2 解密用 VB 代码加密的密文。 Test 3 generates a ciphertext that can be decrypted with the VB code.测试 3 生成可以用 VB 代码解密的密文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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