|
DaveyM69 wrote: if anyone has any suggestions on improving it?
Perhaps you have an alternate reason for using encryption but maybe one improvement would be to provide some level of security?
|
|
|
|
|
Security is the reason for the encryption. The application has to store customer data (xml format) localy. To comply with data protection laws (United Kingdom) I have to encrypt this data. The only way to access it is through my application - which requires the user to supply a valid user name and password before the data can be seen.
I'm really looking for code/performance improvements as it just seems a little clumsy as it is.
|
|
|
|
|
Use the CryptoStream library class. If you want the data to be really secure use the Users password to encrypt the data that way programmers can't even get to it.
Need a C# Consultant? I'm available.
Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
|
|
|
|
|
Thankyou! CryptoStream - I spent at least six hours trying to find something like that before ending up with the code I posted I was going to ask last night but I was determined to experiment first, but at least i learned a few things along the way.
Thanks for your help - back to coding now
|
|
|
|
|
Cryptographic libraries only provide algorithm implementations. To actually provide security you are still left to determine key management strategies based on your projects requirements.
|
|
|
|
|
I ended up with this - a slight variation on the examle given in MSDN.
class CryptoStreamEncryption
{
private static byte[] Key = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
private static byte[] IV = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
public static void Encrypt(XmlDocument ThisDocument, string FullPath)
{
try
{
FileStream fStream = File.Open(FullPath, FileMode.Create);
Rijndael RijndaelAlg = Rijndael.Create();
CryptoStream cStream = new CryptoStream(fStream, RijndaelAlg.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
StreamWriter sWriter = new StreamWriter(cStream);
try
{
sWriter.WriteLine(ThisDocument.OuterXml);
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
sWriter.Close();
cStream.Close();
fStream.Close();
}
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
}
}
public static XmlDocument Decrypt(string FullPath)
{
XmlDocument ThisDocument = new XmlDocument();
string val = null;
try
{
FileStream fStream = File.Open(FullPath, FileMode.Open);
Rijndael RijndaelAlg = Rijndael.Create();
CryptoStream cStream = new CryptoStream(fStream, RijndaelAlg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
StreamReader sReader = new StreamReader(cStream);
try
{
val = sReader.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("An error occurred: {0}", e.Message);
}
finally
{
sReader.Close();
cStream.Close();
fStream.Close();
}
}
catch (CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("A file error occurred: {0}", e.Message);
}
catch (System.IO.FileLoadException e)
{
Console.WriteLine("A file load error occurred: {0}", e.Message);
}
catch (System.IO.FileNotFoundException e)
{
Console.WriteLine("A file not found error occurred: {0}", e.Message);
}
if (!(val == null))
{
ThisDocument.LoadXml(val);
}
return ThisDocument;
}
}
|
|
|
|
|
This is close to the other method I was going to suggest, so now I don't have to type it! I will, however, reiterate that key storage is essential to security, and simply including it in the compiled dll is NOT secure. Since it looks like you are doing this, I will reiterate (original warning came from one of the MVP's) that encrypting data does not imply security. You MUST have a way to secure the key from being read by another party for the encryption above to be secure. This is part of the key management strategy, and I encourage you to research it via the web to get ideas.
-Jeff
|
|
|
|
|
Hi Jeff,
Yeah - I did take your point on board, but getting the encryption/decryption working/performing optimally was my priority at that point.
The key storage is a bit of a problem as the encrypted data is stored on a network share with many clients needing access it (the reason for the filelock question) so they all need to know the key!
I thought maybe using the assembly's GUID with a little hashing as an extra layer may be a solution but I've been strugglig to get the GUID within code.
Any suggestions?
|
|
|
|
|
OK, this is an entirely incorrect way to go about this. You should NEVER require the users to know the key to encrypt/decrypt data. This leads to software upgrade nightmares, as key management is nearly impossible. What you should do is have a SINGLE web application (or a few for redundancy)that can get and decrypt the data, then return the decrypted data to the client (or re-encrypt it on the fly with a session key, if you want it to be secure). Hard-coding keys into client apps is a bad idea, as one key leak is detrimental to the entire system. On the other hand, with a single web app, changing the key after a known leak is easy, as you have control over both the data and the web app. Just a suggestion, but if you do implement the web app method, you could make it run as a specific user, so again, you could encrypt/decrypt on a user level, which alleviates you from having to manage the crypto key, as explained in earlier posts. Hope this helps,
-Jeff
|
|
|
|
|
The users do not need to know the key - only the application instances. They may only have network access and not internet so a web app is not an option so I think I'm stuck with hard coding it in some way but hopefully well obscured within the app.
|
|
|
|
|
I don't think you need to be "online" to connect to a web service. If you use a local computer, the address gets resolved within your own network (I think, but you could test this by disconnecting from the internet and seeing if you can still access other computers on your network). Again, I will reiterate that giving multiple users knowledge of the key makes the key more accessible and therefore, less secure. Anyway, to get the GUID of the assembly you can just do the following:
using System.Reflection;
using System.Runtime.InteropServices;
...
object[] res = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true);
string guid = null;
if (res.Length > 0)
guid = ((GuidAttribute)res[0]).Value; Hope this helps,
-Jeff
|
|
|
|
|
That's helped alot Jeff,
Many thanks.
|
|
|
|
|
If you are using NTFS, do the following (adding try/catch as appropriate):
public static void Encrypt(XmlDocument ThisDocument, string targetFile) {
FileStream outFile = new FileStream(targetFile, FileMode.OpenOrCreate, FileAccess
.Write, FileShare.None, 0x1000, FileOptions.Encrypted| FileOptions.SequentialScan);
ThisDocument.Save(outFile);
outFile.Close();
}
public static XmlDocument Decrypt(string sourceFile) {
FileStream inFile = new FileStream(sourceFile, FileMode.Open, FileAccess
.Read, FileShare.None, 0x1000, FileOptions.Encrypted | FileOptions.SequentialScan);
ThisDocument.Save(outFile);
inFile.Close();
}
I am currently tired of typing, but I will explain how to do it another way in a bit, in case you are not using NTFS.
-Jeff
|
|
|
|
|
Isn't that user specific?
Need a C# Consultant? I'm available.
Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway
|
|
|
|
|
Yes, it is user specific... I suggested this because a previous post suggested that the user's password should be used as the key, which would also make it user specific.
-Jeff
|
|
|
|
|
There will be many users accessing this so this isn't viable unfortunately. Thanks for the suggestion though.
|
|
|
|
|
G'day,
A little while back I ran into a similar problem of storing data in a XML file which needs to be encrypted/decrypted as required. I found that using the Cryptography Application Block from Enterprise Library very useful. Purely because I could generate the symmetric key file specific to the user's credential's or machine config. Also you need to consider what happens to the encrypted/decrypted data memory once you have finished with it as well.
I can post some code if you are unfamiliar with the Cryptography Application Block.
To lock a file during Read/Write there is a class within .net that allows you do it. It escapes my mind right now.
cheers,
V
|
|
|
|
|
Downloaded the Enterprise Library - I'll definately look at it in detail. For now, the CryptoStream will suffice.
Thanks.
|
|
|
|
|
Hi,
I've changed my form to use a context menu for basic CRUD operations after using a menu previously.
Now, if you fill out the form (Winform C# 2.0) and right click "save", the last field on the databound form doesn't update the property value in the business object. If I tab through it then the value's updated properly.
So it seems that if the cursor is still focused in that last textbox as I invoke the save, the databinding doesn't update the property and I end up with a blank value in the database.
How can I ensure that the property gets updated if the user doesn't tab out of it?
Seems simple enough but I've gotten myself so confused that I can't think straight, so I ask for help! Thanks.
|
|
|
|
|
Took me quite some time to figure that one out, too.
The update back from control back to BO is after on leave of the control. I notice that if the user move from the control to say a tab page or button, it may not get fired.
Change the update mode to on property changed instead of on leave, ie
this.txtUserCode.DataBindings.Add("Text", UpdateObject, "UserCode", false, DataSourceUpdateMode.OnPropertyChanged, string.Empty);
The BO will get updated on every changes on the control, though.
|
|
|
|
|
Thanks for the response. Your suggestion worked great!! It had me stumped for a while.
|
|
|
|
|
My book on LINQ hasn't arrived yet, so this might be a stupid question or really basic, but anyway...
Is it possible to build a dynamic where clause?
"On one of my cards it said I had to find temperatures lower than -8. The numbers I uncovered were -6 and -7 so I thought I had won, and so did the woman in the shop. But when she scanned the card the machine said I hadn't.
"I phoned Camelot and they fobbed me off with some story that -6 is higher - not lower - than -8 but I'm not having it."
-Tina Farrell, a 23 year old thicky from Levenshulme, Manchester.
|
|
|
|
|
|
That's some mighty fine Google work. I'm annoyed, however, that it didn't come up in my googling.
"On one of my cards it said I had to find temperatures lower than -8. The numbers I uncovered were -6 and -7 so I thought I had won, and so did the woman in the shop. But when she scanned the card the machine said I hadn't.
"I phoned Camelot and they fobbed me off with some story that -6 is higher - not lower - than -8 but I'm not having it."
-Tina Farrell, a 23 year old thicky from Levenshulme, Manchester.
|
|
|
|
|
Yes, I was fiddling abit with dynamic query also.
|
|
|
|