File (XmlDocument) Encryption / Decryption improvements
-
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
-
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
-
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 HemingwayI 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 (CryptographicExcep
-
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 (CryptographicExcep
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
-
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?
-
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
-
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
-
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