3
\$\begingroup\$

I've been looking for a while for the right code to encrypt/decrypt files with AES in vb.net. I created the code below. Is this the right way doing AES encryption/decryption nowadays?

Public Function EncryptFile(ByVal plainFilePath As String, ByVal encryptedFilePath As String, ByVal EncryptionKey As String, ByVal SaltValue As String) As String
    Dim passwordIterations As Integer = 1000
    Dim initVector As String = "Bla3212EWMND12es"
    Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
    Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(SaltValue)
    Dim k1 As New Rfc2898DeriveBytes(EncryptionKey, saltValueBytes, passwordIterations)
    Dim symmetricKey As New RijndaelManaged()
    symmetricKey.Mode = CipherMode.CBC
    Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(k1.GetBytes(16), initVectorBytes)

    Using plain As FileStream = File.Open(plainFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
        Using encrypted As FileStream = File.Open(encryptedFilePath, FileMode.Create, FileAccess.Write, FileShare.None)
            Using cs As CryptoStream = New CryptoStream(encrypted, encryptor, CryptoStreamMode.Write)
                plain.CopyTo(cs)
            End Using
        End Using
    End Using
End Function

Public Function DecryptFile(ByVal plainFilePath As String, ByVal encryptedFilePath As String, ByVal DecryptionKey As String, ByVal SaltValue As String) As String
    Dim passwordIterations As Integer = 1000
    Dim initVector As String = "Bla3212EWMND12es"
    Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
    Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(SaltValue)
    Dim k1 As New Rfc2898DeriveBytes(DecryptionKey, saltValueBytes, passwordIterations)
    Dim symmetricKey As New RijndaelManaged()
    symmetricKey.Mode = CipherMode.CBC
    Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(k1.GetBytes(16), initVectorBytes)

    Using plain As FileStream = File.Open(plainFilePath, FileMode.Create, FileAccess.Write, FileShare.None)
        Using encrypted As FileStream = File.Open(encryptedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
            Using cs As CryptoStream = New CryptoStream(plain, decryptor, CryptoStreamMode.Write)
                encrypted.CopyTo(cs)
            End Using
        End Using
    End Using
End Function
\$\endgroup\$
3
\$\begingroup\$

Security is hard. The recommended approach to implementing anything crypto related is let someone else do it! When I first thought, before reading the code, that you were actually trying to implement AES from scratch by hand in VB, I was just going to say don't. You aren't doing that, but there are still a lot of fiddly details to worry about for a secure system.

Dim initVector As String = "Bla3212EWMND12es"

The purpose of an initialisation vector is to randomise the subsequent stream. The way that AES under CBC (or one of its successors) works is that you encrypt the first block with the key, the second block with the key and the first block, the the third block with the key and the second block, and so on. This means that even if two blocks contain the same data, they won't be the same once they're encrypted.

However, this does mean that if two messages are the same, they'll encrypt to the same thing. Even if two messages are different but the first 100 blocks are the same, the first hundred blocks will encyrpt to the same thing. This might not sound like much, but it gives valuable information to an attacker.

Solution: we use initialisation vectors. If you start your message off with one block of random junk, even two identical messages will (assuming an ideal cipher) have no more in common than with the equivalent amount of random noise. For this to work, initialisation vectors must be different each time. (The initialisation vector is not secret: you can happily stick it onto the front of your encrypted file in plaintext so the decrypt side knows how to start off. But generate it with your favourite cryptographically secure random number generator.)

symmetricKey.Mode = CipherMode.CBC

I've briefly described the idea behind CBC above. Of the available ciphermodes, it is not a bad one for encrypting static files although there have been some quite famous attacks on it when used to encrypt network traffic. (Basically, you should use anything but ECB!)

ByVal EncryptionKey As String

Darting right back to the top, be careful with security data. From the context I'm infering that this is a password of some description, presumably user-supplied. Whereever it comes from, crypto libraries do all sorts of magic to make sure that secret data (especially passwords and keys) get wiped out of RAM once used and don't get accidentally written to the page file or something. I am not familar enough with VB.net to say how you'd do that, but you should consider your chain of custody here.

Dim symmetricKey As New RijndaelManaged()

Per MSDN:

The Rijndael algorithm is the predecessor of Aes. You should use the Aes class instead of RijndaelManaged. For more information, see the entry The Differences Between Rijndael and AES in the .NET Security blog.

plain.CopyTo(cs)

It's worth thinking about what you want to happen to your plaintext file. I very much would not expect anything about it to change in an EncryptFile function, and very often you do just want it to just stay there and do nothing. However, I'll at least mention it in case you don't want a copy of the original: in that case you want to securely delete it. There's nothing quite so satisfying for an attacker as ignoring all your fancy encryption and reading the unencrypted original straight from disk!

\$\endgroup\$
  • \$\begingroup\$ P.S. I am not by any stretch of the imagination a VB expert, so I cannot comment on any peculiarities of the language that may make things either safer or harder to secure. \$\endgroup\$ – Josiah Apr 24 '18 at 18:56
  • \$\begingroup\$ Thanks for the extensive review! I know that I need to get rid of RijndaelManaged, but how do I change that in this code? \$\endgroup\$ – Jp19 Apr 25 '18 at 7:57
1
\$\begingroup\$

I have modified my code slightly in relation to AES. I only try to find out how I can add the IV to my file and then retrieve it again?

 Public Function AESEncryptFile(ByVal plainFilePath As String, ByVal encryptedFilePath As String, ByVal EncryptionKey As String, ByVal SaltValue As String, IV As String) As String
    Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(IV)
    Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(SaltValue)
    Dim k1 As New Rfc2898DeriveBytes(EncryptionKey, saltValueBytes, 100)
    Dim symmetricKey As New AesManaged
    symmetricKey.KeySize = 256
    symmetricKey.Mode = CipherMode.CBC
    Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(k1.GetBytes(16), initVectorBytes)
    Using plain As FileStream = File.Open(plainFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
        Using encrypted As FileStream = File.Open(encryptedFilePath, FileMode.Create, FileAccess.Write, FileShare.None)
            Using cs As CryptoStream = New CryptoStream(encrypted, encryptor, CryptoStreamMode.Write)
                plain.CopyTo(cs)
            End Using
        End Using
    End Using
End Function

Public Function AESDecryptFile(ByVal plainFilePath As String, ByVal encryptedFilePath As String, ByVal DecryptionKey As String, ByVal SaltValue As String, IV As String) As String
    Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(IV)
    Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(SaltValue)
    Dim k1 As New Rfc2898DeriveBytes(DecryptionKey, saltValueBytes, 100)
    Dim symmetricKey As New AesManaged
    symmetricKey.KeySize = 256
    symmetricKey.Mode = CipherMode.CBC
    Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(k1.GetBytes(16), initVectorBytes)
    Using plain As FileStream = File.Open(plainFilePath, FileMode.Create, FileAccess.Write, FileShare.None)
        Using encrypted As FileStream = File.Open(encryptedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)
            Using cs As CryptoStream = New CryptoStream(plain, decryptor, CryptoStreamMode.Write)
                encrypted.CopyTo(cs)
            End Using
        End Using
    End Using
End Function
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.