Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. File (XmlDocument) Encryption / Decryption improvements

File (XmlDocument) Encryption / Decryption improvements

Scheduled Pinned Locked Moved C#
questionalgorithmsdata-structuressecurityxml
19 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D DaveyM69

    Hi, After many hours of searching, I've managed to get this working using the code below - but I'm wondering if anyone has any suggestions on improving it? I'm sure this is not as efficient as it could be! Also - how do I go about locking the target file during the read and write?

    #region Encryption
    class RijndaelEncrypt
    {
    public static void Encrypt(XmlDocument ThisDocument, string FullPath)
    {
    //Save XML to memory stream
    MemoryStream ms = new MemoryStream();
    ThisDocument.Save(ms);
    //Convert memory stream to byte array
    byte[] xmlArray = ms.ToArray();
    //Encrypt
    RijndaelManaged Rij = new RijndaelManaged();
    Rij.Key = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey); //MyKey is 16 character string
    Rij.IV = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
    ICryptoTransform rijEncrypt = Rij.CreateEncryptor();
    byte[] encryptedData = rijEncrypt.TransformFinalBlock(xmlArray, 0, xmlArray.Length);
    //Create file stream and write encrypted data
    FileStream fsout = new FileStream(FullPath, FileMode.Create);
    fsout.Write(encryptedData, 0, encryptedData.Length);
    fsout.Close();
    }

        public static XmlDocument Decrypt(string FullPath)
        {
            //Create file stream and get file length
            FileStream fsin = new FileStream(FullPath, FileMode.Open, FileAccess.Read);
            FileInfo finfo = new FileInfo(FullPath);
            //Create binary reader and read from file stream
            BinaryReader br = new BinaryReader(fsin);
            //Decrypt
            byte\[\] encryptedData = br.ReadBytes((int)finfo.Length);
            RijndaelManaged Rij = new RijndaelManaged();
            Rij.Key = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
            Rij.IV = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
            ICryptoTransform rijDecrypt = Rij.CreateDecryptor();
            byte\[\] decryptedData = rijDecrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
            //Create XML document, fill with decrypted data and return the document
            XmlDocument ThisDocument = new XmlDocument();
            ThisDocument.LoadXml(Encoding.UTF8.GetString(decryptedData));
            return ThisDocument;
        }
    }
    #endregion
    
    S Offline
    S Offline
    Skippums
    wrote on last edited by
    #5

    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

    E 1 Reply Last reply
    0
    • S Skippums

      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

      E Offline
      E Offline
      Ennis Ray Lynch Jr
      wrote on last edited by
      #6

      Isn't that user specific?

      Need a C# Consultant? I'm available.
      Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway

      S 1 Reply Last reply
      0
      • E Ennis Ray Lynch Jr

        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

        D Offline
        D Offline
        DaveyM69
        wrote on last edited by
        #7

        Thankyou! CryptoStream - I spent at least six hours trying to find something like that before ending up with the code I posted :laugh: 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 :-D

        L 1 Reply Last reply
        0
        • D DaveyM69

          Hi, After many hours of searching, I've managed to get this working using the code below - but I'm wondering if anyone has any suggestions on improving it? I'm sure this is not as efficient as it could be! Also - how do I go about locking the target file during the read and write?

          #region Encryption
          class RijndaelEncrypt
          {
          public static void Encrypt(XmlDocument ThisDocument, string FullPath)
          {
          //Save XML to memory stream
          MemoryStream ms = new MemoryStream();
          ThisDocument.Save(ms);
          //Convert memory stream to byte array
          byte[] xmlArray = ms.ToArray();
          //Encrypt
          RijndaelManaged Rij = new RijndaelManaged();
          Rij.Key = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey); //MyKey is 16 character string
          Rij.IV = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
          ICryptoTransform rijEncrypt = Rij.CreateEncryptor();
          byte[] encryptedData = rijEncrypt.TransformFinalBlock(xmlArray, 0, xmlArray.Length);
          //Create file stream and write encrypted data
          FileStream fsout = new FileStream(FullPath, FileMode.Create);
          fsout.Write(encryptedData, 0, encryptedData.Length);
          fsout.Close();
          }

              public static XmlDocument Decrypt(string FullPath)
              {
                  //Create file stream and get file length
                  FileStream fsin = new FileStream(FullPath, FileMode.Open, FileAccess.Read);
                  FileInfo finfo = new FileInfo(FullPath);
                  //Create binary reader and read from file stream
                  BinaryReader br = new BinaryReader(fsin);
                  //Decrypt
                  byte\[\] encryptedData = br.ReadBytes((int)finfo.Length);
                  RijndaelManaged Rij = new RijndaelManaged();
                  Rij.Key = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
                  Rij.IV = ASCIIEncoding.ASCII.GetBytes(Constants.Misc.MyKey);
                  ICryptoTransform rijDecrypt = Rij.CreateDecryptor();
                  byte\[\] decryptedData = rijDecrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
                  //Create XML document, fill with decrypted data and return the document
                  XmlDocument ThisDocument = new XmlDocument();
                  ThisDocument.LoadXml(Encoding.UTF8.GetString(decryptedData));
                  return ThisDocument;
              }
          }
          #endregion
          
          E Offline
          E Offline
          ekynox
          wrote on last edited by
          #8

          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

          D 1 Reply Last reply
          0
          • D DaveyM69

            Thankyou! CryptoStream - I spent at least six hours trying to find something like that before ending up with the code I posted :laugh: 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 :-D

            L Offline
            L Offline
            led mike
            wrote on last edited by
            #9

            Cryptographic libraries only provide algorithm implementations. To actually provide security you are still left to determine key management strategies based on your projects requirements.

            1 Reply Last reply
            0
            • E Ennis Ray Lynch Jr

              Isn't that user specific?

              Need a C# Consultant? I'm available.
              Happiness in intelligent people is the rarest thing I know. -- Ernest Hemingway

              S Offline
              S Offline
              Skippums
              wrote on last edited by
              #10

              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

              D 1 Reply Last reply
              0
              • S Skippums

                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

                D Offline
                D Offline
                DaveyM69
                wrote on last edited by
                #11

                There will be many users accessing this so this isn't viable unfortunately. Thanks for the suggestion though.

                1 Reply Last reply
                0
                • E ekynox

                  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

                  D Offline
                  D Offline
                  DaveyM69
                  wrote on last edited by
                  #12

                  Downloaded the Enterprise Library - I'll definately look at it in detail. For now, the CryptoStream will suffice. Thanks.

                  1 Reply Last reply
                  0
                  • E Ennis Ray Lynch Jr

                    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

                    D Offline
                    D Offline
                    DaveyM69
                    wrote on last edited by
                    #13

                    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
                    
                    S 1 Reply Last reply
                    0
                    • D DaveyM69

                      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
                      
                      S Offline
                      S Offline
                      Skippums
                      wrote on last edited by
                      #14

                      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

                      D 1 Reply Last reply
                      0
                      • S Skippums

                        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

                        D Offline
                        D Offline
                        DaveyM69
                        wrote on last edited by
                        #15

                        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?

                        S 1 Reply Last reply
                        0
                        • D DaveyM69

                          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?

                          S Offline
                          S Offline
                          Skippums
                          wrote on last edited by
                          #16

                          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

                          D 1 Reply Last reply
                          0
                          • S Skippums

                            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

                            D Offline
                            D Offline
                            DaveyM69
                            wrote on last edited by
                            #17

                            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.

                            S 1 Reply Last reply
                            0
                            • D DaveyM69

                              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.

                              S Offline
                              S Offline
                              Skippums
                              wrote on last edited by
                              #18

                              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

                              D 1 Reply Last reply
                              0
                              • S Skippums

                                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

                                D Offline
                                D Offline
                                DaveyM69
                                wrote on last edited by
                                #19

                                That's helped alot Jeff, Many thanks.

                                1 Reply Last reply
                                0
                                Reply
                                • Reply as topic
                                Log in to reply
                                • Oldest to Newest
                                • Newest to Oldest
                                • Most Votes


                                • Login

                                • Don't have an account? Register

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • World
                                • Users
                                • Groups