C# 当我将密码保存到注册表时,加密密码的最简单方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/212510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:20:20  来源:igfitidea点击:

What is the easiest way to encrypt a password when I save it to the registry?

c#encryptionpasswords

提问by

Currently I'm writing it in clear text oops!, it's an in house program so it's not that bad but I'd like to do it right. How should I go about encrypting this when writing to the registry and how do I decrypt it?

目前我正在用明文写它,哎呀!,这是一个内部程序,所以还不错,但我想做得对。在写入注册表时我应该如何加密它以及如何解密它?

OurKey.SetValue("Password", textBoxPassword.Text);

回答by Bogdan Maxim

One option would be to store the hash (SHA1, MD5) of the password instead of the clear-text password, and whenever you want to see if the password is good, just compare it to that hash.

一种选择是存储密码的散列(SHA1、MD5)而不是明文密码,并且每当您想查看密码是否正确时,只需将其与该散列进行比较。

If you need secure storage (for example for a password that you will use to connect to a service), then the problem is more complicated.

如果您需要安全存储(例如用于连接到服务的密码),那么问题就更复杂了。

If it is just for authentication, then it would be enough to use the hash.

如果只是用于身份验证,那么使用哈希就足够了。

回答by Oli

You don't decrypt authentication passwords!

您不会解密身份验证密码!

Hash them using something like the SHA256 provider and when you have to challenge, hash the input from the user and see if the two hashes match.

使用诸如 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);

Leaving passwords reversible is a reallyhorrible model.

让密码可逆是一个非常可怕的模型。

Edit2: I thought we were just talking about front-line authentication. Sure there are cases where you want to encrypt passwords for other things that need to be reversible but there should be a 1-way lock on top of it all (with a very few exceptions).

Edit2:我以为我们只是在谈论前线身份验证。当然,在某些情况下,您想为其他需要可逆的事物加密密码,但在这一切之上应该有一个单向锁(极少数例外)。

I've upgraded the hashing algorithm but for the best possible strength you want to keep a private salt and add that to your input beforehashing it. You would do this again when you compare. This adds another layer making it even harder for somebody to reverse.

我已经升级了散列算法,但为了获得最佳强度,您希望保留一个私有盐并散列之前将其添加到您的输入中。当你比较时,你会再次这样做。这增加了另一层,使某人更难逆转。

回答by Jeremy B.

Rather than encrypt/decrypt, you should be passing the password through a hashing algorithm, md5/sha512, or similar. What you would ideally do is hash the password and store the hash, then when the password is needed, you hash the entry and compare the entries. A password will then never be "decrypted", simply hashed and then compared.

您应该通过散列算法、md5/sha512 或类似算法传递密码,而不是加密/解密。理想情况下,您会做的是散列密码并存储散列,然后当需要密码时,您散列条目并比较条目。密码永远不会被“解密”,只是散列然后比较。

回答by liggett78

If you want to be able to decrypt the password, I think the easiest way would be to use DPAPI (user store mode) to encrypt/decrypt. This way you don't have to fiddle with encryption keys, store them somewhere or hard-code them in your code - in both cases somebody can discover them by looking into registry, user settings or using Reflector.

如果您希望能够解密密码,我认为最简单的方法是使用 DPAPI(用户存储模式)进行加密/解密。这样您就不必摆弄加密密钥、将它们存储在某处或将它们硬编码在您的代码中——在这两种情况下,有人可以通过查看注册表、用户设置或使用 Reflector 来发现它们。

Otherwise use hashes SHA1 or MD5 like others have said here.

否则像其他人在这里所说的那样使用哈希 SHA1 或 MD5。

回答by osp70

..NET provides cryptographics services in class contained in the System.Security.Cryptography namespace.

..NET 在 System.Security.Cryptography 命名空间中包含的类中提供加密服务。

回答by Bogdan Maxim

If you need more than this, for example securing a connection string (for connection to a database), check this article, as it provides the best "option" for this.

如果您需要的不止这些,例如保护连接字符串(用于连接到数据库),请查看这篇文章,因为它为此提供了最佳“选项”。

Oli's answer is also good, as it shows how you can create a hash for a string.

Oli 的回答也很好,因为它展示了如何为字符串创建哈希。

回答by DOK

Please also consider "salting" your hash (not a culinary concept!). Basically, that means appending some random text to the password before you hash it.

还请考虑“腌制”您的哈希(不是烹饪概念!)。基本上,这意味着在对密码进行哈希处理之前将一些随机文本附加到密码中。

"The salt value helps to slow an attacker perform a dictionary attack should your credential store be compromised, giving you additional time to detect and react to the compromise."

如果您的凭据存储遭到破坏,salt 值有助于减缓攻击者执行字典攻击的速度,从而让您有更多时间来检测和应对破坏。

To store password hashes:

存储密码哈希:

a) Generate a random salt value:

a) 生成一个随机盐值:

byte[] salt = new byte[32];
System.Security.Cryptography.RNGCryptoServiceProvider.Create().GetBytes(salt);

b) Append the salt to the password.

b) 将盐附加到密码中。

// 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) Hash the combined password & salt:

c) 散列组合的密码和盐:

// Create hash for the pwd+salt
System.Security.Cryptography.HashAlgorithm hashAlgo = new System.Security.Cryptography.SHA256Managed();
byte[] hash = hashAlgo.ComputeHash(combinedBytes);

d) Append the salt to the resultant hash.

d) 将盐附加到结果散列中。

// 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) Store the result in your user store database.

e) 将结果存储在您的用户存储数据库中。

This approach means you don't need to store the salt separately and then recompute the hash using the salt value and the plaintext password value obtained from the user.

这种方法意味着您不需要单独存储盐,然后使用盐值和从用户获得的明文密码值重新计算哈希。

Edit: As raw computing power becomes cheaper and faster, the value of hashing -- or salting hashes -- has declined. Jeff Atwood has an excellent 2012 updatetoo lengthy to repeat in its entirety here which states:

编辑:随着原始计算能力变得越来越便宜,速度越来越快,散列(或加盐散列)的价值已经下降。杰夫·阿特伍德 (Jeff Atwood) 有一个出色的 2012 年更新,太长了,无法在此处完整重复,其中指出:

This (using salted hashes) will provide the illusion of security more than any actual security. Since you need both the salt and the choice of hash algorithm to generate the hash, and to check the hash, it's unlikely an attacker would have one but not the other. If you've been compromised to the point that an attacker has your password database, it's reasonable to assume they either have or can get your secret, hidden salt.

The first rule of security is to always assume and plan for the worst. Should you use a salt, ideally a random salt for each user? Sure, it's definitely a good practice, and at the very least it lets you disambiguate two users who have the same password. But these days, salts alone can no longer save you from a person willing to spend a few thousand dollars on video card hardware, and if you think they can, you're in trouble.

这(使用加盐哈希)将提供比任何实际安全性都更安全的假象。由于您需要盐和散列算法的选择来生成散列并检查散列,因此攻击者不太可能拥有一个而不是另一个。如果您已经受到攻击,以至于攻击者拥有您的密码数据库,那么可以合理地假设他们拥有或可以获取您的秘密、隐藏的盐。

安全的第一条规则是始终假设和计划最坏的情况。您是否应该使用盐,最好为每个用户使用随机盐?当然,这绝对是一个很好的做法,至少它可以让您消除两个具有相同密码的用户的歧义。但是现在,单靠盐已经无法让您免于愿意在显卡硬件上花费数千美元的人,如果您认为他们可以,那么您就有麻烦了。

回答by Joe

If it's a password used for authentication by your application, then hash the password as others suggest.

如果它是您的应用程序用于身份验证的密码,则按照其他人的建议对密码进行哈希处理。

If you're storing passwords for an external resource, you'll often want to be able to prompt the user for these credentials and give him the opportunity to save them securely. Windows provides the Credentials UI (CredUI) for this purpose - there are a number of samples showing how to use this in .NET, including this one on MSDN.

如果您要为外部资源存储密码,您通常希望能够提示用户输入这些凭据并让他有机会安全地保存它们。Windows 为此目的提供了凭据 UI (CredUI) - 有许多示例展示了如何在 .NET 中使用它,包括MSDN 上的这个示例。

回答by Jamie Wright

This is what you would like to do:

这是你想要做的:

OurKey.SetValue("Password", StringEncryptor.EncryptString(textBoxPassword.Text));
OurKey.GetValue("Password", StringEncryptor.DecryptString(textBoxPassword.Text));

You can do that with this the following classes. This class is a generic class is the client endpoint. It enables IOC of various encryption algorithms using Ninject.

您可以使用以下类来做到这一点。这个类是一个泛型类,是客户端端点。它使用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<IStringEncryptor>().EncryptString(plainText);
    }

    public static string DecryptString(string encryptedText)
    {
        return _kernel.Get<IStringEncryptor>().DecryptString(encryptedText);
    }
}

This next class is the ninject class that allows you to inject the various algorithms:

下一个类是 ninject 类,它允许您注入各种算法:

public class EncryptionModule : StandardModule
{
    public override void Load()
    {
        Bind<IStringEncryptor>().To<TripleDESStringEncryptor>();
    }
}

This is the interface that any algorithm needs to implement to encrypt/decrypt strings:

这是任何算法都需要实现以加密/解密字符串的接口:

public interface IStringEncryptor
{
    string EncryptString(string plainText);
    string DecryptString(string encryptedText);
}

This is a implementation using the TripleDES algorithm:

这是使用 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());
            }
        }
    }
}

You can watch my video and download the code for this at : http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html

您可以在以下位置观看我的视频并下载代码:http: //www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html

回答by Beau

Like ligget78 said, DPAPI would be a good way to go for storing passwords. Check out the ProtectedData class on MSDNfor example usage.

就像 ligget78 所说,DPAPI 将是存储密码的好方法。查看 MSDN 上的 ProtectedData 类以获取示例用法。