问题
I have to store the key into memory. So as security concern we can not store the cryptographic key into the memory directly, We need to store the key in Encrypted way. So the idea is we store the key in encrypted manner and at the time of crypto operation, just decrypt the key and use it and dispose the key.
So we are using Password based encryption(PBE) define in BouncyCastle c# version Example code.
The problem in code is that the password is fix here. I have to generate the password at run time.
Steps to Store the Key:
- Generate password
- Create temporary key to encrypt the key(secure data)
- Save into memory
Steps to perform Crypto operation:
- Generate password
- Create temporary key to decrypt the key(secure data)
- perform crypto operation
- Dispose the key(secure data)
回答1:
Here is an idea so the password can be never stored unencrypted outside local vars:
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();
}
}
Example of salt specific to your app (use any random value between 0 and 255):
byte[] DefaultCryptoSalt = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
来源:https://stackoverflow.com/questions/58092320/store-data-securely-in-memory-password-based-encryption