websitepanel/WebsitePanel/Sources/WebsitePanel.Providers.Base/Common/PasswdHelper.cs
2011-07-13 16:07:32 -07:00

209 lines
6 KiB
C#

using System;
using System.Security.Cryptography;
using System.Text;
namespace WebsitePanel.Providers.Common
{
public class PasswdHelper
{
protected static readonly string MD5_MAGIC_PREFIX = "$apr1$";
protected const int MD5_DIGESTSIZE = 16;
protected static readonly string SHA_MAGIC_PREFIX = "{SHA}";
private static readonly string itoa64 = /* 0 ... 63 => ASCII - 64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static Random _random;
static PasswdHelper()
{
_random = new Random();
}
public static string to64(ulong v, int n)
{
StringBuilder sb = new StringBuilder();
while (--n >= 0)
{
sb.Append(itoa64[(int)v & 0x3f]);
v >>= 6;
}
return sb.ToString();
}
public static string ByteArrayToHexString(byte[] ba)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in ba)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
public static byte[] getMD5HashHex(string s)
{
MD5 md5 = MD5.Create();
return md5.ComputeHash(Encoding.ASCII.GetBytes(s));
}
public static string MD5Encode(string pw, string salt)
{
// äëÿ ïðîâåðêè ïðèõîäèò òàêîå:
// $apr1$Vs5.....$iSQlpTkND9RjL7iAMTjDt.
// äëÿ ãåíåðèðîâàíèÿ ïàðîëÿ ïðèõîäèò ñëó÷àéíàÿ ñòðîêà - ñîëü
string password;
byte[] final;
// íàéä¸ì ñîëü, åñëè â êà÷åñòâå ñîëè ïðèø¸ë óæå õýø
// 1. Óáåð¸ì ìàãè÷åñêèé $apr1$
if (salt.StartsWith(MD5_MAGIC_PREFIX))
{
salt = salt.Substring(MD5_MAGIC_PREFIX.Length);
}
// 2. Íàéä¸ì ñîëü äî ïåðâîãî '$' Èëè 8 ñèìâîëîâ
int sp = salt.IndexOf('$');
if (sp < 0 || sp > 8) sp = 8;
salt = salt.Substring(0, sp);
//Debug.WriteLine(string.Format("salt [{0}]", salt));
ByteVector s = new ByteVector();
ByteVector s1 = new ByteVector();
s.Add(pw);
s.Add(MD5_MAGIC_PREFIX);
s.Add(salt);
s1.Add(pw);
s1.Add(salt);
s1.Add(pw);
final = s1.GetMD5Hash();
for (int i = pw.Length; i > 0; i -= MD5_DIGESTSIZE)
{
s.Add(final, 0, (i > MD5_DIGESTSIZE) ? MD5_DIGESTSIZE : i);
}
for (int i = 0; i < final.Length; i++)
final[i] = 0;
for (int i = pw.Length; i != 0; i >>= 1)
{
// (i & 1) â àïà÷å
if ((i & 0x01) == 1)
{
s.Add(final, 0, 1);
}
else
{
s.Add(pw.Substring(0, 1));
}
}
final = s.GetMD5Hash();
for (int i = 0; i < 1000; i++)
{
s1.Clear();
if ((i & 1) != 0)
{
s1.Add(pw);
}
else
{
s1.Add(final);
}
if ((i % 3) != 0)
{
s1.Add(salt);
}
if ((i % 7) != 0)
{
s1.Add(pw);
}
if ((i & 1) != 0)
{
s1.Add(final);
}
else
{
s1.Add(pw);
}
final = s1.GetMD5Hash();
}
password = "";
ulong l;
l = ((ulong)final[0] << 16) | ((ulong)final[6] << 8) | ((ulong)final[12]);
password += PasswdHelper.to64(l, 4);
l = ((ulong)final[1] << 16) | ((ulong)final[7] << 8) | ((ulong)final[13]);
password += PasswdHelper.to64(l, 4);
l = ((ulong)final[2] << 16) | ((ulong)final[8] << 8) | ((ulong)final[14]);
password += PasswdHelper.to64(l, 4);
l = ((ulong)final[3] << 16) | ((ulong)final[9] << 8) | ((ulong)final[15]);
password += PasswdHelper.to64(l, 4);
l = ((ulong)final[4] << 16) | ((ulong)final[10] << 8) | ((ulong)final[5]);
password += PasswdHelper.to64(l, 4);
l = ((ulong)final[11]);
password += PasswdHelper.to64(l, 2);
password = string.Format("{0}{1}${2}", MD5_MAGIC_PREFIX, salt, password);
return password;
}
public static string SHA1Encode(string clear)
{
if (clear.StartsWith(SHA_MAGIC_PREFIX))
{
clear = clear.Substring(SHA_MAGIC_PREFIX.Length);
}
SHA1 sha = new SHA1CryptoServiceProvider();
string cr = Convert.ToBase64String(
sha.ComputeHash(Encoding.Default.GetBytes(clear))
);
return SHA_MAGIC_PREFIX + cr;
}
public static string GetRandomSalt()
{
return to64((ulong)_random.Next(), 8);
}
public static string DigestEncode(string username, string realm, string passwd)
{
MD5 md5 = MD5.Create();
byte[] b = md5.ComputeHash(Encoding.ASCII.GetBytes(
string.Format("{0}:{1}:{2}", username, realm, passwd)
));
StringBuilder sb = new StringBuilder(b.Length*2);
for (int i = 0; i < b.Length; ++i)
{
sb.Append( String.Format("{0:x2}", b[i]) );
}
return sb.ToString();
}
}
}