Are there ever times when you want a cryptographically secure block of memory? Sure there are! Let's say you have a Password EditField that the user puts their secure password into. You don't want that password sitting around in memory as plain text -- that's their password! Instead, you want to make sure that data is secured. Let's make a SecureMemoryBlock class that does this for us.
The first thing we need to do is make a new class and set its super to MemoryBlock (and call it SecureMemoryBlock).
The next thing we need is a way to secure the data. We'll do this with a method called "Encrypt" -- its purpose is to encrypt the data the memory block holds. This is what will secure the data. One of the things that Encrypt needs to do is ensure that the data is a specific multiple of 16 (as per the MSDN docs). So this means we may allocate slightly more memory for the MemoryBlock.
Function Encrypt() As Boolean
#if TargetWin32
Soft Declare Function CryptProtectMemory Lib "Crypt32" ( data as Ptr, size as Integer, flags as Integer ) as Boolean
Const CRYPTPROTECTMEMORY_SAME_PROCESS = 0
Const CRYPTPROTECTMEMORY_BLOCK_SIZE = 16
dim modSize as Integer = self.Size mod CRYPTPROTECTMEMORY_BLOCK_SIZE
if modSize <> 0 then
// Increase the memory block size so that it's the proper length
self.Size = self.Size + CRYPTPROTECTMEMORY_BLOCK_SIZE - modSize
end if
if CryptProtectMemory( self, self.Size, CRYPTPROTECTMEMORY_SAME_PROCESS ) then
mEncrypted = true
return true
end if
#endif
End Function
As you can see, the call is pretty self-explanatory. The first thing it does is ensure that the MemoryBlock is a multple of 16 by expanding the data block. Then it encrypts the data so that only the same process can decrypt it.
The next piece of the puzzle that is needed is the Decrypt function. It's the opposite of the Encrypt function. It should worry about the data block size, but I'm leaving that out under the assumption that the user will not mess with an encrypted data block. However, that assumption is not enfored in code (I will leave that up to the reader). The Decrypt function is simply this:
Function Decrypt() As Boolean
#if TargetWin32
Soft Declare Function CryptUnprotectMemory Lib "Crypt32" ( data as Ptr, size as Integer, flags as Integer ) as Boolean
Const CRYPTPROTECTMEMORY_SAME_PROCESS = 0
if CryptUnprotectMemory( self, self.Size, CRYPTPROTECTMEMORY_SAME_PROCESS ) then
mEncrypted = false
return true
end if
#endif
End Function
The final piece of the puzzle is to ensure that the data held by the MemoryBlock is zero'ed out when it is no longer needed. For instance, let's say you're done with the user's password (encrypted or not) -- there's no reason to keep that memory around. When it's being released back to the OS under normal conditions, it remains in the same state it was when the MemoryBlock is released. However, if it's decrypted, then the user's plaintext password is available for anyone to read. So we'll zero that memory out.
Sub Destructor()
// No matter what, we want to zero out the
// memory we used to point to so that it's
// not sitting in memory.
#if TargetWin32
Declare Sub memset Lib "msvcrt" ( data as Ptr, value as Integer, size as Integer )
memset( self, 0, self.Size )
#endif
End Sub
Ta da! That's all there is to it -- once you've obtained the sensitive data, you call Encrypt on it to ensure that it stays encrypted in memory. Whenever you need it in plain text again, you can Decrypt it (but be sure to do this as sparingly as possible, for obvious security reasons). Note that this functionality should never be used to store the data on disk. It is for in-memory encryption only! If you want to store the memory to disk, then you should use the CryptProtectData function instead. Another thing to note is that some functionality is left to the user. Namely, once the data has been encrypted, and subsequent calls to modify or resize the contents of the MemoryBlock are illegal and will cause nothing but heartache and problems.
Enjoy!
This is neat -- the first line of every paragraph (including code) is suddenly being fully-justified, while the rest are all left-justified. Man, MT is a pile of crap some days.