|
|
Title | Encrypt or decrypt files in Visual Basic .NET |
Description | This example shows how to encrypt or decrypt files in Visual Basic .NET. |
Keywords | cryptography, files, encrypt, decrypt, cipher, encipher, decipher, AES |
Categories | Algorithms |
|
|
The CryptFile method encrypts or decrypts a file into an output file at a fairly high level. The EncryptFile and DecryptFile methods simply call CryptFile.
|
|
' Encrypt or decrypt a file, saving the results in another
' file.
Public Sub EncryptFile(ByVal password As String, ByVal _
in_file As String, ByVal out_file As String)
CryptFile(password, in_file, out_file, True)
End Sub
Public Sub DecryptFile(ByVal password As String, ByVal _
in_file As String, ByVal out_file As String)
CryptFile(password, in_file, out_file, False)
End Sub
Public Sub CryptFile(ByVal password As String, ByVal _
in_file As String, ByVal out_file As String, ByVal _
encrypt As Boolean)
' Create input and output file streams.
Using in_stream As New FileStream(in_file, _
FileMode.Open, FileAccess.Read)
Using out_stream As New FileStream(out_file, _
FileMode.Create, FileAccess.Write)
' Encrypt/decrypt the input stream into the
' output stream.
CryptStream(password, in_stream, out_stream, _
encrypt)
End Using
End Using
End Sub
|
|
The CryptStream method does all of the real work.
|
|
' Encrypt the data in the input stream into the output
' stream.
Public Sub CryptStream(ByVal password As String, ByVal _
in_stream As Stream, ByVal out_stream As Stream, ByVal _
encrypt As Boolean)
' Make an AES service provider.
Dim aes_provider As New AesCryptoServiceProvider()
' Find a valid key size for this provider.
Dim key_size_bits As Integer = 0
For i As Integer = 1024 To 1 Step -1
If (aes_provider.ValidKeySize(i)) Then
key_size_bits = i
Exit For
End If
Next i
Debug.Assert(key_size_bits > 0)
Console.WriteLine("Key size: " & key_size_bits)
' Get the block size for this provider.
Dim block_size_bits As Integer = aes_provider.BlockSize
' Generate the key and initialization vector.
Dim key() As Byte = Nothing
Dim iv() As Byte = Nothing
Dim salt() As Byte = {&H0, &H0, &H1, &H2, &H3, &H4, _
&H5, &H6, &HF1, &HF0, &HEE, &H21, &H22, &H45}
MakeKeyAndIV(password, salt, key_size_bits, _
block_size_bits, key, iv)
' Make the encryptor or decryptor.
Dim crypto_transform As ICryptoTransform
If (encrypt) Then
crypto_transform = _
aes_provider.CreateEncryptor(key, iv)
Else
crypto_transform = _
aes_provider.CreateDecryptor(key, iv)
End If
' Attach a crypto stream to the output stream.
' Closing crypto_stream sometimes throws an
' exception if the decryption didn't work
' (e.g. if we use the wrong password).
Try
Using crypto_stream As New CryptoStream(out_stream, _
crypto_transform, CryptoStreamMode.Write)
' Encrypt or decrypt the file.
Const block_size As Integer = 1024
Dim buffer(block_size) As Byte
Dim bytes_read As Integer
Do
' Read some bytes.
bytes_read = in_stream.Read(buffer, 0, _
block_size)
If (bytes_read = 0) Then Exit Do
' Write the bytes into the CryptoStream.
crypto_stream.Write(buffer, 0, bytes_read)
Loop
End Using
Catch
End Try
crypto_transform.Dispose()
End Sub
|
|
The basic idea is to make a cryptographic service provider and attach it to a stream. As you write into the stream, the provider automatically encrypts or decrypts the data. The details are in creating and initializing the provider.
The method creates a new AesCryptoServiceProvider to use the AES encryption method.
Next the program must make a key and initialization vector (IV) to initialize the service provider. It starts by finding a supported key size. It starts with a key size of 1,024 and reduces it until the provider's ValidKeySize method returns true. The keyt size you get will depend on things such as which version of Windows you are using.
Note: If you will encrypt and decrypt files on different computers, they must be able to use the same key size. You may need to set this value yourself if one computer can use a larger key than the other.
The program then calls the MakeKeyAndIV method described shortly to create a key and IV. The salt is an array of pseudo-random bytes that you initialize to make breaking the code with a dictionary attack harder. Pick your own set of values for this, don't use the values shown here.
The method then creates an encryptor or decryptor, depending on whether it must encrypt or decrypt the file.
The rest of the method looks messy but is straightforward. It makes a CryptoStream that associates the encryptor/decryptor with the output stream and then writes into the stream.
The following code shows the MakeKeyAndIV method.
|
|
' Use the password to generate key bytes.
Private Sub MakeKeyAndIV(ByVal password As String, ByVal _
salt() As Byte, ByVal key_size_bits As Integer, ByVal _
block_size_bits As Integer, ByRef key() As Byte, ByRef _
iv() As Byte)
Dim derive_bytes As New Rfc2898DeriveBytes(password, _
salt, 1000)
key = derive_bytes.GetBytes(key_size_bits / 8)
iv = derive_bytes.GetBytes(block_size_bits / 8)
End Sub
|
|
This code creates a new Rfc2898DeriveBytes object, passing its constructor your password, salt, and an iteration number. The object applies its operation the indicated number of times to make its result "more random." In this case, it applies a pseudo-random number generator based on the HMACSHA1 algorithm 1000 times to generate its bytes.
The method then uses the object's GetBytes methods to get the key and IV that the program needs to initialize the cryptographic service provider.
Very Important Note: Never store a password inside a program. If you do, then a clever attacker can break open your program, read the password, and decrypt whatever the program wants to keep secret. This is particularly easy for .NET programs where it's relatively easy to read the program's IL code. A much better approach is to make the user enter the password at run time.
Also note that the password must match exactly to decode a file. If the password is off by even a single character, the result will be complete gibberish.
|
|
|
|
|
|