目前我用明文哎呀写它!,这是一个内部计划所以它并没有那么糟糕,但我想做得对.在写入注册表时我应该如何加密这个以及如何解密呢?
OurKey.SetValue("Password", textBoxPassword.Text);
Oli.. 125
您不解密身份验证密码!
使用类似SHA256提供程序的东西对它们进行哈希处理,当你必须挑战时,哈希来自用户的输入并查看两个哈希值是否匹配.
byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString); data = new System.Security.Cryptography.SHA256Managed().ComputeHash(data); String hash = System.Text.Encoding.ASCII.GetString(data);
让密码可逆是一个非常可怕的模型.
Edit2:我以为我们刚才谈的是前线认证.当然,有些情况下你想要为其他需要可逆的东西加密密码,但是应该有一个单向锁定(除了极少数例外).
我已经升级了散列算法,但为了获得最佳强度,您需要保留私有盐并在散列之前将其添加到输入中.比较时你会再次这样做.这增加了另一层,使得某人更难以扭转.
使用类似SHA256提供程序的东西对它们进行哈希处理,当你必须挑战时,哈希来自用户的输入并查看两个哈希值是否匹配.
byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString); data = new System.Security.Cryptography.SHA256Managed().ComputeHash(data); String hash = System.Text.Encoding.ASCII.GetString(data);
让密码可逆是一个非常可怕的模型.
Edit2:我以为我们刚才谈的是前线认证.当然,有些情况下你想要为其他需要可逆的东西加密密码,但是应该有一个单向锁定(除了极少数例外).
我已经升级了散列算法,但为了获得最佳强度,您需要保留私有盐并在散列之前将其添加到输入中.比较时你会再次这样做.这增加了另一层,使得某人更难以扭转.
还请考虑"腌制"你的哈希(不是烹饪概念!).基本上,这意味着在散列之前将一些随机文本附加到密码.
" 如果您的凭证存储受到损害,盐值有助于减缓攻击者执行字典攻击的速度,从而为您提供额外的时间来检测并做出妥协. "
存储密码哈希值:
a)生成随机盐值:
byte[] salt = new byte[32]; System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);
b)将salt附加到密码.
// Convert the plain string pwd into bytes byte[] plainTextBytes = System.Text UnicodeEncoding.Unicode.GetBytes(plainText); // Append salt to pwd before hashing byte[] combinedBytes = new byte[plainTextBytes.Length + salt.Length]; System.Buffer.BlockCopy(plainTextBytes, 0, combinedBytes, 0, plainTextBytes.Length); System.Buffer.BlockCopy(salt, 0, combinedBytes, plainTextBytes.Length, salt.Length);
c)哈希组合密码和盐:
// Create hash for the pwd+salt System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed(); byte[] hash = hashAlgo.ComputeHash(combinedBytes);
d)将salt附加到生成的哈希值.
// Append the salt to the hash byte[] hashPlusSalt = new byte[hash.Length + salt.Length]; System.Buffer.BlockCopy(hash, 0, hashPlusSalt, 0, hash.Length); System.Buffer.BlockCopy(salt, 0, hashPlusSalt, hash.Length, salt.Length);
e)将结果存储在用户存储数据库中.
这种方法意味着您不需要单独存储salt,然后使用salt值和从用户获得的纯文本密码值重新计算哈希值.
编辑:随着原始计算能力变得更便宜和更快,哈希 - 或盐渍哈希 - 的价值已经下降.杰夫阿特伍德有一个非常好的2012年更新太长,不能在这里重复,其中指出:
这(使用盐渍哈希)将提供比任何实际安全更多的安全幻觉.既然你需要salt和hash算法的选择来生成散列,并检查散列,那么攻击者不太可能拥有一个而不是另一个.如果您已被攻击者攻击者拥有您的密码数据库,那么可以合理地假设他们拥有或者可以获得您的秘密隐藏的盐.
安全的第一条规则是始终承担并计划最坏的情况.您是否应该使用盐,理想情况下每个用户使用盐?当然,这绝对是一个很好的做法,至少它可以让你消除两个拥有相同密码的用户的歧义.但是现在,只有盐才能让你不再愿意花费几千美元购买视频卡硬件,如果你认为它们可以,你就会陷入困境.
汤姆斯科特在他的关于如何(不)存储密码的报道中,在Computerphile上做得对.
https://www.youtube.com/watch?v=8ZtInClXe1Q
如果您可以完全避免它,请不要尝试自己存储密码.使用单独的,预先建立的,值得信赖的用户身份验证平台(例如:OAuth提供商,您公司的Active Directory域等).
如果您必须存储密码,请不要遵循此处的任何指导.至少,并非没有咨询适用于您选择的语言的更新近的和有信誉的出版物.
这里肯定有很多聪明人,甚至可能给出一些很好的指导.但是,当你读到这篇文章时,这里的所有答案(包括这个答案)都已经过时了.
所有这一切,这里有一些一般指导,希望有一段时间可以保持有用.
不要加密密码.任何允许恢复存储数据的存储方法本身就不安全以保存密码 - 包括所有形式的加密.
在创建过程中完全按照用户输入的密码处理密码.在将密码发送到加密模块之前对密码所做的任何操作都可能会削弱密码.执行以下任何操作也会增加密码存储和验证过程的复杂性,这可能会导致其他问题(甚至可能引入漏洞).
不要转换为全大写/全小写.
不要删除空格.
不要删除不可接受的字符或字符串.
不要更改文本编码.
不要做任何字符或字符串替换.
不要截断任何长度的密码.
拒绝创建任何无需修改即无法存储的密码.加强以上.如果出于某种原因,您的密码存储机制无法正确处理某些字符,空格,字符串或密码长度,则会返回错误并让用户了解系统的限制,以便他们可以使用适合其中的密码重试.为了获得更好的用户体验,请预先列出用户可以访问的那些限制.甚至不用担心,更别提工作了,将列表从攻击者那里隐藏起来 - 无论如何,他们都会轻易地自己解决这个问题.
为每个帐户使用长,随机且唯一的盐.即使密码实际上相同,也不会有两个帐户的密码在存储中看起来相同.
使用专为密码设计的慢速和加密强哈希算法.MD5肯定是出局的.SHA-1/SHA-2是禁止的.但我不会告诉你你应该在这里使用什么.(参见本文中的第一个#2子弹.)
尽可能多地迭代.虽然您的系统可能与处理器周期有更好的关系,而不是整天的哈希密码,但是破解密码的人却没有系统.尽可能地让它们变得坚硬,而不是让它"太难".
最重要的是...
去查找有关您所选语言的正确密码存储方法的信誉良好且最新的出版物.实际上,在解决一种方法之前,您应该从多个单独的来源中找到多个最近的出版物.
这里的每个人(包括我自己)所说的一切都极有可能已经被更好的技术所取代,或者被新开发的攻击方法变得不安全.去找一些更可能没有的东西.
这是你想要做的:
OurKey.SetValue("Password", StringEncryptor.EncryptString(textBoxPassword.Text)); OurKey.GetValue("Password", StringEncryptor.DecryptString(textBoxPassword.Text));
您可以使用以下类来完成此操作.这个类是泛型类,是客户端端点.它使用Ninject实现各种加密算法的IOC.
public class StringEncryptor { private static IKernel _kernel; static StringEncryptor() { _kernel = new StandardKernel(new EncryptionModule()); } public static string EncryptString(string plainText) { return _kernel.Get().EncryptString(plainText); } public static string DecryptString(string encryptedText) { return _kernel.Get ().DecryptString(encryptedText); } }
下一个类是ninject类,它允许您注入各种算法:
public class EncryptionModule : StandardModule { public override void Load() { Bind().To (); } }
这是任何算法需要实现的用于加密/解密字符串的接口:
public interface IStringEncryptor { string EncryptString(string plainText); string DecryptString(string encryptedText); }
这是使用TripleDES算法的实现:
public class TripleDESStringEncryptor : IStringEncryptor { private byte[] _key; private byte[] _iv; private TripleDESCryptoServiceProvider _provider; public TripleDESStringEncryptor() { _key = System.Text.ASCIIEncoding.ASCII.GetBytes("GSYAHAGCBDUUADIADKOPAAAW"); _iv = System.Text.ASCIIEncoding.ASCII.GetBytes("USAZBGAW"); _provider = new TripleDESCryptoServiceProvider(); } #region IStringEncryptor Members public string EncryptString(string plainText) { return Transform(plainText, _provider.CreateEncryptor(_key, _iv)); } public string DecryptString(string encryptedText) { return Transform(encryptedText, _provider.CreateDecryptor(_key, _iv)); } #endregion private string Transform(string text, ICryptoTransform transform) { if (text == null) { return null; } using (MemoryStream stream = new MemoryStream()) { using (CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { byte[] input = Encoding.Default.GetBytes(text); cryptoStream.Write(input, 0, input.Length); cryptoStream.FlushFinalBlock(); return Encoding.Default.GetString(stream.ToArray()); } } } }
您可以在以下网址观看我的视频并下载代码:http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html
一种选择是存储密码的散列(SHA1,MD5)而不是明文密码,并且只要您想查看密码是否良好,只需将其与该散列进行比较即可.
如果您需要安全存储(例如,用于连接服务的密码),则问题会更加复杂.
如果只是用于身份验证,那么使用哈希就足够了.
如果您希望能够解密密码,我认为最简单的方法是使用DPAPI(用户存储模式)来加密/解密.这样您就不必使用加密密钥,将它们存储在某处或在代码中对它们进行硬编码 - 在这两种情况下,有人可以通过查看注册表,用户设置或使用Reflector来发现它们.
否则使用哈希SHA1或MD5就像其他人所说的那样.
就像ligget78所说,DPAPI是存储密码的好方法.查看MSDN上的ProtectedData类以获取示例用法.
我到处寻找加密和解密过程的一个很好的例子,但是大多数都过于复杂。
无论如何,有人可能有许多原因想要解密某些文本值(包括密码)。我需要在当前正在使用的网站上解密密码的原因是,他们希望确保在过期时何时有人被迫更改密码,我们不允许他们使用相同密码的紧密变体来更改密码他们在过去x个月中使用过。
因此,我编写了一个简化的过程。我希望这段代码对某人有益。就我所知,我可能最终会在另一个时间将其用于其他公司/站点。
public string GenerateAPassKey(string passphrase) { // Pass Phrase can be any string string passPhrase = passphrase; // Salt Value can be any string(for simplicity use the same value as used for the pass phrase) string saltValue = passphrase; // Hash Algorithm can be "SHA1 or MD5" string hashAlgorithm = "SHA1"; // Password Iterations can be any number int passwordIterations = 2; // Key Size can be 128,192 or 256 int keySize = 256; // Convert Salt passphrase string to a Byte Array byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); // Using System.Security.Cryptography.PasswordDeriveBytes to create the Key PasswordDeriveBytes pdb = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations); //When creating a Key Byte array from the base64 string the Key must have 32 dimensions. byte[] Key = pdb.GetBytes(keySize / 11); String KeyString = Convert.ToBase64String(Key); return KeyString; } //Save the keystring some place like your database and use it to decrypt and encrypt //any text string or text file etc. Make sure you dont lose it though. private static string Encrypt(string plainStr, string KeyString) { RijndaelManaged aesEncryption = new RijndaelManaged(); aesEncryption.KeySize = 256; aesEncryption.BlockSize = 128; aesEncryption.Mode = CipherMode.ECB; aesEncryption.Padding = PaddingMode.ISO10126; byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString); aesEncryption.Key = KeyInBytes; byte[] plainText = ASCIIEncoding.UTF8.GetBytes(plainStr); ICryptoTransform crypto = aesEncryption.CreateEncryptor(); byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length); return Convert.ToBase64String(cipherText); } private static string Decrypt(string encryptedText, string KeyString) { RijndaelManaged aesEncryption = new RijndaelManaged(); aesEncryption.KeySize = 256; aesEncryption.BlockSize = 128; aesEncryption.Mode = CipherMode.ECB; aesEncryption.Padding = PaddingMode.ISO10126; byte[] KeyInBytes = Encoding.UTF8.GetBytes(KeyString); aesEncryption.Key = KeyInBytes; ICryptoTransform decrypto = aesEncryption.CreateDecryptor(); byte[] encryptedBytes = Convert.FromBase64CharArray(encryptedText.ToCharArray(), 0, encryptedText.Length); return ASCIIEncoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length)); } String KeyString = GenerateAPassKey("PassKey"); String EncryptedPassword = Encrypt("25Characterlengthpassword!", KeyString); String DecryptedPassword = Decrypt(EncryptedPassword, KeyString);
如果它是您的应用程序用于身份验证的密码,则按其他人的建议散列密码.
如果您要存储外部资源的密码,您通常希望能够提示用户提供这些凭据,并让他有机会安全地保存这些凭据.Windows为此提供了凭据UI(CredUI) - 有许多示例显示如何在.NET中使用它,包括MSDN上的这个.