Im, yeni bir ASP.Net çözüm için bazı eski ALP kullanıcı hesaplarını taşıma çalışıyorum, ve kullanıcıların eski şifreleri kullanmak edebilmek için isterim.
Ancak, bu çalışması için için, ben yeni yazdığınız şifre dayalı bir yeni hesaplanan birine eski sağlamalarının karşılaştırmak gerekiyor.
Etrafa arandı, ve this crypt()
PHP ile adlandırılan uygulama olarak bulundu:
char *
crypt_md5(const char *pw, const char *salt)
{
MD5_CTX ctx,ctx1;
unsigned long l;
int sl, pl;
u_int i;
u_char final[MD5_SIZE];
static const char *sp, *ep;
static char passwd[120], *p;
static const char *magic = "$1$";
/* Refine the Salt first */
sp = salt;
/* If it starts with the magic string, then skip that */
if(!strncmp(sp, magic, strlen(magic)))
sp += strlen(magic);
/* It stops at the first '$', max 8 chars */
for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
continue;
/* get the length of the true salt */
sl = ep - sp;
MD5Init(&ctx);
/* The password first, since that is what is most unknown */
MD5Update(&ctx, (const u_char *)pw, strlen(pw));
/* Then our magic string */
MD5Update(&ctx, (const u_char *)magic, strlen(magic));
/* Then the raw salt */
MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
/* Then just as many characters of the MD5(pw,salt,pw) */
MD5Init(&ctx1);
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
MD5Final(final, &ctx1);
for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
MD5Update(&ctx, (const u_char *)final,
(u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
/* Don't leave anything around in vm they could use. */
memset(final, 0, sizeof(final));
/* Then something really weird... */
for (i = strlen(pw); i; i >>= 1)
if(i & 1)
MD5Update(&ctx, (const u_char *)final, 1);
else
MD5Update(&ctx, (const u_char *)pw, 1);
/* Now make the output string */
strcpy(passwd, magic);
strncat(passwd, sp, (u_int)sl);
strcat(passwd, "$");
MD5Final(final, &ctx);
/*
* and now, just to make sure things don't run too fast
* On a 60 Mhz Pentium this takes 34 msec, so you would
* need 30 seconds to build a 1000 entry dictionary...
*/
for(i = 0; i < 1000; i++) {
MD5Init(&ctx1);
if(i & 1)
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
else
MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
if(i % 3)
MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
if(i % 7)
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
if(i & 1)
MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
else
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
MD5Final(final, &ctx1);
}
p = passwd + strlen(passwd);
l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
_crypt_to64(p, l, 4); p += 4;
l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
_crypt_to64(p, l, 4); p += 4;
l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
_crypt_to64(p, l, 4); p += 4;
l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
_crypt_to64(p, l, 4); p += 4;
l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
_crypt_to64(p, l, 4); p += 4;
l = final[11];
_crypt_to64(p, l, 2); p += 2;
*p = '\0';
/* Don't leave anything around in vm they could use. */
memset(final, 0, sizeof(final));
return (passwd);
}
Ve, burada beklenen maçı ile birlikte, C # benim sürümüdür.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography;
using System.IO;
using System.Management;
namespace Test
{
class Program
{
static void Main(string[] args)
{
byte[] salt = Encoding.ASCII.GetBytes("$1$ls3xPLpO$Wu/FQ.PtP2XBCqrM.w847/");
Console.WriteLine("Hash: " + Encoding.ASCII.GetString(salt));
byte[] passkey = Encoding.ASCII.GetBytes("suckit");
byte[] newhash = md5_crypt(passkey, salt);
Console.WriteLine("Hash2: " + Encoding.ASCII.GetString(newhash));
byte[] newhash2 = md5_crypt(passkey, newhash);
Console.WriteLine("Hash3: " + Encoding.ASCII.GetString(newhash2));
Console.ReadKey(true);
}
public static byte[] md5_crypt(byte[] pw, byte[] salt)
{
MemoryStream ctx, ctx1;
ulong l;
int sl, pl;
int i;
byte[] final;
int sp, ep; //** changed pointers to array indices
MemoryStream passwd = new MemoryStream();
byte[] magic = Encoding.ASCII.GetBytes("$1$");
// Refine the salt first
sp = 0; //** Changed to an array index, rather than a pointer.
// If it starts with the magic string, then skip that
if (salt[0] == magic[0] &&
salt[1] == magic[1] &&
salt[2] == magic[2])
{
sp += magic.Length;
}
// It stops at the first '$', max 8 chars
for (ep = sp;
(ep + sp < salt.Length) && //** Converted to array indices, and rather than check for null termination, check for the end of the array.
salt[ep] != (byte)'$' &&
ep < (sp + 8);
ep++)
continue;
// Get the length of the true salt
sl = ep - sp;
ctx = MD5Init();
// The password first, since that is what is most unknown
MD5Update(ctx, pw, pw.Length);
// Then our magic string
MD5Update(ctx, magic, magic.Length);
// Then the raw salt
MD5Update(ctx, salt, sp, sl);
// Then just as many characters of the MD5(pw,salt,pw)
ctx1 = MD5Init();
MD5Update(ctx1, pw, pw.Length);
MD5Update(ctx1, salt, sp, sl);
MD5Update(ctx1, pw, pw.Length);
final = MD5Final(ctx1);
for(pl = pw.Length; pl > 0; pl -= final.Length)
MD5Update(ctx, final,
(pl > final.Length ? final.Length : pl));
// Don't leave anything around in vm they could use.
for (i = 0; i < final.Length; i++) final[i] = 0;
// Then something really weird...
for (i = pw.Length; i != 0; i >>= 1)
if((i & 1) != 0)
MD5Update(ctx, final, 1);
else
MD5Update(ctx, pw, 1);
// Now make the output string
passwd.Write(magic, 0, magic.Length);
passwd.Write(salt, sp, sl);
passwd.WriteByte((byte)'$');
final = MD5Final(ctx);
// and now, just to make sure things don't run too fast
// On a 60 Mhz Pentium this takes 34 msec, so you would
// need 30 seconds to build a 1000 entry dictionary...
for(i = 0; i < 1000; i++)
{
ctx1 = MD5Init();
if((i & 1) != 0)
MD5Update(ctx1, pw, pw.Length);
else
MD5Update(ctx1, final, final.Length);
if((i % 3) != 0)
MD5Update(ctx1, salt, sp, sl);
if((i % 7) != 0)
MD5Update(ctx1, pw, pw.Length);
if((i & 1) != 0)
MD5Update(ctx1, final, final.Length);
else
MD5Update(ctx1, pw, pw.Length);
final = MD5Final(ctx1);
}
//** Section changed to use a memory stream, rather than a byte array.
l = (((ulong)final[0]) << 16) | (((ulong)final[6]) << 8) | ((ulong)final[12]);
_crypt_to64(passwd, l, 4);
l = (((ulong)final[1]) << 16) | (((ulong)final[7]) << 8) | ((ulong)final[13]);
_crypt_to64(passwd, l, 4);
l = (((ulong)final[2]) << 16) | (((ulong)final[8]) << 8) | ((ulong)final[14]);
_crypt_to64(passwd, l, 4);
l = (((ulong)final[3]) << 16) | (((ulong)final[9]) << 8) | ((ulong)final[15]);
_crypt_to64(passwd, l, 4);
l = (((ulong)final[4]) << 16) | (((ulong)final[10]) << 8) | ((ulong)final[5]);
_crypt_to64(passwd, l, 4);
l = final[11];
_crypt_to64(passwd, l, 2);
byte[] buffer = new byte[passwd.Length];
passwd.Seek(0, SeekOrigin.Begin);
passwd.Read(buffer, 0, buffer.Length);
return buffer;
}
public static MemoryStream MD5Init()
{
return new MemoryStream();
}
public static void MD5Update(MemoryStream context, byte[] source, int length)
{
context.Write(source, 0, length);
}
public static void MD5Update(MemoryStream context, byte[] source, int offset, int length)
{
context.Write(source, offset, length);
}
public static byte[] MD5Final(MemoryStream context)
{
long location = context.Position;
byte[] buffer = new byte[context.Length];
context.Seek(0, SeekOrigin.Begin);
context.Read(buffer, 0, (int)context.Length);
context.Seek(location, SeekOrigin.Begin);
return MD5.Create().ComputeHash(buffer);
}
// Changed to use a memory stream rather than a character array.
public static void _crypt_to64(MemoryStream s, ulong v, int n)
{
char[] _crypt_a64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
while (--n >= 0)
{
s.WriteByte((byte)_crypt_a64[v & 0x3f]);
v >>= 6;
}
}
}
}
Neyi yanlış yapıyorum? Ben FreeBSD sürümünde MD5xxxx fonksiyonların işleyişi hakkında bazı büyük varsayımlar yapıyorum, ama o iş gibi görünüyor.
Bu PHP tarafından kullanılan gerçek sürüm değil mi? Herkes herhangi bir fikir var mı?
EDIT:
PHP'nin kaynak kodunun bir kopyasını indirdim ve glibc kütüphanesini kullanır bulundu. Yani, ben, glibc'mizin kaynak kodunun bir kopyasını karşıdan __ md5_crypt_r işlevi bulundu, bu FreeBSD sürümü ÖZDEŞ aynı karmaları ile geri geldi işlevselliği, karınca çoğaltılamaz.
Şimdi, hemen hemen şaşkına duyuyorum. PHP 4 5 daha farklı bir yöntem kullandınız mı? Neler oluyor?