How to improve memory security in Delphi?

Is it possible to "erase" lines in Delphi? Let me explain:

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

Clearly, unencrypted XML is still in DLL memory and therefore vulnerable to validation. Now I'm not going to defend this - the user can create another DLL, but I would like to take a basic step to prevent usernames from sitting in memory for ages. However, I don’t think I can easily erase the memory due to the links. If I go through my DOM (which is a TNativeXML class) and find each instance of a string and then make it something like "aaaaa", will it not really assign a new string pointer to the DOM link and then leave the old string sitting there in memory awaiting redistribution? Is there any way to make sure I'm killing a single and original copy?

Or is there a way in D2007 to tell him to erase all unused memory from the heap? So I can free the DOM and then ask it to erase.

Or should I just continue my next task and forget about it, because it really is not worth the worry.

+3
source share
11 answers

I don’t think it’s worth the trouble, because if the user can read the process memory using the DLL, the same user can also stop execution at any time. Stopping execution before the memory is erased will still give the user full access to unencrypted data.

IMO, any user who is sufficiently interested and able to do what you have described will not be seriously uncomfortable with your memory wiped DLL.

+7
source

Two common points:

Firstly, this is one of those areas where "if you should ask, you probably shouldn't." And please do not take it wrong; I mean the lack of contempt for your programming skills. Just writing secure, cryptographically strong software is something that you are either an expert or not. It is very likely that knowing a little karate is much more dangerous than karate does not know at all. There are many third-party tools for writing secure software in Delphi, with available expert support; I would urge anyone who does not know the deep knowledge of cryptographic services on Windows, the mathematical basics of cryptography and experience in dealing with side-channel attacks, to use them instead of trying to "minimize their own."

To answer your specific question: The Windows API has a number of useful features, such as CryptProtectMemory . However, this will lead to a false understanding of security if you encrypt your memory but have a hole elsewhere in the system or expose a side channel. It might be like putting a lock on your door, but leaving the window open.

+4
source

How about something like that?

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; 
+3
source

DLLs do not have allocated memory; processes are running. The memory allocated by your particular process will be discarded after the process terminates, regardless of whether the DLL hangs (because it is being used by another process) or not.

+2
source

How to decrypt a file in a stream using a SAX processor instead of an XML DOM to do your verification and then overwrite the decrypted stream before releasing it?

+1
source

If you use FastMM memory manager in full debug mode, you can force it to overwrite memory when it is freed.

Usually this behavior is used to detect wild pointers, but it can also be used for your desire.

On the other hand, make sure that you understand what Craig Stuntz writes: do not write these materials for authentication and authorization yourself, if possible, use the underlying operating system.

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

Hello,

Jeroen pluimers

+1
source

Loosely, but you can write down the heap size that you used when you have a heap filled with confidential data, and then when it is released, GetMem will give you a large chunk covering (say) 200% of that. make a Fill on this fragment and make the assumption that any fragmentation will be unreasonably very useful for the examiner. Bree

0
source

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

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

0
source

Is it possible to load decrypted XML into a char or byte array, and not a string? Then there would be no copy-to-write processing, so could you populate memory # 0 before releasing it?

Be careful when assigning a char array to a string, since Delphi has some smart processing here for compatibility with a traditional packed array [1..x] from char.

Alternatively, could you use ShortString?

0
source

If you use XML, even encrypted, to store passwords, you endanger your users. The best approach would be to save the password hash values ​​instead, and then compare the hash against the entered password. The advantage of this approach is that even knowing the value of the hash, you will not know the password that the hash does. Adding a brute force identifier (counting invalid password attempts and blocking an account after a certain number) will further increase security.

There are several methods that you can use to create a hash of a string. A good starting point would be to view the LockBox turbocharged open source project, I believe it has several examples of creating a single hash key.

EDIT

But how do you know the meaning of a hash if its one-way help? If you are truly paranoid, you can change the hash value with something predictable that only you know ... let's say a random number using a specific starting value plus a date. Then you could only save enough hash in your xml so that 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 with the same seed.

0
source

Be careful with functions that try to treat the string as a pointer, and try using FillChar or ZeroMemory to erase the contents of the string.

  • This is wrong (the lines are split, you are casting someone else who is currently using the line)
  • and can cause an access violation (if the line was a constant, it sits on the read-only data page in the process address space, and an attempt to write to it is an access violation)

 procedure BurnString(var s: UnicodeString); begin { If the string is actually constant (reference count of -1), then any attempt to burn it will be an access violation; as the memory is sitting in a read-only data page. But Delphi provides no supported way to get the reference count of a string. It also an issue if someone else is currently using the string (ie Reference Count > 1). If the string were only referenced by the caller (with a reference count of 1), then our function here, which received the string through a var reference would also have the string with a reference count of one. Either way, we can only burn the string if there no other reference. The use of UniqueString, while counter-intuitiave, is the best approach. If you pass an unencrypted password to BurnString as a var parameter, and there were another reference, the string would still contain the password on exit. You can argue that what the point of making a *copy* of a string only to burn the copy. Two things: - if you're debugging it, the string you passed will now be burned (ie your local variable will be empty) - most of the time the RefCount will be 1. When RefCount is one, UniqueString does nothing, so we *are* burning the only string } if Length(s) > 0 then begin System.UniqueString(s); //ensure the passed in string has a reference count of one ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar)); { By not calling UniqueString, we only save on a memory allocation and wipe if RefCnt <> 1 It an unsafe micro-optimization because we're using undocumented offsets to reference counts. And i'm really uncomfortable using it because it really is undocumented. It is absolutely a given that it won't change. And we'd have stopping using Delphi long before it changes. But i just can't do it. } //if PLongInt(PByte(S) - 8)^ = 1 then //RefCnt=1 // ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar)); s := ''; //We want the callee to see their passed string come back as empty (even if it was shared with other variables) end; end; 

Once you have the UnicodeString version, you can create the AnsiString and WideString :

 procedure BurnString(var s: AnsiString); overload; begin if Length(s) > 0 then begin System.UniqueString(s); ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1 // ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); s := ''; end; end; procedure BurnString(var s: WideString); begin //WideStrings (ie COM BSTRs) are not reference counted, but they are modifiable if Length(s) > 0 then begin ZeroMemory(Pointer(s), System.Length(s)*SizeOf(WideChar)); //if PLongInt(PByte(S) - 8)^ = 1 then //RefCount=1 // ZeroMemory(Pointer(s), System.Length(s)*SizeOf(AnsiChar)); s := ''; end; end; 
0
source

All Articles