![]() |
General Programming »
Cryptography & Security »
Encryption
Intermediate
.NET cryptography library for files and stringsBy HanreGThis is a VB.NET wrapper for the .NET framework cryptography classes (HashAlgorithm, SymmetricAlgorithm) for working with strings and files. |
VB, Windows, .NET 1.1VS.NET2003, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

Although the cryptography classes of the .NET framework have been discussed at length on CodeProject and elsewhere, I can not help but think that most examples are either over simplified or just not thorough enough. And hence I have written yet another article on the topic.
Most articles show in a few lines of code how to encrypt a string into a byte array. That's just great, but what is a developer to do with just a byte array? Often that is just not useful.
I have also never seen any good examples of how to encrypt files, small or large. Most examples read the contents of the file into a byte array, encrypt it, and write it out to a new file. That's just fabulous for 10 KB files, but what about that 700 MB movie you have on your hard drive? Should you try to cram that 700 MB into your 512 MB RAM, encrypt it, and then write it out to a file? Probably, not such a good idea.
Have you ever tried to decrypt data with an incorrect key? Did you notice that the decryption completes before you get a very descriptive 'Bad Data' error? Imagine loading your encrypted 700 MB movie into your 512 MB RAM, waiting for your poor PC to decrypt the thing only to get a 'Bad Data' error because you made a typo in your password. With an error like that, most people will think the file was corrupted and get rid of it.
With this example, I have tried to create a component that you can use for all your encryption needs with no modifications required.
With this component, you can do the following:
HashAlgorithm;
HashAlgorithm;
SymmetricAlgorithm;
SymmetricAlgorithm;
For background on cryptography, do a search for 'cryptography' or 'encrypting data' at MSDN.
The code in the component is not rocket science at all and the sample app included in the download uses all the functionality of the component, I will therefore only discuss some points of interest below.
bufferSize parameter. This is the amount of data the functions will work with at any given time, in KB. While conducting tests on various machines, a buffer size of 256 KB has consistently given the best performance, and hence that is the default buffer size.
Public Function HashFileToBase64String(ByVal file As String, _
ByVal provider As HashAlgorithm, _
ByVal bufferSize As Integer) As String
Dim fileStream As IO.FileStream
Dim output As String
Dim position As Long
Dim length As Long
Dim storage() As Byte
Dim retStorage() As Byte
Dim bytesRead As Integer
Dim cea As CryptoEventArgs
If bufferSize = 0 Then bufferSize = 256
If file Is Nothing OrElse file = "" Then
Throw New ArgumentNullException("file", _
"'file' should not be Nothing" & _
" (null in C#) or String.Empty.")
End If
fileStream = New IO.FileStream(file, IO.FileMode.Open, _
IO.FileAccess.Read, IO.FileShare.None, _
bufferSize * 1024 - 1)
If provider Is Nothing Then provider = New SHA512Managed
ReDim storage(bufferSize * 1024 - 1)
ReDim retStorage(bufferSize * 1024 - 1)
cea = New CryptoEventArgs
cea.StartTimeInternal = Now
length = fileStream.Length
cea.BytesTotalInternal = length
While position < length
bytesRead = fileStream.Read(storage, 0, _
storage.Length)
position += bytesRead
cea.BytesDoneInternal = position
If Not position = length Then
provider.TransformBlock(storage, 0, _
bytesRead, retStorage, 0)
Else
provider.TransformFinalBlock(storage, 0, bytesRead)
End If
cea.EndTimeInternal = Now
RaiseEvent CryptoProgress(Me, cea)
If cea.Cancel Then Exit While
End While
fileStream.Close()
If Not cea.Cancel Then output = _
Convert.ToBase64String(provider.Hash)
provider.Clear()
cea.EndTimeInternal = Now
RaiseEvent CryptoCompleted(Me, cea)
cea.Dispose()
Return output
End Function
The function contains a private variable, retStorage, which is used in the While loop to receive bytes from the provider.TransformBlock method. The bytes written to this variable are never used anywhere in our function and are overwritten every time the loop executes. However, the variable is required as the provider.TransformBlock method expects it, and it has to have the correct dimension as well. To get the calculated hash value of the file, one has to evaluate the provider.Hash property after the provider.TransformFinalBlock method has been called.
The problem is that if you loop through a file and write random bytes to the file, the OS uses write caching to speed things up a bit. If you immediately delete the file after writing your random bytes to it, the file gets deleted before the data in the cache is written to disk. The file never actually gets overwritten!
Luckily, the good old API can come to our rescue. Our component here contains a class called Files which contains the enumerations, constants, and function declarations that will enable us to open a file where write caching has been disabled for the file.
Friend Function OpenFileForSecureOverwrite(ByVal _
path As String) As FileStream
If Not _openHandle.Equals(IntPtr.Zero) AndAlso _
Not _openHandle.ToInt32 = _
Me.INVALID_HANDLE_VALUE Then
Me.CloseHandle(_openHandle)
_openHandle = IntPtr.Zero
End If
_openHandle = Me.CreateFile(path, FileAccess.GENERIC_WRITE, _
FileShare.FILE_SHARE_READ Or FileShare.FILE_SHARE_WRITE, _
Nothing, CreationDisposition.OPEN_EXISTING, _
FlagsAndAttributes.FILE_FLAG_WRITE_THROUGH, Nothing)
If _openHandle.ToInt32 = Me.INVALID_HANDLE_VALUE Then
Return Nothing
Else
Return New FileStream(_openHandle, IO.FileAccess.ReadWrite)
End If
End Function
We use CreateFile found in Kernel32.dll to open the file and return a handle to the open file. We then pass the handle to the constructor of FileStream to allow us to continue working with the file in .NET. The important bit in all this is the FlagsAndAttributes.FILE_FLAG_WRITE_THROUGH enumeration value that is passed to CreateFile as one of the parameters. This value disables the write caching for the open file.
The obvious drawback here is that performance takes about a 50% hit. Another thing is that some hardware do not support the ability to disable write caching.
The first 127 bytes contain a hash value of the password used to encrypt the data. This hash is used during decryption to determine upfront if the password is correct, thus avoiding that annoying 'Bad Data' error.
The second 127 bytes is used to store the IV used for encrypting the file. Some Microsoft documentation says, the IV does not have to be secret (look at the bottom of the section titled 'Secret-Key Encryption' of Microsoft's Cryptography Overview) and some does. Point is, without the correct IV you cannot decrypt the data properly, and therefore we save it here.
The last two bytes is used to store a value indicating which of the .NET SymmetricAlgorithm derived classes were used for encryption. The decryption functions of our component do not have a provider parameter. The provider is determined by the value saved in the header.
CryptoEventArgs class. The events only fire for file operations and the class exposes properties relating to the progress of the operation. The only writeable property of the class is Cancel. Set this property to True if you wish to cancel the operation. The sample application included in the download uses this functionality. | You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 29 Dec 2005 Editor: Smitha Vijayan |
Copyright 2005 by HanreG Everything else Copyright © CodeProject, 1999-2009 Web15 | Advertise on the Code Project |