Discussion:
ZeroMemory
(too old to reply)
Meron LAVIE
2009-11-30 10:00:49 UTC
Permalink
I am writing some encryption utilities. Obviously, I am interested in
ensuring that no trace of the clear, unencrypted data will be left in
memory. Therefore, I dutifully called RtlZeroMemory via pinvoke. This works
fine on byte[] (the source clear data), but when I try it on a String, all
sorts of memory corruption ensues and even VisualStudio itself starts acting
stange (buttons dissapear, etc).

Please find below my code. Any suggestions would be appreciated.

Lavie

[code]
/// <summary>

/// Sets properties for a SymmetricAlgorithm

/// </summary>

/// <param name="symmetricAlgorithm">SymmetricAlgorithm whose properties
should be set</param>

/// <param name="password">Password - WARNING: this methods trounces the
passwords with zeros</param>

private static void SetEncryptionAlgorithmProperties(SymmetricAlgorithm
symmetricAlgorithm, string password)

{

GCHandle gchPassword = GCHandle.Alloc(password, GCHandleType.Pinned);

PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, SALT);


symmetricAlgorithm.Key =
pdb.GetBytes(symmetricAlgorithm.LegalKeySizes[0].MinSize / BITS_IN_BYTE);

symmetricAlgorithm.IV =
pdb.GetBytes(symmetricAlgorithm.LegalBlockSizes[0].MinSize / BITS_IN_BYTE);

// Trounce the password!

Helper.ZeroMemory(gchPassword.AddrOfPinnedObject(),
(uint)(password.Length*2));

gchPassword.Free();

}

[/code]



[code]

/// <summary>

/// Zero memory (fill with zeros)

/// </summary>

/// <param name="destinationObject">Address of object in memory, at which
trouncing should commence</param>

/// <param name="length">How many bytes to trounce</param>

/// <returns>Did trouncing succeed</returns>

[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory", SetLastError=true)]

public static extern bool ZeroMemory(IntPtr destinationObject, uint length);

[code]
"Patrice" <http://scribe-en.blogspot.com/>
2009-11-30 11:05:49 UTC
Permalink
It reminds of a SecureString class I never used but that could be usefull in
your case :
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx

I gave a quick look and it looks like it is used in association with classes
in the Marshalling namespace allowing to get and clear the value hold in an
unmanaged buffer...

If you still use ZeroMemory I would double check how string are stored.
First they are reference types so that address you get could be those of the
string pointer rather than the actual data plus the string length is perhaps
stored somewhere.

My approach would be first to try to read the string data to make sure the
method used to get at the string location is correct.
--
Patrice
Post by Meron LAVIE
I am writing some encryption utilities. Obviously, I am interested in
ensuring that no trace of the clear, unencrypted data will be left in
memory. Therefore, I dutifully called RtlZeroMemory via pinvoke. This works
fine on byte[] (the source clear data), but when I try it on a String, all
sorts of memory corruption ensues and even VisualStudio itself starts
acting stange (buttons dissapear, etc).
Please find below my code. Any suggestions would be appreciated.
Lavie
[code]
/// <summary>
/// Sets properties for a SymmetricAlgorithm
/// </summary>
/// <param name="symmetricAlgorithm">SymmetricAlgorithm whose properties
should be set</param>
/// <param name="password">Password - WARNING: this methods trounces the
passwords with zeros</param>
private static void SetEncryptionAlgorithmProperties(SymmetricAlgorithm
symmetricAlgorithm, string password)
{
GCHandle gchPassword = GCHandle.Alloc(password, GCHandleType.Pinned);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, SALT);
symmetricAlgorithm.Key =
pdb.GetBytes(symmetricAlgorithm.LegalKeySizes[0].MinSize / BITS_IN_BYTE);
symmetricAlgorithm.IV =
pdb.GetBytes(symmetricAlgorithm.LegalBlockSizes[0].MinSize /
BITS_IN_BYTE);
// Trounce the password!
Helper.ZeroMemory(gchPassword.AddrOfPinnedObject(),
(uint)(password.Length*2));
gchPassword.Free();
}
[/code]
[code]
/// <summary>
/// Zero memory (fill with zeros)
/// </summary>
/// <param name="destinationObject">Address of object in memory, at which
trouncing should commence</param>
/// <param name="length">How many bytes to trounce</param>
/// <returns>Did trouncing succeed</returns>
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory",
SetLastError=true)]
public static extern bool ZeroMemory(IntPtr destinationObject, uint length);
[code]
Meron LAVIE
2009-11-30 12:05:37 UTC
Permalink
Thanks Patrice.

Upon further analysis - I discovered the wonderful world of "Intern". In
fact, for testing purposes, my encryption password and decryption (obviously
identical) were passed as 2 literals, e.g.,:

<code>
string encryptedByteArray = Encrypt(clearByteArray, "myPassword");
strinf decryptedByteArray = Decrypt(encryptedByteArray, "myPassword");
</code>

As it turns out, our "friend" the CLR (and with firends like that, who needs
enemies???), in order to save memory in fact created only ONE entry in the
Intern table. Thus, the following occured:

1) Encryption was performed using password "myPassword".
2) "myPassword" was zeroed-out - but this also meant that "myPassword" was
zeroed out when used by any later method, as both literals shared the same
memory.
3) Decryption was performed using "\0" (as the Intern table set aside for
the literal value of "myPassword" had already been zeroed, due to "Intern"
behavior).
4) From then on, all sorts of other things started to go very wrong as I
made later use of the literals...

I *heartily* recommend that people read up on Intern. I am embarrased to say
that after nearly 8 years in .NET that this is the first time I've
encountered this.

Lavie
Post by "Patrice" <http://scribe-en.blogspot.com/>
It reminds of a SecureString class I never used but that could be usefull
http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx
I gave a quick look and it looks like it is used in association with
classes in the Marshalling namespace allowing to get and clear the value
hold in an unmanaged buffer...
If you still use ZeroMemory I would double check how string are stored.
First they are reference types so that address you get could be those of
the string pointer rather than the actual data plus the string length is
perhaps stored somewhere.
My approach would be first to try to read the string data to make sure the
method used to get at the string location is correct.
--
Patrice
Post by Meron LAVIE
I am writing some encryption utilities. Obviously, I am interested in
ensuring that no trace of the clear, unencrypted data will be left in
memory. Therefore, I dutifully called RtlZeroMemory via pinvoke. This
works fine on byte[] (the source clear data), but when I try it on a
String, all sorts of memory corruption ensues and even VisualStudio itself
starts acting stange (buttons dissapear, etc).
Please find below my code. Any suggestions would be appreciated.
Lavie
[code]
/// <summary>
/// Sets properties for a SymmetricAlgorithm
/// </summary>
/// <param name="symmetricAlgorithm">SymmetricAlgorithm whose properties
should be set</param>
/// <param name="password">Password - WARNING: this methods trounces the
passwords with zeros</param>
private static void SetEncryptionAlgorithmProperties(SymmetricAlgorithm
symmetricAlgorithm, string password)
{
GCHandle gchPassword = GCHandle.Alloc(password, GCHandleType.Pinned);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, SALT);
symmetricAlgorithm.Key =
pdb.GetBytes(symmetricAlgorithm.LegalKeySizes[0].MinSize / BITS_IN_BYTE);
symmetricAlgorithm.IV =
pdb.GetBytes(symmetricAlgorithm.LegalBlockSizes[0].MinSize /
BITS_IN_BYTE);
// Trounce the password!
Helper.ZeroMemory(gchPassword.AddrOfPinnedObject(),
(uint)(password.Length*2));
gchPassword.Free();
}
[/code]
[code]
/// <summary>
/// Zero memory (fill with zeros)
/// </summary>
/// <param name="destinationObject">Address of object in memory, at which
trouncing should commence</param>
/// <param name="length">How many bytes to trounce</param>
/// <returns>Did trouncing succeed</returns>
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory",
SetLastError=true)]
public static extern bool ZeroMemory(IntPtr destinationObject, uint length);
[code]
"Patrice" <http://scribe-en.blogspot.com/>
2009-11-30 12:58:27 UTC
Permalink
Great to see it solved.. One more reason to be always as close as possible
to the actual code even in test code (sucha s suign variables rather than
constants even if the variable is filled with a test value).
--
Patrice
Peter Duniho
2009-11-30 18:04:19 UTC
Permalink
Post by Meron LAVIE
[...]
I *heartily* recommend that people read up on Intern. I am embarrased to
say that after nearly 8 years in .NET that this is the first time I've
encountered this.
Well, string interning is an implementation detail that most programmers
never have to concern themselves with, because they aren't trying to
modify what are normally opaque data structures.

I recommend you use the SecureString class Patrice mentioned, or write
your own. Don't muck with the internals of the System.String class.
Even if you figure out how to get things to work now, there could be
some change in implementation later that breaks your code.

Pete
MarkusSchaber
2009-11-30 13:13:19 UTC
Permalink
Hi, Meron,
Post by Meron LAVIE
I am writing some encryption utilities. Obviously, I am interested in
ensuring that no trace of the clear, unencrypted data will be left in
memory. Therefore, I dutifully called RtlZeroMemory via pinvoke. This works
fine on byte[] (the source clear data), but when I try it on a String, all
sorts of memory corruption ensues and even VisualStudio itself starts acting
stange (buttons dissapear, etc).
Without taking special precautions like pinning etc, this won't work
reliably with .NET as the garbage collector is free to relocate (->
copy) objects at will. So even by breaking the immutability of strings
by zeroing out the internal buffer (which can lead to lots of ugly
evil things), you cannot guarantee that you removed every trace from
memory.

Markus
Kerem Gümrükcü
2009-12-01 04:53:49 UTC
Permalink
Hi,
Post by MarkusSchaber
you cannot guarantee that you removed every trace from
memory.
Thats true, but you can work with either raw pinvoke memory
and functions and then zero everything you used, fore garbage
collect on several "confidential" data and objects (but only at a certain
level for sure). Another more secure way is using the Crypto API
of Windows, since it works with opaque handles and no sensetive
data can be accessed that easy. It also has some secure memory
allocation/deallocation functions (mostly internally standard WinAPI),
but a good start! But i think using SecureString is the best thing
if you want to stay on pure and stable .NET Code. here is a Helper
i wrote (for the OP if he has use for it), that creates a SecureString
from a ordinary String:


public static SecureString CreateSecureString(string UnsecureString)
{
SecureString ss = new SecureString();

foreach (char c in UnsecureString.ToCharArray())
{
ss.AppendChar(c);
}

return ss;
}


Good Luck to the OP!


Regards

Kerem
--
-----------------------
Beste Grüsse / Best regards / Votre bien devoue
Kerem Gümrükcü
Latest Project: http://www.pro-it-education.de/software/deviceremover
Latest Open-Source Projects: http://entwicklung.junetz.de
-----------------------
Tom Shelton
2009-11-30 14:54:03 UTC
Permalink
Post by Meron LAVIE
I am writing some encryption utilities. Obviously, I am interested in
ensuring that no trace of the clear, unencrypted data will be left in
memory. Therefore, I dutifully called RtlZeroMemory via pinvoke. This works
fine on byte[] (the source clear data), but when I try it on a String, all
sorts of memory corruption ensues and even VisualStudio itself starts acting
stange (buttons dissapear, etc).
Please find below my code. Any suggestions would be appreciated.
Lavie
[code]
/// <summary>
/// Sets properties for a SymmetricAlgorithm
/// </summary>
/// <param name="symmetricAlgorithm">SymmetricAlgorithm whose properties
should be set</param>
/// <param name="password">Password - WARNING: this methods trounces the
passwords with zeros</param>
private static void SetEncryptionAlgorithmProperties(SymmetricAlgorithm
symmetricAlgorithm, string password)
{
GCHandle gchPassword = GCHandle.Alloc(password, GCHandleType.Pinned);
PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, SALT);
symmetricAlgorithm.Key =
pdb.GetBytes(symmetricAlgorithm.LegalKeySizes[0].MinSize / BITS_IN_BYTE);
symmetricAlgorithm.IV =
pdb.GetBytes(symmetricAlgorithm.LegalBlockSizes[0].MinSize / BITS_IN_BYTE);
// Trounce the password!
Helper.ZeroMemory(gchPassword.AddrOfPinnedObject(),
(uint)(password.Length*2));
gchPassword.Free();
}
[/code]
[code]
/// <summary>
/// Zero memory (fill with zeros)
/// </summary>
/// <param name="destinationObject">Address of object in memory, at which
trouncing should commence</param>
/// <param name="length">How many bytes to trounce</param>
/// <returns>Did trouncing succeed</returns>
[DllImport("KERNEL32.DLL", EntryPoint = "RtlZeroMemory", SetLastError=true)]
public static extern bool ZeroMemory(IntPtr destinationObject, uint length);
[code]
I'm no expert on it - but have you looked at System.Secuirty.SecureString?
--
Tom Shelton
Loading...