Exemple #1
0
 /// <summary>
 /// What to do when the selection changes in the QR Code site list:
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void cmboExportSiteQR_SelectedIndexChanged(object sender, EventArgs e)
 {
     // Asbestos underpants:
     try
     {
         // Get the current selection of the combo box and make sure it
         // isn't empty:
         String site = (string)cmboExportSiteQR.Text;
         if (!String.IsNullOrEmpty(site))
         {
             // Ask the main form to give us the site parameters for this site.
             // Since the main form has all the code to do this, we'll ask it
             // to do the dirty work.
             SiteParameters siteParams = caller.GetSiteParamsForQRCode(site);
             // Now we'll generate the text we'll embed into the QR Code.  We want
             // this to be as compact as we can get it, so our "headings" will be
             // single letters.  We'll start off with an identifying header so the
             // QR Code reader will know the format of our string.  We delimite the
             // string with pipes, which aren't allowed in any of our fields.  We
             // want this to match as closely to the values of the XML export file
             // for consistency.  That means the hash engine and the character
             // limit fields will need some tweaking.
             StringBuilder sb = new StringBuilder();
             sb.Append("CRYPTNOSv1|" +
                       "S:" + siteParams.Site + "|" +
                       "H:" + HashEngine.HashEnumStringToDisplayHash(siteParams.Hash) + "|" +
                       "I:" + siteParams.Iterations.ToString() + "|" +
                       "C:" + siteParams.CharTypes.ToString() + "|L:");
             if (siteParams.CharLimit < 0)
             {
                 sb.Append("0");
             }
             else
             {
                 sb.Append(siteParams.CharLimit.ToString());
             }
             // Now that we've built our string, use the QRCodeWriter from ZXing to
             // build the QR Code image and assign the bitmap to the picture box:
             byteMatrix = qrCodeWriter.encode(sb.ToString(),
                                              BarcodeFormat.QR_CODE, 200, 200);
             pictureBox1.Image = byteMatrix.ToBitmap();
         }
         // If the selection in the combo box wasn't useful, empty the picture box:
         else
         {
             pictureBox1.Image = null;
         }
     }
     // Similarly, if anything blew up, empty the picture box:
     catch { pictureBox1.Image = null; }
 }
 /// <summary>
 /// Read a <see cref="List"/> of <see cref="SiteParameters"/> from the new XML-based
 /// cross-platform export file format
 /// </summary>
 /// <param name="filename">A string containing the full path to the import file</param>
 /// <param name="password">A string containing the password used to decrypt the
 /// file</param>
 /// <returns>A <see cref="List"/> of <see cref="SiteParameters"/></returns>
 /// <exception cref="ImportHandlerException">Thrown if a parsing error occurs during
 /// the import process</exception>
 /// <exception cref="Exception">Thrown if anything else blows up along the way</exception>
 private static List <SiteParameters> ImportFromXMLv1File(string filename,
                                                          string password)
 {
     try
     {
         // Declare somewhere to hold the site count as read from the file:
         int siteCount = 0;
         // Try to open a file stream for the file:
         FileStream fs = new FileStream(filename, FileMode.Open);
         // The process below will blow up if we try to read a file that is so large
         // it exceeds the 32-bit integer max value.  This should never happen with an
         // actual Cryptnos export file, but if the user accidentally tries to import
         // a DVD ISO or something, we don't want to blow up their machine.  Bomb out
         // if we find out that the file is too large.
         if (fs.Length > (long)Int32.MaxValue)
         {
             fs.Close();
             throw new ImportHandlerException("Import file too large to load into memory");
         }
         // Read the entire contents of the file into memory:
         byte[] contents = new byte[(int)fs.Length];
         fs.Read(contents, 0, contents.Length);
         fs.Close();
         // Create our cipher in decryption mode:
         BufferedBlockCipher cipher = CreateCipher(password, false);
         // Create our plaintext container:
         byte[] plaintext = new byte[cipher.GetOutputSize(contents.Length)];
         // Decrypt the data and create a memory stream so we can read from it:
         plaintext = cipher.DoFinal(contents);
         MemoryStream ms = new MemoryStream(plaintext);
         contents = null;
         // Define our XML reader settings:
         XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
         // Note that we'll point to our local copy of the XSD, which should be in the
         // application directory:
         xmlReaderSettings.Schemas.Add("http://www.cryptnos.com/",
                                       Application.StartupPath + Char.ToString(System.IO.Path.DirectorySeparatorChar) +
                                       "cryptnos_export1.xsd");
         // Validate against the schema.  Invalid files will throw exceptions:
         xmlReaderSettings.ValidationType          = ValidationType.Schema;
         xmlReaderSettings.ValidationEventHandler +=
             new ValidationEventHandler(xmlReaderSettings_ValidationEventHandler);
         // Ignore unnecessary information:
         xmlReaderSettings.IgnoreComments   = true;
         xmlReaderSettings.IgnoreWhitespace = true;
         // Close any other file/input streams when we close this one:
         xmlReaderSettings.CloseInput = true;
         // Create the XML reader.  Note that we're reading from the memory stream
         // created from the decrypted file, then passing that through a gzip
         // decompressor before actually getting to the data.
         XmlReader xr = XmlReader.Create(new GZipStream(ms,
                                                        CompressionMode.Decompress), xmlReaderSettings);
         // This forces us to go to the first element, which should be <cryptnos>.  If
         // not, complain:
         xr.MoveToContent();
         if (xr.Name != "cryptnos")
         {
             throw new ImportHandlerException("Invalid Cryptnos export file; expected <cryptnos> tag but got <" + xr.Name + ">");
         }
         // At this point, things are looking good.  We'll hopefully have sites we can
         // import now.  Go ahead and create our List of SiteParameters so we can start
         // building it:
         List <SiteParameters> siteList = new List <SiteParameters>();
         // Read the next element.  This should be a <version> tag.  If it is, make sure
         // it's a version we recognize.  Otherwise, complain.
         xr.Read();
         if (xr.NodeType != XmlNodeType.Element)
         {
             throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
         }
         if (xr.Name.CompareTo("version") == 0)
         {
             xr.Read();
             // Make sure this is a text value, then make sure it's the version
             // number we expect.  This version of Cryptnos only accepts version
             // 1 of the Cryptnos export file format.
             if (xr.NodeType == XmlNodeType.Text && xr.Value != "1")
             {
                 throw new ImportHandlerException("This Cryptnos export file appears to have been generated by a later version of Cryptnos and is incompatible with this version. (File format version was " + xr.Value + ".)");
             }
         }
         else
         {
             throw new ImportHandlerException("Invalid Cryptnos export file; expected a <version> element, but got <" + xr.Name + ">");
         }
         // Read on to the next tag:
         xr.Read();
         while (xr.NodeType == XmlNodeType.EndElement)
         {
             xr.Read();
         }
         if (xr.NodeType != XmlNodeType.Element)
         {
             throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
         }
         // At this point, the next few tags should be the <generator> and/or <comment>
         // tags, neither of which we care about.  Therefore, just read ahead until we
         // hit the <sites> tag, which is where we really want to go to next.
         while (xr.Name.CompareTo("siteCount") != 0)
         {
             do
             {
                 xr.Read();
             } while (xr.NodeType != XmlNodeType.Element);
         }
         // The next tag should be the <siteCount> tag.  This contains the number of
         // site blocks in the file.  This technically isn't necessary, but it was added
         // to improve reporting on Android, where performance is much more of an issue.
         // The main thing we'll worry about here is that (a) it's an integer greater
         // than zero and (b) the number of sites we eventually read must equal the
         // count listed here.
         if (xr.NodeType == XmlNodeType.Element && xr.Name.CompareTo("siteCount") == 0)
         {
             xr.Read();
             if (xr.NodeType == XmlNodeType.Text)
             {
                 siteCount = Int32.Parse(xr.Value);
             }
             if (siteCount <= 0)
             {
                 throw new ImportHandlerException("Invalid Cryptnos export file; <siteCount> is " + siteCount.ToString());
             }
         }
         // Read on to the next tag:
         xr.Read();
         while (xr.NodeType == XmlNodeType.EndElement)
         {
             xr.Read();
         }
         // Now we need to check to make sure we actually got a <sites> tag:
         if (xr.NodeType == XmlNodeType.Element && xr.Name.CompareTo("sites") == 0)
         {
             // Read the next tag.  This should be a <site> tag and the beginning of a
             // site defintion.
             xr.Read();
             while (xr.NodeType == XmlNodeType.Element && xr.Name.CompareTo("site") == 0)
             {
                 // Create a new SiteParameters object to store the data we're about
                 // to read.
                 SiteParameters site = new SiteParameters();
                 // Try to read the <siteToken> tag:
                 xr.Read();
                 if (xr.NodeType != XmlNodeType.Element)
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
                 }
                 if (xr.Name.CompareTo("siteToken") == 0)
                 {
                     xr.Read();
                     if (xr.NodeType == XmlNodeType.Text)
                     {
                         site.Site = xr.Value;
                     }
                     else
                     {
                         throw new ImportHandlerException("Invalid site token (" + xr.Value + ")");
                     }
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected a <siteToken> element, but got <" + xr.Name + ">");
                 }
                 do
                 {
                     xr.Read();
                 } while (xr.NodeType != XmlNodeType.Element);
                 // Try to read the <hash> tag:
                 if (xr.NodeType != XmlNodeType.Element)
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
                 }
                 if (xr.Name.CompareTo("hash") == 0)
                 {
                     xr.Read();
                     if (xr.NodeType == XmlNodeType.Text)
                     {
                         site.Hash = HashEngine.DisplayHashToHashEnumString(xr.Value);
                     }
                     else
                     {
                         throw new ImportHandlerException("Invalid hash token (" + xr.Value + ")");
                     }
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected a <hash> element, but got <" + xr.Name + ">");
                 }
                 do
                 {
                     xr.Read();
                 } while (xr.NodeType != XmlNodeType.Element);
                 // Try to read the <iterations> tag:
                 if (xr.NodeType != XmlNodeType.Element)
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
                 }
                 if (xr.Name.CompareTo("iterations") == 0)
                 {
                     xr.Read();
                     if (xr.NodeType == XmlNodeType.Text)
                     {
                         site.Iterations = Int32.Parse(xr.Value);
                     }
                     else
                     {
                         throw new ImportHandlerException("Invalid iterations token (" + xr.Value + ")");
                     }
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an <iterations> element, but got <" + xr.Name + ">");
                 }
                 do
                 {
                     xr.Read();
                 } while (xr.NodeType != XmlNodeType.Element);
                 // Try to read the <charTypes> tag:
                 if (xr.NodeType != XmlNodeType.Element)
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
                 }
                 if (xr.Name.CompareTo("charTypes") == 0)
                 {
                     xr.Read();
                     if (xr.NodeType == XmlNodeType.Text)
                     {
                         site.CharTypes = Int32.Parse(xr.Value);
                     }
                     else
                     {
                         throw new ImportHandlerException("Invalid charTypes token (" + xr.Value + ")");
                     }
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected a <charTypes> element, but got <" + xr.Name + ">");
                 }
                 do
                 {
                     xr.Read();
                 } while (xr.NodeType != XmlNodeType.Element);
                 // Try to read the <charLimit> tag:
                 if (xr.NodeType != XmlNodeType.Element)
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected an element, but got " + xr.NodeType.ToString());
                 }
                 if (xr.Name.CompareTo("charLimit") == 0)
                 {
                     xr.Read();
                     if (xr.NodeType == XmlNodeType.Text)
                     {
                         // The character limit, unfortunately, is a bit inconsistent.
                         // Obviously, we can't limit it to zero, as that will mean we
                         // have an empty password.  But the XML schema defines this as
                         // only positive integers, so our built-in -1 value can't work.
                         // So if we read a zero, convert it to -1 here.  We'll do the
                         // reverse when we write the file.
                         site.CharLimit = Int32.Parse(xr.Value);
                         if (site.CharLimit == 0)
                         {
                             site.CharLimit = -1;
                         }
                     }
                     else
                     {
                         throw new ImportHandlerException("Invalid charLimit token (" + xr.Value + ")");
                     }
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected a <charLimit> element, but got <" + xr.Name + ">");
                 }
                 // The next item should be the closing element for <charLimit>, so
                 // read it in and then read the next one.  That should either be the
                 // start element for the next <site> or the closing element for
                 // <sites>.
                 xr.Read();
                 if (xr.NodeType == XmlNodeType.EndElement)
                 {
                     xr.Read();
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected ending <charLimit> tag, got " + xr.NodeType.ToString());
                 }
                 if (xr.NodeType == XmlNodeType.EndElement)
                 {
                     xr.Read();
                 }
                 else
                 {
                     throw new ImportHandlerException("Invalid Cryptnos export file; expected ending <site> tag, got " + xr.NodeType.ToString());
                 }
                 // We should now have a hopefully valid SiteParameters object.  Add it
                 // to the site list:
                 siteList.Add(site);
             }
             // We get here, we've exhausted the <sites> block and all that should be
             // left will be closing tags.  If we were going to be extremely thorough,
             // we should probably check these closing tags and make sure they're legit.
             // For now, we'll just assume there's nothing left to read.  Close the
             // streams, free up memory, and return the list of read sites.
             xr.Close();
             ms.Close();
             ms.Dispose();
             plaintext = null;
             if (siteList.Count != siteCount)
             {
                 throw new ImportHandlerException("Invalid Cryptnos export file; File reported " + siteCount.ToString() + " sites in the file, but actually read " + siteList.Count.ToString());
             }
             return(siteList);
         }
         else
         {
             throw new ImportHandlerException("Invalid Cryptnos export file; could not find <sites> tag");
         }
     }
     catch (Exception ex) { throw ex; }
 }
        /// <summary>
        /// Export a list of <see cref="SiteParameters"/> to an encrypted export file.  Note
        /// that this method only exports to the newer XML-based cross-platform format, not
        /// the old platform specific format that is no longer supported.
        /// </summary>
        /// <param name="filename">A string containing the full path to the export file</param>
        /// <param name="password">A string containing the password used to encrypt the
        /// file</param>
        /// <param name="generator">A string containing the "generator" ID for the file, usually
        /// the full application name ("Cryptnos for Windows") and version number.  If this
        /// value is null the generator tag will be omitted from the file.</param>
        /// <param name="comment">A string containing an optional comment.    If this value is
        /// null the comment tag will be omitted from the file.</param>
        /// <param name="siteList">A <see cref="List"/> of <see cref="SiteParameters"/> to
        /// export</param>
        /// <exception cref="ArgumentException">Thrown if any required field (file name,
        /// password, or site list) is empty or null</exception>
        /// <exception cref="Exception">Thrown if anything blows up along the way</exception>
        public static void ExportToFile(string filename, string password, string generator,
                                        string comment, List <SiteParameters> siteList)
        {
            try
            {
                // A little bit of sanity checking.  Make sure our required inputs are
                // not null or empty:
                if (String.IsNullOrEmpty(filename))
                {
                    throw new ArgumentException("File name is empty or null");
                }
                if (String.IsNullOrEmpty(password))
                {
                    throw new ArgumentException("Password is empty or null");
                }
                if (siteList == null || siteList.Count == 0)
                {
                    throw new ArgumentException("Site parameter list is empty or null");
                }

                // Set up the XML formatting options for our XML writer.  I don't think these
                // guys are actually essential, given that our XML is not meant to be human
                // readable, but they seemed to work for Mandelbrot Madness! so I'll keep them
                // here.
                XmlWriterSettings xws = new XmlWriterSettings();
                xws.Indent      = true;
                xws.IndentChars = "\t";
                xws.CloseOutput = true;
                xws.Encoding    = Encoding.UTF8;
                // We won't be writing directly to a file, at least not yet.  Create a memory
                // stream for us to write to initially, then open up the XML writer to point
                // to that stream.  Note that we'll also gzip the XML as it goes into the
                // memory stream to compress it.
                MemoryStream ms = new MemoryStream();
                XmlWriter    xw = XmlWriter.Create(new GZipStream(ms,
                                                                  CompressionMode.Compress), xws);
                // Start writing out our XML by putting in the required headers.  Note that
                // the <version> tag is required and for now must be 1, but the <generator>
                // and <comment> tags are technically optional.  Generator is highly recommended,
                // however, as that helps us ID where the file came from.
                xw.WriteStartDocument();
                xw.WriteStartElement("cryptnos", "http://www.cryptnos.com/");
                xw.WriteElementString("version", "1");
                if (!String.IsNullOrEmpty(generator))
                {
                    xw.WriteElementString("generator", generator);
                }
                if (!String.IsNullOrEmpty(comment))
                {
                    xw.WriteElementString("comment", comment);
                }
                xw.WriteElementString("siteCount", siteList.Count.ToString());
                // Start writing out the <sites> tag
                xw.WriteStartElement("sites");
                // Now step through each site parameter group and write out a <site>
                // tag to contain its data:
                foreach (SiteParameters site in siteList)
                {
                    xw.WriteStartElement("site");
                    xw.WriteElementString("siteToken", site.Site);
                    xw.WriteElementString("hash",
                                          HashEngine.HashEnumStringToDisplayHash(site.Hash));
                    xw.WriteElementString("iterations", site.Iterations.ToString());
                    xw.WriteElementString("charTypes", site.CharTypes.ToString());
                    if (site.CharLimit < 0)
                    {
                        xw.WriteElementString("charLimit", "0");
                    }
                    else
                    {
                        xw.WriteElementString("charLimit", site.CharLimit.ToString());
                    }
                    xw.WriteEndElement();
                }
                // Close the <sites> tag:
                xw.WriteEndElement();
                // Close the <cryptnos> tag and the rest of the document:
                xw.WriteEndElement();
                xw.WriteEndDocument();
                xw.Flush();
                xw.Close();
                ms.Flush();
                ms.Close();
                // Get the contents of the memory stream as raw bytes:
                byte[] plaintext = ms.ToArray();
                // Create the cipher.  Note that we're using the encryption
                // mode, and that we're passing in the password:
                BufferedBlockCipher cipher = CreateCipher(password, true);
                // Create our ciphertext container.  Note that we call the
                // cipher's getOutputSize() method, which tells us how big
                // the resulting ciphertext should be.  In practice, this
                // has always been the same size as the plaintext, but we
                // can't take that for granted.
                byte[] ciphertext = new byte[cipher.GetOutputSize(plaintext.Length)];
                // Do the encyrption.  Note that the .NET version is different from
                // the Java version.  Here we've got it easy.  The BC classes include
                // a simpler one-call DoFinal() method that does everything for us.
                ciphertext = cipher.DoFinal(plaintext);
                // Write the ciphertext to the export file:
                FileStream fs = new FileStream(filename, FileMode.Create);
                fs.Write(ciphertext, 0, ciphertext.Length);
                // Close up shop:
                fs.Flush();
                fs.Close();
                plaintext  = null;
                ciphertext = null;
            }
            catch (Exception ex) { throw ex; }
        }