如何在我的应用程序中加密用户设置(如密码)?

Ody*_*dys 21 c# .net-3.5 winforms

我想为用户提供保存加密的个人数据的能力.这可能是微不足道的,或者可能已经被问过,但我无法找到一个易于使用的方法来加密/解密密码的示例.

我真的不需要任何超级魔法 - 牢不可破的密码.我只需要密码就像难以破解一样.

我已经看到一些msdn和SO问题,但还没有找到可以使用的东西.

Jes*_*cer 33

大卫,我认为你的答案很漂亮,但我认为那些作为扩展方法会更加狡猾.这将允许这样的语法:

string cypherText;
string clearText;

using (var secureString = "Some string to encrypt".ToSecureString())
{
    cypherText = secureString.EncryptString();
}

using (var secureString = cypherText.DecryptString())
{
    clearText = secureString.ToInsecureString();
}
Run Code Online (Sandbox Code Playgroud)

这是更新的代码:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;

public static class SecureIt
{
    private static readonly byte[] entropy = Encoding.Unicode.GetBytes("Salt Is Not A Password");

    public static string EncryptString(this SecureString input)
    {
        if (input == null)
        {
            return null;
        }

        var encryptedData = ProtectedData.Protect(
            Encoding.Unicode.GetBytes(input.ToInsecureString()),
            entropy,
            DataProtectionScope.CurrentUser);

        return Convert.ToBase64String(encryptedData);
    }

    public static SecureString DecryptString(this string encryptedData)
    {
        if (encryptedData == null)
        {
            return null;
        }

        try
        {
            var decryptedData = ProtectedData.Unprotect(
                Convert.FromBase64String(encryptedData),
                entropy,
                DataProtectionScope.CurrentUser);

            return Encoding.Unicode.GetString(decryptedData).ToSecureString();
        }
        catch
        {
            return new SecureString();
        }
    }

    public static SecureString ToSecureString(this IEnumerable<char> input)
    {
        if (input == null)
        {
            return null;
        }

        var secure = new SecureString();

        foreach (var c in input)
        {
            secure.AppendChar(c);
        }

        secure.MakeReadOnly();
        return secure;
    }

    public static string ToInsecureString(this SecureString input)
    {
        if (input == null)
        {
            return null;
        }

        var ptr = Marshal.SecureStringToBSTR(input);

        try
        {
            return Marshal.PtrToStringBSTR(ptr);
        }
        finally
        {
            Marshal.ZeroFreeBSTR(ptr);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*rke 17

以下是一样简单,假设您真的只想加密/解密字符串并将其存储到磁盘.请注意,这不使用密码,它使用登录用户System.Security.Cryptography.DataProtectionScope.CurrentUser的安全上下文来保护数据.

public class SecureIt
{
    static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Salt Is Not A Password");

    public static string EncryptString(System.Security.SecureString input)
    {
        byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
            System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)),
            entropy,
            System.Security.Cryptography.DataProtectionScope.CurrentUser);
        return Convert.ToBase64String(encryptedData);
    }

    public static SecureString DecryptString(string encryptedData)
    {
        try
        {
            byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
                Convert.FromBase64String(encryptedData),
                entropy,
                System.Security.Cryptography.DataProtectionScope.CurrentUser);
            return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
        }
        catch
        {
            return new SecureString();
        }
    }

    public static SecureString ToSecureString(string input)
    {
        SecureString secure = new SecureString();
        foreach (char c in input)
        {
            secure.AppendChar(c);
        }
        secure.MakeReadOnly();
        return secure;
    }

    public static string ToInsecureString(SecureString input)
    {
        string returnValue = string.Empty;
        IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
        try
        {
            returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
        }
        finally
        {
            System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
        }
        return returnValue;
    }

}
Run Code Online (Sandbox Code Playgroud)

然后加密字符串:

  var clearText = "Some string to encrypt";
  var cypherText = SecureIt.EncryptString( SecureIt.ToSecureString( clearText));
Run Code Online (Sandbox Code Playgroud)

并随后解密:

var clearText = SecureIt.ToInsecureString( SecureIt.DecryptString(cypherText));
Run Code Online (Sandbox Code Playgroud)

  • 如果您解密安全字符串,则无需使用安全字符串.完整的目的是将完整的字符串保留在单个内存块之外.你不是最好不要使用这种方法比你是,如果你只是把一个字符串和加密的吧:'一个SecureString的对象不应该从String构造,因为敏感数据已经受不可变的内存持久的后果字符串类.构造SecureString对象的最佳方法是来自一次一个字符的非托管源,例如Console.ReadKey方法. (3认同)