One of the worst security issues is "saving a password". The best method is use a HASH (not the already broken MD5). The limitation for this method is obvious: the machine can only authenticate the user, but it can't log-on as the user to another machine.
In the case I was working on the problem was the machine needed to log-on to a different machine in some future time using this user. Which machine is unknown, what time is unknown and most of the other "password saving bypasses" are not applicable.
Bottom line I had to save the password in a DB which can be accessed by some of the users (with permissions and some protection).
I decided to use an asymmetric encryption for the obvious reason, the user inserting (or updating) the data will be able to encrypt it, but won't be able to decrypt it. The methods for the encryption and decryption are as follows:
private static string EncryptText(string data, string PublicKeyXML)
{
System.Security.Cryptography.RSACryptoServiceProvider l_RSA = new System.Security.Cryptography.RSACryptoServiceProvider();
l_RSA.FromXmlString(PublicKeyXML);
byte[] encBytes = Encoding.Default.GetBytes(data);
byte[] encData = l_RSA.Encrypt(encBytes, false);
return ByteAtoString(encData);
}
private static string DecryptText(string data, string PrivateKeyXML)
{
System.Security.Cryptography.RSACryptoServiceProvider l_RSA = new System.Security.Cryptography.RSACryptoServiceProvider();
l_RSA.FromXmlString(PrivateKeyXML);
byte[] encBytes = StringtoByteA(data);
byte[] encData = l_RSA.Decrypt(encBytes, false);
return Encoding.Default.GetString(encData);
}
There's a catch inhere, the byte-array to string conversion (and its reverse). The problem is that using encoding conversion might contain illegal characters. This "string" has to travel from one system to another, using different encoding, locales and all kinds of horrors. So I ended writing in-house "byte to string" and "string to byte" methods.
Remember those methods are NOT optimized. They are however easy to understand and maintain.
private static string ByteToString(byte bt)
{
int tmp_byte = System.Convert.ToInt16(bt);
string res = System.Convert.ToString(tmp_byte, 16); ;
while (res.Length < 2)
{
res = "0" + res;
}
return res;
}
private static string ByteAtoString(byte[] arr)
{
string res = "";
for (int i = 0; i < arr.Length; i++)
{
res += ByteToString(arr[i]);
}
return res;
}
private static byte[] StringtoByteA(string arr)
{
byte[] res = (byte[])System.Array.CreateInstance(typeof(byte), arr.Length / 2);
for (int i = 0; i < arr.Length; i++)
{
int tmp = int.Parse(arr[i].ToString(), System.Globalization.NumberStyles.AllowHexSpecifier) * 16;
i++;
tmp += int.Parse(arr[i].ToString(), System.Globalization.NumberStyles.AllowHexSpecifier);
res[i / 2] = System.Convert.ToByte(tmp);
}
return res;
}
Of course you'll need an XML key in order to use the functions, a simple generator is:
private static void GenerateKeys(out string PrivateKey, out string PublicKey)
{
System.Security.Cryptography.CspParameters persistantCsp = new System.Security.Cryptography.CspParameters();
persistantCsp.KeyContainerName = "LIRON";
System.Security.Cryptography.RSACryptoServiceProvider l_RSA = new System.Security.Cryptography.RSACryptoServiceProvider(persistantCsp);
l_RSA.PersistKeyInCsp = true;
PrivateKey = l_RSA.ToXmlString(true);
PublicKey = l_RSA.ToXmlString(false);
}
P.S. it's a good practice to delete the passwords after usage, this way a break-in would have only a limited time to occur in.
Wednesday, December 17, 2008
Wednesday, December 3, 2008
The methods to verify empty strings
This posting was born after reading a nice comparison in "Maximizing .NET Performance" by Nick Wienholt.
The book claims that comparing an empty string to "" or string.Empty is slower than comparing the Length to 0.
Testing this claim is one of the easiest things to do:
int j = 0;
int k = 0;
int l = 0;
string s = "";
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s == "")
{
j++;
}
}
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s == string.Empty)
{
k++;
}
}
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s.Length == 0)
{
l++;
}
}
Console.WriteLine(DateTime.Now);
Console.ReadKey();
//Avoid the optimiser by "using" the action variables
Console.WriteLine(j);
Console.WriteLine(k);
Console.WriteLine(l);
The results are shocking at first:
1st run:
Compare to "": 32 sec
Compare to string.Empty: 51 sec
Compare the Length to 0: 26 sec
2nd run:
Compare to "": 28 sec
Compare to string.Empty: 48 sec
Compare the Length to 0: 7 sec
3rd run:
Compare to "": 28 sec
Compare to string.Empty: 48 sec
Compare the Length to 0: 7 sec
While the book claimed that comparing to "" or to string.Empty is the same, my computer "translated" the string.Empty to "" prior to the comparison. The result is a slower comparison.
The main conclusion from this experiment is:
TEST THE BLOODY THING ON YOUR PLATFORM! The book is usually tested on some platforms, but not on YOUR platform.
The book claims that comparing an empty string to "" or string.Empty is slower than comparing the Length to 0.
Testing this claim is one of the easiest things to do:
int j = 0;
int k = 0;
int l = 0;
string s = "";
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s == "")
{
j++;
}
}
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s == string.Empty)
{
k++;
}
}
Console.WriteLine(DateTime.Now);
for (int i = 0; i < int.MaxValue; i++)
{
if (s.Length == 0)
{
l++;
}
}
Console.WriteLine(DateTime.Now);
Console.ReadKey();
//Avoid the optimiser by "using" the action variables
Console.WriteLine(j);
Console.WriteLine(k);
Console.WriteLine(l);
The results are shocking at first:
1st run:
Compare to "": 32 sec
Compare to string.Empty: 51 sec
Compare the Length to 0: 26 sec
2nd run:
Compare to "": 28 sec
Compare to string.Empty: 48 sec
Compare the Length to 0: 7 sec
3rd run:
Compare to "": 28 sec
Compare to string.Empty: 48 sec
Compare the Length to 0: 7 sec
While the book claimed that comparing to "" or to string.Empty is the same, my computer "translated" the string.Empty to "" prior to the comparison. The result is a slower comparison.
The main conclusion from this experiment is:
TEST THE BLOODY THING ON YOUR PLATFORM! The book is usually tested on some platforms, but not on YOUR platform.
Subscribe to:
Posts (Atom)