Вот некоторые идеи, взятые из моей личной базовой библиотеки, для сохранения / загрузки зашифрованных файлов или объектов и потоков.
using System;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using ( StreamWriter writer = new StreamWriter(filename) )
{
string password = AskPassword();
writer.Write(Encrypt(Content, password));
}
using ( StreamReader reader = new StreamReader(filename) )
{
string password = AskPassword();
string content = Decrypt(reader.ReadToEnd(), password);
}
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();
}
}
Пример соли, специфичной для вашего приложения (используйте любое случайное значение от 0 до 255):
byte[] DefaultCryptoSalt = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Вы не можете хранить необработанный пароль в любой переменной (свойствах и / или полях) вне локальных переменных.
public string Password
{
get
{
lock ( locker )
{
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
{
lock ( locker )
{
if ( !MemorizePassword ) 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;
}
Надеюсь, я не забыл что-то еще спроситьit.
Если вы хотите сериализовать и десериализовать зашифрованные объекты, вы можете сделать следующее:
Сохранить:
using ( FileStream f = new FileStream(filename,
FileMode.Create, FileAccess.Write, FileShare.None,
buffersize) )
{
var cbf = new BinaryFormatter(new CoreSurrogateSelector(),
new StreamingContext(StreamingContextStates.All));
using ( MemoryStream ms = new MemoryStream() )
{
cbf.Serialize(ms, obj);
var buf = ms.GetBuffer();
if ( compress ) buf = buf.Compress();
cbf.Serialize(f, Encrypt(buf, password));
}
}
Загрузить:
using ( FileStream f = new FileStream(filename,
FileMode.Open, FileAccess.Read, FileShare.None,
buffersize) )
{
BinaryFormatter bf = new BinaryFormatter(new CoreSurrogateSelector(),
new StreamingContext(StreamingContextStates.All));
byte[] buf = (byte[])bf.Deserialize(f);
buf = Decrypt(buf, password);
if ( compress ) buf = buf.Decompress();
using ( MemoryStream ms = new MemoryStream() )
{
ms.Write(buf, 0, buf.Length);
ms.Position = 0;
T obj = (T)bf.Deserialize(ms);
return obj;
}
}
Если вы хотите использовать сжатие:
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
static public string Compress(this string text)
{
if ( text.IsNullOrEmpty() ) return text;
return Convert.ToBase64String(Encoding.Default.GetBytes(text).Compress());
}
static public byte[] Compress(this byte[] buffer)
{
using ( MemoryStream ms = new MemoryStream() )
{
using ( GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true) )
zip.Write(buffer, 0, buffer.Length);
ms.Position = 0;
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return gzBuffer;
}
}
static public string Decompress(this string text)
{
return Encoding.Default.GetString(Convert.FromBase64String(text).Decompress());
}
static public byte[] Decompress(this byte[] gzBuffer)
{
using ( MemoryStream ms = new MemoryStream() )
{
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
using ( GZipStream zip = new GZipStream(ms, CompressionMode.Decompress) )
zip.Read(buffer, 0, buffer.Length);
return buffer;
}
}