TonyK
TonyK

Reputation: 23

Password encrypted in php and trying to decrypt in VB

I have a password that I'm encrypting using openssl AES-256-CBC in php that I'm trying to decrypt in VB. I'm having problems with an IV generated by the openssl_random_pseudo_bytes() php function. If I just use a random IV string instead of calling openssl_random_pseudo_bytes() which returns a string of bytes in php, my VB code returns the correct decrypted password. Any suggestions would be greatly appreciated.

I have the following php function that encrypts a password:

function f_infr_encrypt_value($password, $key) {
   $iv  = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));
   return trim(
     base64_encode(
       openssl_encrypt($value, "AES-256-CBC", $key, 0, $iv) . '::' . $iv));
}

I have the following VB code that attempts to decrypt the password created by the php function above

Private Function DecryptPassword(encryptedPassword As String, key As String) As String
   Try
      'Decode password from base 64
      Dim base64Decoded As String
      Dim data() As Byte
      data = System.Convert.FromBase64String(encryptedPassword)
      base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data)
    
      'Separating the password from the IV. Delimeter is "::"
      Dim ivct = base64Decoded.Split({"::"}, StringSplitOptions.None)
    
      'baseEncodedPassword is the password that is encrypted using AES-256-CBC
      Dim baseEncodedPassword As String
      baseEncodedPassword = ivct(0)
    
      Dim iv As String = ivct(1)
      Dim sEncryptedString As String = baseEncodedPassword
      Dim myRijndael As New RijndaelManaged
      myRijndael.Padding = PaddingMode.Zeros
      myRijndael.Mode = CipherMode.CBC
      myRijndael.KeySize = 256
      myRijndael.BlockSize = 128
    
      Dim keyByte() As Byte
      Dim IVByte() As Byte
    
      keyByte = System.Text.Encoding.ASCII.GetBytes(key)
      IVByte = System.Text.Encoding.ASCII.GetBytes(iv)
    
      Dim decryptor As ICryptoTransform = myRijndael.CreateDecryptor(keyByte, IVByte)
      Dim sEncrypted As Byte() = Convert.FromBase64String(sEncryptedString)
      Dim fromEncrypt() As Byte = New Byte(sEncrypted.Length) {}
      Dim msDecrypt As New MemoryStream(sEncrypted)
      Dim csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
    
      csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length)
    
      Dim returnvalue = (System.Text.Encoding.ASCII.GetString(fromEncrypt))
    
      Return returnvalue
    
   Catch ex As Exception
      Return ex.Message
   End Try
End Function

Upvotes: 2

Views: 257

Answers (1)

Topaco
Topaco

Reputation: 49251

There are a few issues in the VB code:

  • In the current PHP code the ciphertext is implicitly Base64 encoded by openssl_encrypt and the binary IV is concatenated with the separator :: in the order ciphertext | IV. The result is then Base64 encoded again. In the VB code the data is converted into a string after Base64 decoding. This corrupts the binary IV (see also). The ciphertext is not corrupted because of its Base64 decoding. To prevent this, the conversion into a string must not be performed.

    Note: The concatenation in the PHP code is unnecessarily complicated. Usually IV and ciphertext are concatenated in binary form without a separator (typically in the order IV | ciphertext) and the result is Base64 encoded. The second variant would be to concatenate both parts, each in Base64 encoded form, using a separator (s. Michael Fehr's comment).

  • openssl_encrypt implicitly uses PKCS7 padding, in the VB code zero padding is applied (see also). Here PKCS7 padding must be used as well.

  • In the VB Code the plaintext is stored in a Byte array, which has the length of the ciphertext. Because the ciphertext is longer than the plaintext due to padding, the array is too large. This problem is solved when e.g. using a StreamReader.

  • Also, Using statements should be applied to release possible system resources.

A possible implementation is:

Dim ciphertextSepIv() As Byte
ciphertextSepIv = System.Convert.FromBase64String(encryptedPassword)

Dim iv(16 - 1) As Byte                                                 'arbitrary binary data, length: 16 bytes
Dim ciphertext(ciphertextSepIv.Length - 1 - 2 - 16) As Char            'ASCII data (since Base64 encoded), length: ciphertext.Length - 2 - 16 bytes, 2 considers the delimiter ::
Array.Copy(ciphertextSepIv, 0, ciphertext, 0, ciphertext.Length)
Array.Copy(ciphertextSepIv, ciphertext.Length + 2, iv, 0, iv.Length)

Dim rijndael As New RijndaelManaged
rijndael.Padding = PaddingMode.PKCS7                                   'use PKCS7-Padding
rijndael.Mode = CipherMode.CBC
rijndael.KeySize = 256
rijndael.BlockSize = 128

Dim keyByte() As Byte
keyByte = System.Text.Encoding.ASCII.GetBytes(key)

Dim decryptor As ICryptoTransform = rijndael.CreateDecryptor(keyByte, iv)
Dim encrypted As Byte() = Convert.FromBase64CharArray(ciphertext, 0, ciphertext.Length)
Dim decryptedData As String = Nothing
Using msDecrypt As New MemoryStream(encrypted)
    Using csDecrypt As New CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)
        Using srDecrypt As New StreamReader(csDecrypt)                 'return only the plain text (without whitespaces etc.)
            decryptedData = srDecrypt.ReadToEnd()
        End Using
    End Using
End Using

Return decryptedData

With this VB code a ciphertext encrypted with the posted PHP Code can be decrypted.

Upvotes: 3

Related Questions