How to convert a SecureString into an encrypted String in a secure manner?

73 views
Skip to first unread message
Message has been deleted

sp...@brandt-lassen.dk

unread,
Aug 28, 2007, 6:35:57 AM8/28/07
to
I'm designing a system for Windows initiated Single Sign-On against
RACF.

I keep my RACF-passwords in fields of the new .net 2.0 type
System.Security.SecureString. I need to store these passwords in a SQL
server 2005 database between user sessions. Hence, I need to convert
the SecureString into an encrypted string.

I could of course convert the SecureString into a string before
encryption, but this would compromise the security of the system.

My suggestion is to read the bytes of the SecureString byte by byte,
writing the each byte directly into a CryptoStream like this:

private static string SecurePassword2EncryptedPassword(SecureString
password)
{

SymmetricAlgorithm cryptoAlg = GetCryptoAlg();
ICryptoTransform encryptor = cryptoAlg.CreateEncryptor();

MemoryStream outStream = new MemoryStream();
using (CryptoStream encryptStream = new CryptoStream(outStream,
encryptor, CryptoStreamMode.Write))
{

IntPtr bstr = Marshal.SecureStringToBSTR(password);

try
{
byte b;
for (int ofset = 0; ofset < password.Length * 2;
ofset = ofset + 2)
{
b = Marshal.ReadByte(bstr, ofset);
encryptStream.WriteByte(b);

}
b = 0;

encryptStream.FlushFinalBlock();

}
finally
{
Marshal.ZeroFreeBSTR(bstr);
}


return Convert.ToBase64String(outStream.ToArray());

}
}

Is my way, the secure way to converte a SecureString into an encrypted
string? Or should I do something else?

Best regards

Michael Brandt Lassen
3F, Denmark

Michael Brandt Lassen

unread,
Aug 28, 2007, 6:52:01 AM8/28/07
to
Sorry about the HTML, I've deleted the post, but it's still here!? I've
reposted without the HTML.

Best regards

Michael

Joe Kaplan

unread,
Aug 30, 2007, 12:30:38 AM8/30/07
to
This may or may not be a good way to do this. It depends a lot on whether
you use a single symmetric key or multiple different keys, how you store the
keys and what you plan to do about a real random IV. It also depends a bit
on the algorithm used and the key length. It also depends on what the
threat models are.

If you are really concerned about what would happen if someone was able to
get the encrypted data and wanted to recover your passwords, you would
probably want to improve this. For example, if you use a single symmetric
key, recovery of that key will provide access to all of the passwords. If
you don't use a random IV, duplicate passwords will produce duplicate cipher
text which increases vunerability. It also makes the cipher text more
generally vulnerable to brute force attacks that could compromise the key.

In general, it is better to avoid storing encrypted passwords and store
hashes instead, but I'm guessing your system requires you to recover the
plaintext password, so you probably don't have a choice but to encrypt them.
You can probably make this significantly more secure though.

SQL Server 2005 has some built in ability to encrypt stored data, so it
might not be a bad idea to look into those features and try to leverage the
platform. I don't know much about how it works though.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
<sp...@brandt-lassen.dk> wrote in message
news:1188297357.3...@r29g2000hsg.googlegroups.com...

Michael Brandt Lassen

unread,
Aug 31, 2007, 8:54:01 AM8/31/07
to
Hey Joe…

Thank you so much for your answer.

First, let me shine some light on the “threat model” of this application:

The app is running on our internal network, which means inside our firewall.
It’s an ASP.NET 2.0 web app, running on IIS 6.0 with Integrated Windows
Authentication, so only authorised active directory users can access it. The
app is also using Forms Authentication to authenticate the user against the
RACF-backend. It’s this authentication against RACF that we wish to automate
using stored passwords.

Now, about the chosen encryption: Before reading your answer, we were
planning to encrypt the passwords using the symmetric Rijndael algorithm,
with a single 256 bit key for all users.

We also planed to hide the key and initialisation vector (IV) in an
encrypted section of the applications configuration file (web.config), along
the lines of the article: “How To: Encrypt Configuration Sections in ASP.NET
2.0 Using DPAPI” (http://msdn2.microsoft.com/en-us/library/ms998280.aspx).
Finally, we planed to protect the configuration file itself using NTLM.

With our thread model, should we go for a key per user? How should we obtain
these, and where should they be stored?

I’m no sure if I fully understand the issues around a random IV. How do your
suggest we achieve a real random IV?

I’ve already looked into SQL Server 2005 encryption, but I didn’t like the
fact that I had to pass the password unencrypted from the data access layer
to the database. Should I do both, that is encrypt the passwords in the
business layer and encrypt it once again in SQL Server 2005?

And by the way, I’d still like comments on the very conversion from
SecureString to encrypted string.

I just go one crazy idea: What if we generate a key for each user based on
the very password of the user (that is an unencrypted string version) using
the Rfc2898DeriveBytes class, between sessions we could store the key in the
user specific isolated storage. Sure this leads to some web-farm issues…


Best regards,

Michael Brandt Lassen

Joe Kaplan

unread,
Aug 31, 2007, 10:35:54 AM8/31/07
to
The way you were using the interop marshaling classes to get the data out of
secure string and into a byte array looked a little weird to me, but I
haven't played with SecureString that much and wasn't prepared to comment on
it. Looking at it more now, it seems like it is probably fine. You need to
use SecureStringtoBSTR to get the data out and that gives you an IntPtr.
You can then either convert that to a .NET string (not a good idea if the
point was to use a SecureString in the first place) or read the memory into
your CryptoStream via some mechanism. Walking the pointer seems reasonable
as a way to do that, so basically that code looks fine to me. :)

I think your alg and key length is fine. If you feel that you can securely
store that key, then that is fine too. Note that the weakness in your
system probably ends up reducing to how well you are able to secure that
key. If you wanted to make things more secure, you might consider rotating
keys periodically and re-encrypting your values.

Now, on to the IV. You should always use a new, random IV when encrypting
any data with a symmetric alg that uses CBC (which Rjindael does by
default). Using a null IV is bad crypto hygeine, as is using a single fixed
IV for all transformations. The IV is NOT a secret, but it does need to be
different every time.

What you probably want to do is something like this:

Generate new IV via RNG function
Encrypt data using fixed key, new random IV and plaintext binary data
Create a new byte array containing the IV + cipher text (prepend IV probably
easiest)
Convert the entire thing to base64
Save in database

To reverse, you just need to make sure you separate the IV from the cipher
text after you convert from base64 to binary. Since IV is fixed length,
this is easy to do with some array manipulation.

You can also store the IV in a separate column in the database if you like,
but combining the data allows you to keep your current db schema.

So, basically I think you are pretty close to being good here. If you
implement the IV suggestion and store the key securely (whatever that means
:)), this should be pretty hard to compromise.

Note that you can encrypt your SQL network traffic on the wire if you are
using Windows auth by using SSPI encryption.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--

"Michael Brandt Lassen" <MichaelBr...@discussions.microsoft.com>
wrote in message news:E39AB4B6-E5ED-4FFF...@microsoft.com...
> Hey Joe.

> user specific isolated storage. Sure this leads to some web-farm issues.

Reply all
Reply to author
Forward
0 new messages