patternMinor
Encrypt Using AES
Viewed 0 times
encryptusingaes
Problem
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
Publi
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
Publi
Solution
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.
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.
Context
StackExchange Code Review Q#40774, answer score: 5
Revisions (0)
No revisions yet.