加密和解密ASP.NET

时间:2015-04-06 20:13:56

标签: c# asp.net encryption

我一直在谷歌搜索只是为了一个简单的加密和解密方法来存储密码。我不是在寻找一种非常复杂的加密技术,所以我想这就是让它很难找到的原因。

有没有人可以与我分享任何简单的加密和解密方法?

4 个答案:

答案 0 :(得分:3)

例如,您应该使用SHA256哈希密码。要检查密码有效性,请对从用户收到的密码进行哈希处理,并将其与存储在数据库中的哈希值进行比较。

也就是说,您应该确保通过SSL发送密码或者可以捕获密码。如果您自己的操作系统不安全,则密码可能会在到达时以明文形式捕获。

当您的网站位于Intranet上时,最好使用Windows集成身份验证。对于互联网,OAuth可能被证明是更好的选择。

感谢@philsoady指出https://security.stackexchange.com/questions/35250/hmacsha512-versus-rfc2898derivebytes-for-password-hash进一步阅读。

答案 1 :(得分:1)

为什么你应该使用散列而不是加密:

如果使用加密,则需要密钥。可以使用此密钥并将其用于解密密码。最有可能的是,组织内的人员可以访问此密钥。这意味着每个人都有可能知道您的用户密码。

Hashing的做法有何不同?

哈希设计为单向线性变换。因此,您无法倒退并获得实际密码。可以通过以下方式演示一个简单的哈希算法:使用将密码除以6的其余部分。假设您的密码为10.您将在数据库中存储4,因为10/6的余数为4。如果您在数据库中看到4,你不能倒退并弄清楚你有10,因为它也可能是4或16(或无限多的其他)。但是,通过传入10,您可以验证这与存储在数据库中的4相同。您可能会注意到这里存在的固有缺陷。如果您使用16作为密码,它仍将在数据库中匹配。这被称为碰撞。

建议您使用大于SHA128(128位输出)的散列算法,因为在您发现碰撞之前搜索是不可行的。 SHA算法是为速度而设计的,所以这些对你来说仍然足够快(你说它很轻)。另外,有些人会生成一组已知的流行密码及其哈希值(通常称为rainbow tables),用于快速交叉引用存储的值。

为了更加安全,请为每个用户创建一个唯一值(通常称为salt),在散列之前应将其附加到密码的开头或结尾。例如,salt值为salt,密码为password,因此我们将哈希saltpassword并存储结果。然后,当用户再次登录时,我们会将生成的哈希与存储的值进行比较。这个更好的原因是在两个用户拥有相同密码的情况下,它们将具有两个不同的唯一哈希值。

一个小代码示例:

using System.Security.Cryptography;

private string HashPassword(string password,  string salt) 
{
    string hashedString = CryptoConfig.CreateFromName("SHA256")
                                      .ComputeHash(salt+password);
    return hashedString;
}

基本上,使用加密意味着可以发现密码。使用散列意味着你无法找到它们是什么,只是找到一个潜在的碰撞(除非你真的很幸运)。

答案 2 :(得分:1)

正如oscar132在评论中解释的那样,你不应该尝试重塑会员资格。

ASP.NET有一个非常好的成员资格提供程序作为默认选项,不需要那么多配置。它拥有良好密码管理所需的一切:用户管理,密码重置,集成Web控制,......

它也不会使用非常不安全的加密方法,而是使用已推荐的SHA256方法对密码进行哈希处理,并选择使用自定义提供程序来增强加密算法,如PBKDF2或bcrypt。

即使您的项目已在进行中,添加对它的支持并不难。 Visual Studio默认支持将asp.net网站升级为实现成员资格的asp.net Web表单应用程序。

答案 3 :(得分:1)

真的不是一个问题,但是其他人会发现这个问题。 有些人会做和做。这里可能缺少本土种植的网站。

  • 不要存储密码,存储单向哈希。如果可能,请对它们进行编码。
  • 不要使用HMacSHA *作为算法,使用BCRPT,SCRYPT或RFC2898DerivedBytes(PBKDF2)作为密码。 SHA速度太快,不适合密码散列。
  • 使用SALT
  • 首选标准经过良好测试和接受的工具,例如在您的环境中ASP.Net Identity
  • 请求用户密码时始终使用SSL
  • 如果您必须(您确定)加密和解密具有计算机密钥/解密密钥策略。加密只能与密钥的安全性一样好。

如果认真的应用程序考虑使用SCyrpt for c# 标准c#中的最低来编码密码应该是这样的 以下使用Rfc2898。

a)将编码密码和随机SALT存储在您的数据库中  b)使用至少250毫秒的成本  c)将用户提供的密码与存储的SALT比较到相同的例程并比较哈希值。

private string PasswordEncode(string password, byte[] salt ) {
      var deriver2898 = new Rfc2898DeriveBytes(password, salt,64000); // approx 300msecs
      byte[] hash = deriver2898.GetBytes(20); // 
      //    return hash;
      // If you dont like storing bytes, use a string
      return Convert.ToBase64String(hash);
}


// himalayan pink rock salt... the best kind
    public byte[] GenerateSalt(int size = 64) {
        using (var crypto = new RNGCryptoServiceProvider()) {
            var bytes = new byte[size];
            crypto.GetBytes(bytes); //get a bucket of very random bytes
            return bytes;
        }
    }

如果您在此阶段仍然确信您需要加密,那么请使用Microsoft的一种对称算法。 EG AesManaged

  /// <summary>
    /// Encrypt using preferred provider. 
    /// </summary>
    /// <typeparam name="T">AesManaged,TripleDESCryptoServiceProvider,RijndaelManaged</typeparam>
    /// <param name="value">Value to be encrypted</param>
    /// <param name="decryptionKey">secret key .. see machine key descryptionKey</param>
    /// <param name="salt">salt for process</param>
    /// <returns></returns>
    public string Encrypt<T>(string value, string salt, string decryptionKey)
        where T : SymmetricAlgorithm, new() {
        var derivedKey = GenerateKey(decryptionKey, salt);
        SymmetricAlgorithm algorithm = new T();
        byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
        byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);

        ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIv);
        using (var buffer = new MemoryStream()) {
            using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) {
                using (var writer = new StreamWriter(stream, Encoding.Unicode)) {
                    writer.Write(value);
                }
            }
            // before finished with the buffer return, now as the stream is now closed
            return Convert.ToBase64String(buffer.ToArray());
        }
    }

public string Decrypt<T>(string text, string salt, string decryptionKey)
        where T : SymmetricAlgorithm, new() {
        // could catch errors here, and return a null string. ? 
        // "CryptographicException: Padding is invalid and cannot be removed"
        // can occur if there is a coding problem , such as invalid key or salt passed to this routine.

        var derivedKey = GenerateKey(decryptionKey, salt);
        SymmetricAlgorithm algorithm = new T();
        byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
        byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);

        ICryptoTransform transform = algorithm.CreateDecryptor(rgbKey, rgbIv);
        using (var buffer = new MemoryStream(Convert.FromBase64String(text))) {
            using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Read)) {
                using (var reader = new StreamReader(stream, Encoding.Unicode)) {
                    return reader.ReadToEnd(); // error here implies wrong keys supplied , and code or environment problem.. NASTY issue
                }
            }
        }
    }


  public DeriveBytes GenerateKey(string salt, string decryptionKey) {
        // generate the key from the shared secret and the salt
        var saltAsByteArray = salt.UTF8StringToByteArray();
        var key = new Rfc2898DeriveBytes(decryptionKey, saltAsByteArray);
        return key;
    }

示例调用:加密和解密。另外,请考虑how to get machine key and use as key here

Encrypt<AesManaged>(password, salt, decryptionKey);
Decrypt<AesManaged>(encryptedPassword, salt, decryptionKey);