Пример #1
0
        /// <summary>
        /// Get a key for a new database.  The user is first asked for the key filename (by default
        /// same location and base filename as the database, but with a different extension).  Next,
        /// the user selects what certificates to encrypt for.  A 256-byte random key is generated.
        /// </summary>
        /// <param name="strPath">Full filename of the database file.</param>
        /// <returns>A byte array with the key, or null if an error occurs.  If an error occurs, user is
        /// notified of the error.</returns>
        byte[] GetNewKey(string strPath)
        {
            MessageBox.Show(Res.str(Res.STR_ENC_KEY_INTRO), Res.str(Res.STR_APP_TITLE),
                            MessageBoxButtons.OK, MessageBoxIcon.Information);

            SaveFileDialog sfd = UIUtil.CreateSaveFileDialog(Res.str(Res.STR_CREATE_KEY_FILE),
                                                             UrlUtil.StripExtension(UrlUtil.GetFileName(strPath)) + "." +
                                                             CertProtKeyFileExtension, UIUtil.CreateFileTypeFilter(CertProtKeyFileExtension,
                                                                                                                   Res.str(Res.STR_CERT_PROT_KEY_FILE), true), 1, CertProtKeyFileExtension, true);

            if (sfd.ShowDialog() != DialogResult.OK)
            {
                return(null);
            }

            CryptoRandom rnd = CryptoRandom.Instance;

            byte[] key = rnd.GetRandomBytes(256);

            try
            {
                byte[] p7m = SelectCertsAndEncryptMsg(key);
                if (p7m == null)
                {
                    return(null);
                }

                BinaryWriter writer = new BinaryWriter(File.Open(sfd.FileName, FileMode.Create));
                writer.Write(p7m);
                writer.Close();

                return(key);
            }
            catch (SystemException e)
            {
                String msg = String.Format(Res.str(Res.STR_ERR_ENCRYPTING_KEY), e.Message);
                MessageBox.Show(msg, Res.AppTitle);
                return(null);
            }
        }
Пример #2
0
        /// <summary>
        /// Encrypt a byte array for a user-selected set of encryption certificates.  More than 1 certificate
        /// can be selected.  Certificates can be selected from the "My" store and the "AddressBook" store.
        /// </summary>
        /// <param name="key">Data to encrypt</param>
        /// <returns>Encrypted blob</returns>
        private byte[] SelectCertsAndEncryptMsg(byte[] data)
        {
            X509Store addrBookStore = new X509Store(StoreName.AddressBook, StoreLocation.CurrentUser);

            addrBookStore.Open(OpenFlags.ReadOnly);
            X509Store myStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);

            myStore.Open(OpenFlags.ReadOnly);

            X509Certificate2Collection allCerts = (X509Certificate2Collection)addrBookStore.Certificates;

            allCerts.AddRange(myStore.Certificates);

            addrBookStore.Close();
            myStore.Close();

            X509Certificate2Collection fcollection = (X509Certificate2Collection)allCerts.Find(
                X509FindType.FindByTimeValid,
                DateTime.Now, false);

            fcollection = fcollection.Find(X509FindType.FindByKeyUsage,
                                           X509KeyUsageFlags.KeyEncipherment, false);
            X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection,
                                                                                             Res.str(Res.STR_SELECT_CERT), Res.str(Res.STR_SELECT_CERT_LONG),
                                                                                             X509SelectionFlag.MultiSelection);

            if (scollection == null || scollection.Count < 1)
            {
                return(null);
            }

            // validate certificates
            X509Chain chain = new X509Chain();

            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            X509Certificate2Collection toRemove = new X509Certificate2Collection();

            foreach (X509Certificate2 cert in scollection)
            {
                Boolean chainRc = false;
                try
                {
                    Cursor.Current = Cursors.WaitCursor;
                    chainRc        = chain.Build(cert);
                }
                finally
                {
                    Cursor.Current = Cursors.Default;
                }

                if (!chainRc)
                {
                    // certificate is invalid ... keep it?
                    String certInfoTemplate = String.Format(Res.str(Res.STR_CERT_INFO_TEMPLATE),
                                                            cert.Subject,
                                                            cert.Issuer,
                                                            cert.GetSerialNumberString());
                    String        warning = String.Format(Res.str(Res.STR_CERT_DIDNT_VALIDATE_CONTINUE), certInfoTemplate);
                    StringBuilder reason  = new StringBuilder();
                    for (int index = 0; index < chain.ChainStatus.Length; index++)
                    {
                        reason.AppendLine(chain.ChainStatus[index].StatusInformation);
                    }
                    DialogResult decision = MessageBox.Show(warning + "\n\n" + reason.ToString(), Res.str(Res.STR_APP_TITLE),
                                                            MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);
                    if (decision == DialogResult.Cancel)
                    {
                        return(null);
                    }
                    if (decision == DialogResult.No)
                    {
                        toRemove.Insert(0, cert);
                    }
                }
            }

            foreach (X509Certificate2 cert in toRemove)
            {
                scollection.Remove(cert);
            }

            if (scollection.Count < 1)
            {
                MessageBox.Show(Res.str(Res.STR_NO_CERTS_LEFT), Res.str(Res.STR_APP_TITLE));
                return(null);
            }

            // check to make sure the user can decrypt the key
            bool havePrivateKey = false;

            foreach (X509Certificate2 cert in scollection)
            {
                havePrivateKey |= cert.HasPrivateKey;
            }

            if (!havePrivateKey)
            {
                DialogResult decision = MessageBox.Show(Res.str(Res.STR_NO_PRIV_KEY_IN_CERTS), Res.str(Res.STR_APP_TITLE),
                                                        MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2);
                if (decision == DialogResult.No)
                {
                    return(null);
                }
            }


            byte[] p7m = CryptoCmsTools.EncryptMsg(data, scollection);
            return(p7m);
        }
Пример #3
0
        /// <summary>
        /// Get a key for an existing database.  First, the key file is located, either because its location
        /// and filename are the same as the database path (with the exception of the extension), or the user
        /// is asked.  Then, the key file is decrypted using a private key.
        /// </summary>
        /// <param name="strPath">Full filename of the database file.</param>
        /// <returns>A byte array with the key, or null if an error occurs.  If an error occurs, user is
        /// notified of the error.</returns>
        byte[] GetExistingKey(IOConnectionInfo ioc)
        {
            Stream stream = null;

            try
            {
                string           newpath = UrlUtil.StripExtension(ioc.Path) + "." + CertProtKeyFileExtension;
                IOConnectionInfo keyIoc  = ioc.CloneDeep();
                keyIoc.Path = newpath;
                stream      = IOConnection.OpenRead(keyIoc);
            }
            catch (Exception)
            {
                // strPath may be a URL (even if IsLocalFile returns true?),
                // whatever the reason, fall through and the user can pick a
                // local file as the key file
            }

            if (stream == null || !stream.CanRead)
            {
                // fall back on opening a local file
                // FUTURE ENHANCEMENT: allow user to enter a URL and name/pwd as well

                OpenFileDialog ofd = UIUtil.CreateOpenFileDialog(Res.str(Res.STR_OPEN_KEY_FILE),
                                                                 UIUtil.CreateFileTypeFilter(CertProtKeyFileExtension, Res.str(Res.STR_CERT_PROT_KEY_FILE), true),
                                                                 1, CertProtKeyFileExtension, false /* multi-select */, true);

                if (ofd.ShowDialog() != DialogResult.OK)
                {
                    return(null);
                }
                stream = IOConnection.OpenRead(IOConnectionInfo.FromPath(ofd.FileName));
            }

            try
            {
                BinaryReader reader = new BinaryReader(stream);
                byte[]       p7m    = reader.ReadBytes(MAX_KEY_FILE_LENGTH);
                // URL streams don't support seeking, and so Position doesn't work
                //bool tooBig = stream.Position >= MAX_KEY_FILE_LENGTH;
                bool tooBig = p7m.Length >= MAX_KEY_FILE_LENGTH;
                reader.Close();

                if (tooBig)
                {
                    MessageBox.Show(Res.str(Res.STR_KEY_FILE_TOO_BIG), Res.AppTitle);
                    return(null);
                }

                Cursor.Current = Cursors.WaitCursor;
                return(CryptoCmsTools.DecryptMsg(p7m));
            }
            catch (SystemException ex)  // covers IOException and CryptographicException
            {
                String msg = String.Format(Res.str(Res.STR_ERR_DECRYPTING_KEY), ex.ToString());
                //String msg = String.Format(Res.str(Res.STR_ERR_DECRYPTING_KEY), getCryptoExceptionDetails(ex));
                MessageBox.Show(msg, Res.AppTitle);
                return(null);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }