views:

720

answers:

10

Is it possible to "wipe" strings in Delphi? Let me explain:

I am writing an application that will include a DLL to authorise users. It will read an encrypted file into an XML DOM, use the information there, and then release the DOM.

It is obvious that the unencrypted XML is still sitting in the memory of the DLL, and therefore vulnerable to examination. Now, I'm not going to go overboard in protecting this - the user could create another DLL - but I'd like to take a basic step to preventing user names from sitting in memory for ages. However, I don't think I can easily wipe the memory anyway because of references. If I traverse my DOM (which is a TNativeXML class) and find every string instance and then make it into something like "aaaaa", then will it not actually assign the new string pointer to the DOM reference, and then leave the old string sitting there in memory awaiting re-allocation? Is there a way to be sure I am killing the only and original copy?

Or is there in D2007 a means to tell it to wipe all unused memory from the heap? So I could release the DOM, and then tell it to wipe.

Or should I just get on with my next task and forget this because it is really not worth bothering.

A: 

Messy but you could make a note of the heap size that you've used while you've got the heap filled with sensitive data then when that is released do a GetMem to allocate you a large chunk spanning (say) 200% of that. do a Fill on that chunk and make the assumption that any fragmentation is unlinkely to be of much use to an examiner. Bri

Brian Frost
I thought about that, but with memory managers being much smarter, and allocating from blocks for different sizes, a 16-byte string is likely to come from a totally different sub-heap to a 12,000 byte block.
mj2008
+1  A: 

How about decrypting the file to a stream, using a SAX processor instead of an XML DOM to do your verification and then overwriting the decrypted stream before freeing it?

Bruce McGee
I've pondered that, but I also need to be able to update the XML in some builds of the DLL, so the DOM makes things easier.
mj2008
You can update XML using SAX.
Bruce McGee
@Bruce McGee: If you are thinking of a TMemoryStream, what about memory reallocations that can not be performed in-place, wouldn't they leave partial decrypted data somewhere without any way of knowing about them?
mghie
I guess there will always be something left in memory.
Bruce McGee
A: 

How about keeping the password as a hash value in the XML and verify by comparing the hash of the input password with the hashed password in your XML.

Edit: You can keep all the sensitive data encrypted and decrypt only at the last possible moment.

Schalk Versteeg
The password is hashed, as you suggest. Only the user names and their access levels are "visible", but even those are a clue to a hacker.
mj2008
keep those values encrypted and decrypt just in time or go to the next task.
Schalk Versteeg
+1  A: 

DLLs don't own allocated memory, processes do. The memory allocated by your specific process will be discarded once the process terminates, whether the DLL hangs around (because it is in use by another process) or not.

anon
Indeed, but the DLL could be loaded by a hacker's application, and the call made to the function that loads the DOM. At that point, they can breakpoint and use the debugger to see memory. Obviously if they breakpoint in my code, I can't stop that, but I'd like it to be clean on my return.
mj2008
@mj2008: It's actually worse than that - it is enough to have permission to debug your own application, there's no need to create a dummy app and find out how to call your DLL. The cracker basically just needs windbg and a little know-how.
mghie
+6  A: 

I don't think it is worth bothering with, because if a user can read the memory of the process using the DLL, the same user can also halt the execution at any given point in time. Halting the execution before the memory is wiped will still give the user full access to the unencrypted data.

IMO any user sufficiently interested and able to do what you describe will not be seriously inconvenienced by your DLL wiping the memory.

mghie
+4  A: 

Two general points about this:

First, this is one of those areas where "if you have to ask, you probably shouldn't be doing this." And please don't take that the wrong way; I mean no disrespect to your programming skills. It's just that writing secure, cryptographically strong software is something that either you're an expert at or you aren't. Very much in the same way that knowing "a little bit of karate" is much more dangerous than knowing no karate at all. There are a number of third-party tools for writing secure software in Delphi which have expert support available; I would strongly encourage anyone without a deep knowledge of cryptographic services in Windows, the mathematical foundations of cryptography, and experience in defeating side channel attacks to use them instead of attempting to "roll their own."

To answer your specific question: The Windows API has a number of functions which are helpful, such as CryptProtectMemory. However, this will bring a false sense of security if you encrypt your memory, but have a hole elsewhere in the system, or expose a side channel. It can be like putting a lock on your door but leaving the window open.

Craig Stuntz
Thanks - no offence taken! I'm quite aware of the difficulties, hence me also asking whether it is worth even bothering. I'll look at the API - that might help make it just hard enough to discourage the casual hacker.
mj2008
@Craig Stuntz: Thanks for posting the link to that API function, there's interesting info about memory contents being visible in the page file - I had not thought of that.
mghie
A: 

If you use the FastMM memory manager in Full Debug mode, then you can force it to overwrite memory when it is being freed.

Normally that behaviour is used to detect wild pointers, but it can also be used for what your want.

On the other hand, make sure you understand what Craig Stuntz writes: do not write this authentication and authorization stuff yourself, use the underlying operating system whenever possible.

BTW: Hallvard Vassbotn wrote a nice blog about FastMM: http://hallvards.blogspot.com/2007/05/use-full-fastmm-consider-donating.html

Regards,

Jeroen Pluimers

Jeroen Pluimers
A: 

Would it be possible to load the decrypted XML into an array of char or byte rather than a string? Then there would be no copy-on-write handling, so you would be able to backfill the memory with #0's before freeing?

Be careful if assigning array of char to string, as Delphi has some smart handling here for compatibility with traditional packed array[1..x] of char.

Also, could you use ShortString?

Gerry
A good thought - avoid the smart string completely. The DOM probably doesn't do that, but it would be smart.
mj2008
A: 

If your using XML, even encrypted, to store passwords your putting your users at risk. A better approach would be to store the hash values of the passwords instead, and then compare the hash against the entered password. The advantage of this approach is that even in knowing the hash value, you won't know the password which makes the hash. Adding a brute force identifier (count invalid password attempts, and lock the account after a certain number) will increase security even further.

There are several methods you can use to create a hash of a string. A good starting point would be to look at the turbo power open source project "LockBox", I believe it has several examples of creating one way hash keys.

EDIT

But how does knowing the hash value if its one way help? If your really paranoid, you can modify the hash value by something prediticable that only you would know... say, a random number using a specific seed value plus the date. You could then store only enough of the hash in your xml so you can use it as a starting point for comparison. The nice thing about psuedo random number generators is that they always generate the same series of "random" numbers given the same seed.

skamradt
All good points, and implemented already, but not actually answering the core issue of security. If the attacker can see the hash, they are a big step forward. My question was trying to reduce the amount of time the hash is available in memory.
mj2008
A: 

How about something like this?

procedure WipeString(const str: String); var i:Integer; iSize:Integer; pData:PChar;

begin iSize := Length(str); pData := PChar(str);

for i := 0 to 7 do
begin
  ZeroMemory(pData, iSize);
  FillMemory(pData, iSize, $FF); // 1111 1111
  FillMemory(pData, iSize, $AA); // 1010 1010
  FillMemory(pData, iSize, $55); // 0101 0101
  ZeroMemory(pData, iSize);
end;

end;

jack