Reputation: 23
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
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