当前位置: 首页 > 编程语言 > C#

将PHPcrypt()函数移植到C#问题分享

时间:2023-04-10 21:15:05 C#

将PHPcrypt()函数移植到C#问题能够使用他们的旧密码。但是,为了让它工作,我需要能够根据新输入的密码将旧哈希与新计算的哈希进行比较。我四处搜索,发现这是由PHP调用的crypt()的实际发现:char*crypt_md5(constchar*pw,constchar*salt){MD5_CTXctx,ctx1;无符号长l;诠释sl,pl;u_inti;u_charfinal[MD5_SIZE];静态常量char*sp,*ep;静态字符密码[120],*p;staticconstchar*magic="$1$";/*先优化盐*/sp=salt;/*如果它以魔法字符串开头,则跳过它*/if(!strncmp(sp,magic,strlen(magic)))sp+=strlen(magic);/*它在第一个'$'处停止,最多8个字符*/for(ep=sp;*ep&&*ep!='$'&&ep0;pl-=MD5_SIZE)MD5Update(&ctx,(constu_char*)最后,(u_int)(pl>MD5_SIZE?MD5_SIZE:pl));/*不要在他们可以使用的vm中留下任何东西。*/memset(final,0,sizeof(final));/*然后有些东西真的很奇怪...*/for(i=strlen(pw);i;i>>=1)if(i&1)MD5Update(&ctx,(constu_char*)final,1);否则MD5Update(&ctx,(constu_char*)pw,1);/*现在输出字符串*/strcpy(passwd,magic);strncat(密码d,sp,(u_int)sl);strcat(密码,“$”);MD5Final(最终,&ctx);/**现在,只是为了确保事情不会运行得太快*在60MhzPentium上这需要34毫秒,所以你*需要30秒来构建一个包含1000个条目的字典...*/for(i=0;我<1000;我++){MD5Init(&ctx1);if(i&1)MD5Update(&ctx1,(constu_char*)pw,strlen(pw));否则MD5Update(&ctx1,(constu_char*)final,MD5_SIZE);如果(i%3)MD5Update(&ctx1,(constu_char*)sp,(u_int)sl);if(i%7)MD5Update(&ctx1,(constu_char*)pw,strlen(pw));if(i&1)MD5Update(&ctx1,(constu_char*)final,MD5_SIZE);否则MD5Update(&ctx1,(constu_char*)pw,strlen(pw));MD5Final(final,&ctx1);}p=passwd+strlen(密码);l=(最终[0]<<16)|(最终[6]<<8)|最终[12];_crypt_to64(p,l,4);p+=4;l=(最终[1]<<16)|(最终[7]<<8)|最终[13];_crypt_to64(p,l,4);p+=4;l=(最终[2]<<16)|(最终[8]<<8)|最终[14];_crypt_to64(p,l,4);p+=4;l=(最终[3]<<16)|(最终[9]<<8)|最终[15];_crypt_to64(p,l,4);p+=4;l=(最终[4]<<16)|(最终[10]<<8)|最后[5];_crypt_to64(p,l,4);p+=4;l=最终[11];_crypt_to64(p,l,2);p+=2;*p='';/*不要在他们可以使用的vm中留下任何东西。*/memset(final,0,sizeof(final));返回(密码);并且,这是我在C#中的版本,以及预期的匹配使用系统;使用System.Collections.Generic;使用System.Linq;使用系统文本;使用系统诊断;使用System.Security.Cryptography;使用System.IO;使用系统管理;namespaceTest{classProgram{staticvoidMain(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(密码,盐);Console.WriteLine("Hash2:"+Encoding.ASCII.GetString(newhash));byte[]newhash2=md5_crypt(密码,newhash);Console.WriteLine("Hash3:"+Encoding.ASCII.GetString(newhash2));控制台.ReadKey(true);}publicstaticbyte[]md5_crypt(byte[]pw,byte[]salt){MemoryStreamctx,ctx1;乌龙l;诠释sl,pl;诠释我;字节[]最终;诠释sp,ep;//**更改指向数组索引的指针MemoryStreampasswd=newMemoryStream();byte[]magic=Encoding.ASCII.GetBytes("$1$");//先提炼盐sp=0;//**改为数组索引,而不是指针。//如果它以魔法字符串开头,则跳过if(salt[0]==magic[0]&&salt[1]==magic[1]&&salt[2]==magic[2]){sp+=魔术。长度;}//它在第一个'$'处停止,最多8个字符for(ep=sp;(ep+sp=1)if((i&1)!=0)MD5Update(ctx,final,1);否则MD5Update(ctx,pw,1);//现在输出字符串passwd.Write(magic,0,magic.Length);passwd.Write(盐,sp,sl);passwd.WriteByte((byte)'$');final=MD5Final(ctx);//现在,只是为了确保事情不会运行得太快//在60MhzPentium这需要34毫秒,所以您//需要30秒来构建一个1000条目的字典...for(i=0;i<1000;i++){ctx1=MD5Init();if((i&1)!=0)MD5Update(ctx1,pw,pw.Length);否则MD5Update(ctx1,final,final.Length);如果((i%3)!=0)MD5Update(ctx1,salt,sp,sl);如果((i%7)!=0)MD5Update(ctx1,pw,pw.Length);if((i&1)!=0)MD5Update(ctx1,final,final.Length);否则MD5Update(ctx1,pw,pw.Length);final=MD5Final(ctx1);}//**部分更改为使用内存流,而不是字节数组。l=(((ulong)final[0])<<16)|(((ulong)最终[6])<<8)|((ulong)最终[12]);_crypt_to64(密码,l,4);l=(((ulong)final[1])<<16)|(((ulong)最终[7])<<8)|((ulong)最终[13]);_crypt_to64(密码,l,4);l=(((ulong)final[2])<<16)|(((ulong)最终[8])<<8)|((ulong)最终[14]);_crypt_to64(密码,l,4);l=(((ulong)final[3])<<16)|(((ulong)最终[9])<<8)|((ulong)最终[15]);_crypt_to64(密码,l,4);l=(((ulong)final[4])<<16)|(((ulong)final[10])<=0){s.WriteByte((byte)_crypt_a64[v&0x3f]);v>>=6;}}}}我究竟做错了什么?我对MD5xxxx函数在FreeBSD版本中的工作做了一些大的假设,但它似乎工作这不是PHP使用的实际版本吗?有没有人有任何见识?编辑:我下载了一份PHP源代码,发现它使用了glibc库。所以,我下载了一份glibc的源代码,找到了__md5_crypt_r函数,复制了它的功能,它带有与FreeBSD版本完全相同的散列。现在,我很难过。PHP4使用与PHP5不同的方法吗?到底是怎么回事?好的,这就是答案:PHP使用crypt函数的glibc实现。(附:C#实现)我的旧密码与哈希不匹配的原因是因为我的旧网站(托管在GoDaddy上)所在的Linux机器有一个非标准的哈希算法。(可能修复算法中完成的一些奇怪的事情。)但是,我已经针对glibc的单元测试和PHP的Windows安装测试了以下实现。两项测试都通过了100%。编辑这是链接:(移至GithubGist)https://gist.github.com/1092558PHP中的crypt()函数使用底层操作系统为加密数据提供的任何哈希算法-请参阅其文档。所以第一步应该是找出数据是如何加密的(使用什么哈希算法)。一旦您了解了这一点,就很容易为C#找到相同的算法。您始终可以将system()(或任何调用C#静态函数的内容)输出到为您执行crypt的php命令行脚本。成功登录后,我建议强制更改密码。然后您可以有一个标志,指示用户是否已更改。一旦每个人都改变了,你就可以转储php调用。只需重用php实现...确保php的crypt库在您的系统环境路径中...您可能需要更新互操作方法以确保字符串编组/字符集正确...然后您可以使用原始哈希算法。[DllImport("crypt.dll",CharSet=CharSet.ASCII)]privatestaticexternstringcrypt(stringpassword,stringsalt);publicboolValidLogin(stringusername,stringpassword){stringhash=crypt(password,null);...}看起来并不简单。更新:最初我写道:“PHPCrypt函数看起来不像标准哈希。为什么不呢?谁知道呢。”正如评论中所指出的,PHPcrypt()与BSD中用于passwdcrypt的相同。我不知道这是不是法定标准,但这是事实上的标准。所以。我坚持我的立场,这似乎并不微不足道。您可以考虑保持旧的PHP运行,并严格使用它来验证旧密码的密码,而不是移植代码。当用户更改密码时,使用更“开放”的新哈希算法。您必须为每个用户存储散列和“散列样式”。以上就是C#学习教程:PHPcrypt()函数移植到C#的全部内容。代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: