代码之家  ›  专栏  ›  技术社区  ›  jiten

在内存中安全地存储数据(基于密码的加密)

  •  0
  • jiten  · 技术社区  · 5 年前

    我必须把钥匙存入存储器。因此出于安全考虑,我们不能将密钥直接存储到内存中,所以需要以加密的方式存储密钥。因此,我们的想法是以加密的方式存储密钥,在进行加密操作时,只需对密钥进行解密并使用并处理密钥。

    所以我们使用的是基于密码的加密(PBE)在BouncyCastle c#版本中定义 Example 代码。

    代码中的问题是这里的密码是固定的。我必须在运行时生成密码。

    存储密钥的步骤:

    • 生成密码
    • 保存到内存中

    执行加密操作的步骤:

    • 创建临时密钥以解密密钥(安全数据)
    • 执行加密操作
    0 回复  |  直到 5 年前
        1
  •  1
  •   Olivier Rogier    5 年前

    以下是一个方法,这样密码就永远不会在未加密的情况下存储在本地VAR之外:

    using System;
    using System.Security;
    using System.Security.Cryptography;
    using System.Text;
    
    private string _SecureKey;
    
    public bool MemorizePassword { get; set; }
    
    public string Password
    {
      get
      {
        if ( _Password.IsNullOrEmpty() ) return _Password;
        var buf = Encoding.Default.GetBytes(_Password);
        ProtectedMemory.Unprotect(buf, MemoryProtectionScope.SameProcess);
        return Encoding.Default.GetString(Decrypt(buf, _SecureKey.ToString()));
      }
      set
      {
        if ( !MemorizePassword ) 
        { 
          _Password = "";
          return;
        }
        CreateSecureKey();
        if ( value.IsNullOrEmpty() ) 
          _Password = value;
        else
        {
          var buf = Encrypt(Encoding.Default.GetBytes(value), _SecureKey.ToString());
          ProtectedMemory.Protect(buf, MemoryProtectionScope.SameProcess);
          _Password = Encoding.Default.GetString(buf);
        }
      }
    }
    
    private void CreateSecureKey()
    {
      _SecureKey = new SecureString();
      foreach ( char c in Convert.ToBase64String(CreateCryptoKey(64)) )
        _SecureKey.AppendChar(c);
      _SecureKey.MakeReadOnly();
    }
    
    static public byte[] CreateCryptoKey(int length)
    {
      if ( length < 1 ) length = 1;
      byte[] key = new byte[length];
      new RNGCryptoServiceProvider().GetBytes(key);
      return key;
    }
    
    static public byte[] Encrypt(byte[] data, string password)
    {
      return Encrypt(data, password, DefaultCryptoSalt);
    }
    
    static public byte[] Decrypt(byte[] data, string password)
    {
      return Decrypt(data, password, DefaultCryptoSalt);
    }
    
    static public string Encrypt(string str, string password, byte[] salt)
    {
      if ( str.IsNullOrEmpty() ) return str;
      PasswordDeriveBytes p = new PasswordDeriveBytes(password, salt);
      var s = Encrypt(Encoding.Default.GetBytes(str), p.GetBytes(32), p.GetBytes(16));
      return Convert.ToBase64String(s);
    }
    
    static public string Decrypt(string str, string password, byte[] salt)
    {
      if ( str.IsNullOrEmpty() ) return str;
      PasswordDeriveBytes p = new PasswordDeriveBytes(password, salt);
      var s = Decrypt(Convert.FromBase64String(str), p.GetBytes(32), p.GetBytes(16));
      return Encoding.Default.GetString(s);
    }
    
    static public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
    {
      if ( data == null ) return data;
      using ( MemoryStream m = new MemoryStream() )
      {
        var r = Rijndael.Create().CreateEncryptor(key, iv);
        using ( CryptoStream c = new CryptoStream(m, r, CryptoStreamMode.Write) )
          c.Write(data, 0, data.Length);
        return m.ToArray();
      }
    }
    
    static public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
    {
      if ( data == null ) return data;
      using ( MemoryStream m = new MemoryStream() )
      {
        var r = Rijndael.Create().CreateDecryptor(key, iv);
        using ( CryptoStream c = new CryptoStream(m, r, CryptoStreamMode.Write) )
          c.Write(data, 0, data.Length);
        return m.ToArray();
      }
    }
    

    特定于应用程序的salt示例(使用0到255之间的任意随机值):

    byte[] DefaultCryptoSalt = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };