【问题标题】:C# - Looking for Encryption/Decryption MethodC# - 寻找加密/解密方法
【发布时间】:2021-03-26 09:38:33
【问题描述】:

我编写了一个使用 RtlEncryptMemory/RtlDecryptMemory 加密/解密字符串的 C# 片段。然后将该字符串保存在配置文件中,一切正常,但问题是一旦我注销/登录,我就无法再解密该字符串。我正在使用 RTL_ENCRYPT_OPTION_SAME_LOGON 选项,这意味着内部机制使用 Windows 会话中的某些内容来执行解密。我正在寻找一种以相同方式工作但与网络用户(或令牌等)相关联的解决方案。 Windows 是否已经提供了一些东西?

我的目标是能够从任何地方解密字符串,只要该进程在同一用户下运行(网络凭据)。我也不想让用户输入密码或使用内部值,因为这可能会受到损害。理想情况下,它就像 RTL 函数,但提供 RTL_ENCRYPT_OPTION_SAME_USER 选项。

谢谢! 尼克

【问题讨论】:

  • 如果你想存储字符串,你不应该使用 RtlEncryptMemory,它只是为了保证字符串在运行的应用程序内存中的安全,因此它可以被存储/序列化和解密。
  • 看看这个线程,我认为 DPAPI 会满足你的需求。 stackoverflow.com/questions/34194223/…
  • 是的,我完全理解 RtlEncryptMemory 不是要走的路。看起来凯文的建议可能是要走的路,我将不得不对此进行原型设计。感谢您的回复。
  • 我刚刚测试完 Kevin 的 DPAPI 建议,这是最符合我要求的。不幸的是,加密数据仍然与机器密钥相关联,但它比我使用 RTL 的原始实现要好。凯文,如果您不介意将您的建议作为解决方案发布,我可以将其标记为已接受。谢谢!
  • @Teknex1 - 完成!很高兴它有帮助。

标签: c# encryption


【解决方案1】:

您想使用 DataProtection API

这是一个添加加密和解密字符串扩展的简单实现...

public static class StringExtensions
{
    public static string Encrypt(this string s)
    {
        if (String.IsNullOrEmpty(s))
        {
            return s;
        }
        else
        {
            var encoding = new UTF8Encoding();
            byte[] plain = encoding.GetBytes(s);
            byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(secret);
        }
    }
    public static string Decrypt(this string s)
    {
        if (String.IsNullOrEmpty(s))
        {
            return s;
        }
        else
        {
            byte[] secret = Convert.FromBase64String(s);
            byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
            var encoding = new UTF8Encoding();
            return encoding.GetString(plain);
        }
    }
}

这是一个例子......

    class Program
{
    static void Main(string[] args)
    {
        string password = "Monkey123";
        string encrypted = password.Encrypt();
        Console.WriteLine($"Encrypted password = '{encrypted}'");
        string decrypted = encrypted.Decrypt();
        Console.WriteLine($"Decrypted password = '{decrypted}'");
    }
}

产生这个输出...

Encrypted password = 'AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA/6wDgM21DkStrNJQ35QDiwAAAAACAAAAAAAQZgAAAAEAACAAAAAPr3/aqafbt/RRoPVe75b+PFBhE6h9MLcQ2Ivsd3adOwAAAAAOgAAAAAIAACAAAABYxqEdzotL+7qXpWnbbpPRkfWZF6oh/meFsXzFtLPnrBAAAAB59VGbboP4Tye1N3dB7E3jQAAAAMQn8cAlnTDe1mwDEJriADizdT2Qr0DtPgpMje+rbjdkVpL+cKiEQs4om4i1hlLPgPn5MG5oVWFFnxU0d4c9TFg='
Decrypted password = 'Monkey123'

注意事项:

  1. 只有当前登录的用户才能解密使用此代码加密的数据。只要当前用户具有漫游配置文件,此功能就可以在整个网络中使用。
  2. 或者,范围可以是本地计算机,在这种情况下,只有登录到同一台计算机的用户才能解密数据。
  3. 这是 .NET Core 3.1 代码,仅适用于 Windows 计算机

使用语句...

using System;
using System.Security.Cryptography;
using System.Text;

【讨论】:

    【解决方案2】:

    如果你想存储字符串,你不应该使用 RtlEncryptMemory,它只是为了保证字符串在运行的应用程序内存中的安全,因此它可以被存储/序列化和解密。

    看看DPAPI password encryption我觉得应该可以满足你的需求。

    【讨论】:

      【解决方案3】:

      我有一个你可能喜欢的 Nuget 包:

      DataJuggler.Net.Cryptography .Net 框架

      DataJuggler.Core.Cryptography 点网核心

      使用起来非常简单,这里有一个现场演示:

      https://blazorcrypto.datajuggler.com/

      上面也有源代码和视频链接。

      用法:

      加密:

      // get the encryptedText
      encryptedResult = CryptographyHelper.EncryptString(textToEncrypt, keyCode);
      

      解密:

      // get thedecryptedText
      decryptedResult = CryptographyHelper.DecryptString(textToDecrypt, keyCode);
      

      它还包括密码哈希。

      如果您认为值得免费支付,请告诉我。

      【讨论】:

      • 感谢您的建议,看起来是一个很棒的包,不幸的是它使用了一个密钥代码或密码,我希望尽可能避免使用。
      【解决方案4】:

      我有一段时间没有使用 c#,但通常 c# 中的加密和解密库使用机器密钥作为哈希密钥。如果您在不同的服务器中有应用程序,请确保在所有服务器中将机器密钥设置为相同的值,或者如果您可以覆盖该方法,您可以使用不同的密钥,该密钥由密码短语生成。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-27
        • 2016-01-10
        • 2012-07-12
        • 2012-05-19
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多