5
\$\begingroup\$

I'm using Microsoft's example for encrypting/decripting a string. In their example, they are using Tripple DES. I'm trying to convert their code to use AES.

The modified code, listed below, works. However, I am wondering if I need to change anything in the TruncateHash function or in the AES.Key and AES.IV value.

This is all new to me, so I am still learning.

Imports System.Security.Cryptography

Public NotInheritable Class AesCrypto

' Private TripleDes As New TripleDESCryptoServiceProvider
' Changed from Triple DES to AES 

Private AES As New AesCryptoServiceProvider

Private Function TruncateHash(ByVal key As String, ByVal length As Integer) As Byte()
    ' Creates a byte array of a specified length from the hash of the specified key.

    Dim sha1 As New SHA1CryptoServiceProvider        

    ' Hash the key.
    Dim keyBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(key)
    Dim hash() As Byte = sha1.ComputeHash(keyBytes)

    ' Truncate or pad the hash.
    ReDim Preserve hash(length - 1)
    Return hash
End Function


Sub New(ByVal key As String)
    ' Initialize the crypto provider.
    AES.Key = TruncateHash(key, AES.KeySize \ 8)
    AES.IV = TruncateHash("", AES.BlockSize \ 8)
End Sub

Public Function EncryptData(ByVal plaintext As String) As String
    ' Encrypt the data.

    ' Convert the plaintext string to a byte array.
    Dim plaintextBytes() As Byte =
        System.Text.Encoding.Unicode.GetBytes(plaintext)

    ' Create the stream.
    Dim ms As New System.IO.MemoryStream
    ' Create the encoder to write to the stream.
    Dim encStream As New CryptoStream(ms,
        AES.CreateEncryptor(),
        System.Security.Cryptography.CryptoStreamMode.Write)

    ' Use the crypto stream to write the byte array to the stream.
    encStream.Write(plaintextBytes, 0, plaintextBytes.Length)
    encStream.FlushFinalBlock()

    ' Convert the encrypted stream to a printable string.
    Return Convert.ToBase64String(ms.ToArray)
End Function

Public Function DecryptData(ByVal encryptedtext As String) As String
    'Decrypt the data.

    ' Convert the encrypted text string to a byte array.
    Dim encryptedBytes() As Byte = Convert.FromBase64String(encryptedtext)

    ' Create the stream.
    Dim ms As New System.IO.MemoryStream
    ' Create the decoder to write to the stream.
    Dim decStream As New CryptoStream(ms,
        AES.CreateDecryptor(),
        System.Security.Cryptography.CryptoStreamMode.Write)

    ' Use the crypto stream to write the byte array to the stream.
    decStream.Write(encryptedBytes, 0, encryptedBytes.Length)
    decStream.FlushFinalBlock()

    ' Convert the plaintext stream to a string.
    Return System.Text.Encoding.Unicode.GetString(ms.ToArray)
End Function

End Class
\$\endgroup\$
1
  • \$\begingroup\$ Very minor notes: variables and fields should use lowercase (so use aes instead of AES. Futhermore you can make the code easier to understand by not relying on defaults, so set the mode of encryption (CBC) and the padding (PKCS#7 padding) explicitly using the properties of the AesCryptoServiceProvider class. \$\endgroup\$ Commented Jan 22, 2014 at 18:15

1 Answer 1

5
\$\begingroup\$

It seems you did a good job getting the same functionality using AES. The problem is that Microsoft is not using good practices themselves.

They confuse a password with a key, and they do not use a good key derivation function such as PBKDF2 (implemented in .NET by the class RFC2898DeriveBytes). This you should only use if you do not have access to a shared AES key, which can just consist of 16 cryptographic random bytes.

Furthermore, they did not use a random IV. The IV has the right size (the block size of the block cipher) but it has been set to a constant value. This means all the security benefits of having an IV are negated. The IV should be a cryptographic random (or at least fully unpredictable to an adversary), and could be written in front of the ciphertext (e.g. by supplying it to the unencrypted stream). Static IV's are only secure if the AES key is randomized or if the plaintext is sufficiently random itself.

They use UTF-16 (incorrectly called Unicode in .NET) to create plaintext bytes from the input. UTF-16 uses 16 bits for each normal character, instead of the 8 bits used by UTF-8. So their encoding method is not very efficient.

Note that if you want to use this in a communication protocol that you may need to add a MAC to protect the integrity and authenticity of the plaintext. If you do not, you may even loose the confidentiality of the plaintext (as the default CBC mode of encryption is vulnerable to padding oracle attacks).

So good job, cannot say the same thing of Microsoft.

\$\endgroup\$
2
  • \$\begingroup\$ Would using this key derivation function be a better alternative? \$\endgroup\$
    – crjunk
    Commented Jan 22, 2014 at 20:22
  • \$\begingroup\$ If you require a password to be used it is probably the best one available in .NET (the others are bcrypt and scrypt, but they are not in the standard libs). But as said, a password is almost never better than a fully random key. \$\endgroup\$ Commented Jan 22, 2014 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.