问题
So I am creating a business management system so the project files will be saved locally on the computer but many can access the computer. In order that no one can just open the files and access all the data, I want the file to be able to open just threw my app. In order to do it, I thought that in order to open the file there will be some constant password, that I will pass the stream so this is the only way the file can open.
Is this possible?
what should I change in order to do it in the following code?
Stream SerializeStream = new FileStream(Project_Name, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite)
回答1:
Here are some ideas taken from my personal core library to save/load encrypted files or objects and streams.
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();
}
}
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 };
You may not store the raw password in any variable (members properties and/or fields) outside local vars.
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;
}
I hope I have not forgot something else ask it.
If you want to serialize and deserialize encrypted objects, you can do things like that:
Save:
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));
}
}
Load:
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;
}
}
If you want to use compression:
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;
}
}
来源:https://stackoverflow.com/questions/58050435/how-to-prevent-users-and-other-applications-from-accessing-data-saved-in-a-file