asp.net – 当passwordFormat = Encrypted和decryption = AES时,
最近我开始开发一个新的MVC应用程序,需要使用较旧的现有asp.net成员资格数据库并将其转换为新的(呃)身份系统.
如果您发现自己处于类似的情况,那么很可能您已经遇到了这个helpful post from microsoft,它为您提供了很好的指导和脚本,可以将数据库转换为新架构,包括密码. 为了处理两个系统之间密码散列/加密的差异,它们包括一个自定义密码哈希,SqlPasswordHasher,它解析密码字段(已合并到Password | PasswordFormat | Salt)并尝试复制SqlMembershipProvider中的逻辑将传入的密码与存储的版本进行比较. 然而,正如我(以及该帖子上的另一位评论者)所注意到的,他们提供的这个方便的哈希不处理加密密码(尽管他们在帖子中使用的混淆语言似乎表明它确实如此).它似乎应该是,考虑到它们确实将密码格式带入数据库,但奇怪的是代码不使用它,而是 int passwordformat = 1; 这是用于散列密码.我需要的是能够使用System.Web / MachineKey配置元素的decryptionKey处理我的场景的加密密码. 如果你也处于这样的困境,并且正在使用AES算法(如machineKey的解密属性中所定义的那样),那么下面的答案应该得到解决. 解决方法
首先,让我们快速谈谈SqlMembershipProvider在幕后做的事情.提供程序通过将两者连接在一起,将转换为byte []的salt与编码为unicode字节数组的密码组合成一个更大的字节数组.非常直截了当.然后它通过抽象(MembershipAdapter)将其传递给MachineKeySection,在那里完成实际工作.
关于该切换的重要部分是它指示MachineKeySection使用空IV(初始化向量)并且还不执行签名.那个空的IV是真正的关键,因为machineKey元素没有IV属性,所以如果你已经摸不着头脑,想知道提供者如何处理这个方面,那就是这样.一旦你知道(从挖掘源代码)然后你可以提取MachineKeySection代码中的加密代码,并将其与成员资格提供程序的代码结合起来,以获得更完整的哈希.完整来源: public class SQLPasswordHasher : PasswordHasher { public override string HashPassword(string password) { return base.HashPassword(password); } public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword,string providedPassword) { string[] passwordProperties = hashedPassword.Split('|'); if (passwordProperties.Length != 3) { return base.VerifyHashedPassword(hashedPassword,providedPassword); } else { string passwordHash = passwordProperties[0]; int passwordformat = int.Parse(passwordProperties[1]); string salt = passwordProperties[2]; if (String.Equals(EncryptPassword(providedPassword,passwordformat,salt),passwordHash,StringComparison.CurrentCultureIgnoreCase)) { return PasswordVerificationResult.SuccessRehashNeeded; } else { return PasswordVerificationResult.Failed; } } } //This is copied from the existing SQL providers and is provided only for back-compat. private string EncryptPassword(string pass,int passwordFormat,string salt) { if (passwordFormat == 0) // MembershipPasswordFormat.Clear return pass; byte[] bIn = Encoding.Unicode.GetBytes(pass); byte[] bSalt = Convert.FromBase64String(salt); byte[] bRet = null; if (passwordFormat == 1) { // MembershipPasswordFormat.Hashed HashAlgorithm hm = HashAlgorithm.Create("SHA1"); if (hm is KeyedHashAlgorithm) { KeyedHashAlgorithm kha = (KeyedHashAlgorithm)hm; if (kha.Key.Length == bSalt.Length) { kha.Key = bSalt; } else if (kha.Key.Length < bSalt.Length) { byte[] bKey = new byte[kha.Key.Length]; Buffer.BlockCopy(bSalt,bKey,bKey.Length); kha.Key = bKey; } else { byte[] bKey = new byte[kha.Key.Length]; for (int iter = 0; iter < bKey.Length;) { int len = Math.Min(bSalt.Length,bKey.Length - iter); Buffer.BlockCopy(bSalt,iter,len); iter += len; } kha.Key = bKey; } bRet = kha.ComputeHash(bIn); } else { byte[] bAll = new byte[bSalt.Length + bIn.Length]; Buffer.BlockCopy(bSalt,bAll,bSalt.Length); Buffer.BlockCopy(bIn,bSalt.Length,bIn.Length); bRet = hm.ComputeHash(bAll); } } else //MembershipPasswordFormat.Encrypted,aka 2 { byte[] bEncrypt = new byte[bSalt.Length + bIn.Length]; Buffer.BlockCopy(bSalt,bEncrypt,bSalt.Length); Buffer.BlockCopy(bIn,bIn.Length); // Distilled from MachineKeyConfigSection EncryptOrDecryptData function,assuming AES algo and paswordCompatMode=Framework20 (the default) MemoryStream stream = new MemoryStream(); var aes = new AesCryptoServiceProvider(); aes.Key = HexStringToByteArray(MachineKey.DecryptionKey); aes.GenerateIV(); aes.IV = new byte[aes.IV.Length]; ICryptoTransform transform = aes.CreateEncryptor(); CryptoStream stream2 = new CryptoStream(stream,transform,CryptoStreamMode.Write); stream2.Write(bEncrypt,bEncrypt.Length); stream2.FlushFinalBlock(); bRet = stream.ToArray(); stream2.Close(); // } return Convert.ToBase64String(bRet); } public static byte[] HexStringToByteArray(String hex) { int NumberChars = hex.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i,2),16); return bytes; } private static MachineKeySection MachineKey { get { //Get encryption and decryption key information from the configuration. System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); return cfg.GetSection("system.web/machineKey") as MachineKeySection; } } } 如果您有不同的算法,那么步骤将非常接近相同,但您可能希望首先深入了解MachineKeySection的源代码,并仔细了解它们如何初始化事物.快乐的编码! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – SQL Server预登录握手确认错误
- asp.net-mvc – Mac上是否有一个好的编辑器支持ASP.NET MVC
- asp.net – 如何为我的网站关闭IIS中的自定义错误处理?
- asp.net – 在javascript中读取cookie
- ASP.NET上的.cshtml razor文件转换
- asp.net – 将HyperLinkField设置为Javascript Url
- asp.net-mvc-4 – Visual Studio 2013 C#Web项目构建但IDE报
- asp.net – 如何将textchanged事件添加到代码隐藏中的文本框
- 当调用ASP.NET System.Web.HttpResponse.End()时,当前线程中
- ASP.Net是适用于高负载网站的技术吗?
- asp.net – 可接受的安全性:使用Paramatised SQ
- asp.net-mvc-3 – 模拟控制器动作单元测试的默认
- asp.net-core – 访问Raw Request Body
- asp.net – ASP核心:如何设置httpContext.User?
- iCalendar格式中关于RRule的解析和生成
- asp.net-mvc – ASP.NET MVC – 为基本控制器中的
- asp.net web api定义的b/s调用方法一例
- 我可以首先使用EF代码和.net核心生成迁移脚本
- asp.net-mvc – 在视图中找不到webgrid引用
- asp.net-mvc – HttpCache vs Singleton – MVC应