コード例 #1
0
        public void SecureFile_Stream_NoContent()
        {
            string privateKey              = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey               = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original  = new EnhancedMemoryStream();
            EnhancedMemoryStream encrypted = new EnhancedMemoryStream();
            EnhancedMemoryStream decrypted = new EnhancedMemoryStream();
            SecureFile           secure    = null;

            secure            = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
            original.Position = 0;
            secure.EncryptTo(encrypted, CryptoAlgorithm.AES, 256);
            secure.Close();
            secure = null;

            original.Position  = 0;
            encrypted.Position = 0;
            Assert.AreNotEqual(original.ReadBytesToEnd(), encrypted.ReadBytesToEnd());

            encrypted.Position = 0;
            secure             = new SecureFile(encrypted, SecureFileMode.Decrypt, privateKey);
            secure.DecryptTo(decrypted);
            secure.Close();
            secure = null;

            Assert.AreEqual(0, decrypted.Length);
        }
コード例 #2
0
        public void SecureFile_Stream_LargeContent()
        {
            string privateKey              = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey               = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original  = new EnhancedMemoryStream();
            EnhancedMemoryStream encrypted = new EnhancedMemoryStream();
            EnhancedMemoryStream decrypted = new EnhancedMemoryStream();
            SecureFile           secure    = null;

            for (int i = 0; i < 128000; i++)
            {
                original.WriteByte((byte)i);
            }

            secure            = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
            original.Position = 0;
            secure.EncryptTo(encrypted, CryptoAlgorithm.AES, 256);
            secure.Close();
            secure = null;

            encrypted.Position = 0;
            secure             = new SecureFile(encrypted, SecureFileMode.Decrypt, privateKey);
            secure.DecryptTo(decrypted);
            secure.Close();
            secure = null;

            original.Position  = 0;
            encrypted.Position = 0;
            CollectionAssert.AreNotEqual(original.ReadBytesToEnd(), encrypted.ReadBytesToEnd());

            original.Position  = 0;
            decrypted.Position = 0;
            CollectionAssert.AreEqual(original.ReadBytesToEnd(), decrypted.ReadBytesToEnd());
        }
コード例 #3
0
        public void SecureFile_Stream_BadHash()
        {
            string privateKey              = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey               = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original  = new EnhancedMemoryStream();
            EnhancedMemoryStream encrypted = new EnhancedMemoryStream();
            EnhancedMemoryStream decrypted = new EnhancedMemoryStream();
            SecureFile           secure    = null;
            byte b;

            for (int i = 0; i < 100; i++)
            {
                original.WriteByte((byte)i);
            }

            secure            = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
            original.Position = 0;
            secure.EncryptTo(encrypted, CryptoAlgorithm.AES, 256);
            secure.Close();
            secure = null;

            // Munge the last byte of the hash digest and then
            // confirm the this is detected

            encrypted.Position = encrypted.Length - 1;
            b = (byte)encrypted.ReadByte();
            encrypted.Position = encrypted.Length - 1;
            encrypted.WriteByte((byte)(~b));

            encrypted.Position = 0;
            secure             = new SecureFile(encrypted, SecureFileMode.Decrypt, privateKey);

            try
            {
                secure.DecryptTo(decrypted);
                Assert.Fail("Corrupt hash digest not detected.");
            }
            catch
            {
                // Expecting an exception
            }
        }
コード例 #4
0
        public void SecureFile_Stream_Metadata()
        {
            string privateKey               = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey                = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original   = new EnhancedMemoryStream();
            EnhancedMemoryStream encrypted  = new EnhancedMemoryStream();
            EnhancedMemoryStream decrypted  = new EnhancedMemoryStream();
            SecureFile           secure     = null;
            DateTime             createTime = Helper.UtcNowRounded - TimeSpan.FromMinutes(1);
            DateTime             writeTime  = Helper.UtcNowRounded;

            secure = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
            secure.Properties["Foo"]   = "Bar";
            secure.Properties["Hello"] = "World";
            secure.FileName            = "Test.dat";
            secure.FullPath            = "c:\\test\\test.dat";
            secure.CreateTimeUtc       = createTime;
            secure.WriteTimeUtc        = writeTime;
            original.Position          = 0;
            secure.EncryptTo(encrypted, CryptoAlgorithm.AES, 256);
            secure.Close();
            secure = null;

            original.Position  = 0;
            encrypted.Position = 0;
            Assert.AreNotEqual(original.ReadBytesToEnd(), encrypted.ReadBytesToEnd());

            encrypted.Position = 0;
            secure             = new SecureFile(encrypted, SecureFileMode.Decrypt, privateKey);
            secure.DecryptTo(decrypted);
            Assert.AreEqual("Bar", secure.Properties["Foo"]);
            Assert.AreEqual("World", secure.Properties["Hello"]);
            Assert.AreEqual("Test.dat", secure.FileName);
            Assert.AreEqual("c:\\test\\test.dat", secure.FullPath);
            Assert.AreEqual(createTime, secure.CreateTimeUtc);
            Assert.AreEqual(writeTime, secure.WriteTimeUtc);
            secure.Close();
            secure = null;

            Assert.AreEqual(0, decrypted.Length);
        }
コード例 #5
0
        /// <summary>
        /// Implements the background thread.
        /// </summary>
        private void DownloadThread()
        {
            DateTime    lastWarningTime = DateTime.MinValue;
            PolledTimer pollTimer;
            bool        resetTimer;

            try
            {
                // Initialize the GeoTracker file folder

                try
                {
                    Helper.CreateFileTree(dataPath);

                    if (File.Exists(downloadPath))
                    {
                        SysLog.LogWarning("GeoTracker: Deleting existing temporary [{0}] file on startup.", downloadPath);
                        Helper.DeleteFile(downloadPath);
                    }

                    if (File.Exists(decryptedPath))
                    {
                        SysLog.LogWarning("GeoTracker: Deleting existing temporary [{0}] file on startup.", decryptedPath);
                        Helper.DeleteFile(decryptedPath);
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }

                // Initalize the poll timer.  We'll schedule an immediate download if the data file does
                // not exist, otherwise we'll delay the polling for a random period of time between
                // 0 and 15 minutes in the hope that we'll end up staggering the polling times across
                // the server cluster (so we won't hammer the source website).

                pollTimer  = new PolledTimer(settings.IPGeocodeSourcePollInterval, false);
                resetTimer = false;

                if (!File.Exists(dataPath))
                {
                    pollTimer.FireNow();
                }
                else
                {
                    pollTimer.ResetRandomTemporary(TimeSpan.Zero, TimeSpan.FromMinutes(15));
                }

                // The polling loop.

                while (true)
                {
                    if (stopPending)
                    {
                        return;
                    }

                    try
                    {
                        if (pollDataNow)
                        {
                            pollTimer.FireNow();
                            pollDataNow = false;
                        }

                        if (pollTimer.HasFired)
                        {
                            DateTime        fileDateUtc = DateTime.UtcNow;
                            bool            isUpdate    = false;
                            double          fileSize    = 0;
                            ElapsedTimer    downloadTimer;
                            HttpWebRequest  request;
                            HttpWebResponse response;
                            HttpStatusCode  statusCode;

                            resetTimer = true;

                            // If a database file already exists then extract its last modify
                            // date and use this in an If-Modified-Since request to the source
                            // website to see if there's an updated file.

                            if (File.Exists(dataPath))
                            {
                                request         = (HttpWebRequest)WebRequest.Create(settings.IPGeocodeSourceUri);
                                request.Timeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;

                                isUpdate    = true;
                                fileDateUtc = File.GetLastWriteTimeUtc(dataPath);

                                request.Method          = "HEAD";
                                request.IfModifiedSince = fileDateUtc;

                                try
                                {
                                    using (response = (HttpWebResponse)request.GetResponse())
                                        statusCode = response.StatusCode;
                                }
                                catch (WebException e)
                                {
                                    statusCode = ((HttpWebResponse)e.Response).StatusCode;
                                }

                                if (statusCode == HttpStatusCode.NotModified)
                                {
                                    // The source website does not have an updated file.  I'm going to
                                    // do one extra check to see if the file we have is more than 45
                                    // days old and log a warning.  Note that we're going to issue this
                                    // warning only once a week while the service is running.

                                    if (DateTime.UtcNow - fileDateUtc < TimeSpan.FromDays(45) || DateTime.UtcNow - lastWarningTime >= TimeSpan.FromDays(7))
                                    {
                                        continue;
                                    }

                                    lastWarningTime = DateTime.UtcNow;

                                    const string warning =
                                        @"GeoTracker: The local copy of the MaxMind GeoIP City or GeoLite City database is [{0}] days old 
and should be updated.  You may need to download a new copy of the database from http://maxmind.com,
decompress it and upload it to the source website at [{1}].

Note: Make sure that the website is configured with the [.DAT=application/octet-stream] MIME mapping.";

                                    SysLog.LogWarning(warning, (int)(DateTime.UtcNow - fileDateUtc).TotalDays, settings.IPGeocodeSourceUri);
                                    continue;
                                }
                            }

                            // Download the database to the temporary download file.

                            Helper.DeleteFile(downloadPath);

                            downloadTimer = new ElapsedTimer(true);
                            fileSize      = Helper.WebDownload(settings.IPGeocodeSourceUri, downloadPath, settings.IPGeocodeSourceTimeout, out response);
                            downloadTimer.Stop();

                            // Set the file times to match the Last-Modified header received from the website (it any).

                            string lastModified = response.Headers["Last-Modified"];

                            if (lastModified != null)
                            {
                                try
                                {
                                    fileDateUtc = Helper.ParseInternetDate(lastModified);
                                    File.SetCreationTimeUtc(downloadPath, fileDateUtc);
                                    File.SetLastWriteTimeUtc(downloadPath, fileDateUtc);
                                }
                                catch (Exception e)
                                {
                                    SysLog.LogException(e, "GeoTracker: Website for [{0}] returned invalid Last-Modified header [{1}].",
                                                        settings.IPGeocodeSourceUri, lastModified);
                                }
                            }

                            // Decrypt the file and set its file dates.

                            var keyChain = new KeyChain(settings.IPGeocodeSourceRsaKey);

                            using (var secureFile = new SecureFile(downloadPath, keyChain))
                            {
                                secureFile.DecryptTo(decryptedPath);
                            }

                            File.SetCreationTimeUtc(decryptedPath, fileDateUtc);
                            File.SetLastWriteTimeUtc(decryptedPath, fileDateUtc);

                            // Verify the decrypted data file and then swap in new file.

                            const string info =
                                @"GeoTracker: {0} of IP-to-location database from [{1}] completed.
Downloaded [{2:#.#}MB] bytes in [{3}].";

                            SysLog.LogInformation(info, isUpdate ? "Update download" : "Initial download", settings.IPGeocodeSourceUri, fileSize / (1024 * 1024), downloadTimer.ElapsedTime);

                            // Create a new MaxMind lookup intance and then swap it in without interrupting
                            // any queries in progress.

                            try
                            {
                                LookupService newMaxMind;

                                newMaxMind = new LookupService(decryptedPath, LookupService.GEOIP_MEMORY_CACHE);
                                newMaxMind.close();

                                maxMind = newMaxMind;
                                UpdateCount++;
                            }
                            catch (Exception e)
                            {
                                SysLog.LogException(e);
                                SysLog.LogError("GeoTracker: The MaxMind downloaded database file [{0}] appears to be corrupted.  This will be deleted so the downloader can get a fresh copy.", downloadPath);
                            }

                            lock (syncLock)
                            {
                                Helper.DeleteFile(dataPath);
                                File.Copy(decryptedPath, dataPath);
                                File.SetCreationTimeUtc(dataPath, fileDateUtc);
                                File.SetLastWriteTimeUtc(dataPath, fileDateUtc);
                            }

                            // Delete the temporary files.

                            Helper.DeleteFile(decryptedPath);
                            Helper.DeleteFile(downloadPath);
                        }
                    }
                    catch (WebException e)
                    {
                        SysLog.LogException(e);
                        SysLog.LogWarning("GeoTracker: The download of the MaxMind database file has failed. The service will try again in 1 minute.");

                        pollTimer.ResetTemporary(TimeSpan.FromMinutes(1));
                        resetTimer = false;
                    }
                    catch (ThreadAbortException e)
                    {
                        SysLog.LogException(e);
                        throw;
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e);
                    }
                    finally
                    {
                        if (resetTimer)
                        {
                            resetTimer = false;
                            pollTimer.Reset();
                        }
                    }

                    Thread.Sleep(settings.BkInterval);
                }
            }
            finally
            {
                running = false;
            }
        }
コード例 #6
0
        public void SecureFile_File_KeyChain()
        {
            string encryptName            = Path.GetTempFileName();
            string privateKey             = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey              = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original = new EnhancedMemoryStream();
            SecureFile           secure   = null;

            try
            {
                for (int i = 0; i < 100; i++)
                {
                    original.WriteByte((byte)i);
                }

                // Verify that SecureFile can find the correct private key in the key chain.

                secure = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
                Assert.IsTrue(secure.SavePublicKey);
                Assert.AreEqual(publicKey, secure.PublicKey);

                original.Position = 0;
                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                secure.Close();
                secure = null;

                var keyChain  = new KeyChain();
                var decrypted = new EnhancedMemoryStream();

                keyChain.Add(privateKey);

                secure = new SecureFile(encryptName, keyChain);
                secure.DecryptTo(decrypted);
                secure.Close();
                secure = null;

                CollectionAssert.AreEqual(original.ToArray(), decrypted.ToArray());

                // Verify that SecureFile throws a CryptographicException if the
                // key is not present in the chain.

                keyChain.Clear();

                try
                {
                    secure = new SecureFile(encryptName, keyChain);
                    secure.DecryptTo(decrypted);
                    Assert.Fail("Expecting a CryptographicException");
                }
                catch (CryptographicException)
                {
                    // Expecting this
                }
                finally
                {
                    if (secure != null)
                    {
                        secure.Close();
                        secure = null;
                    }
                }

                // Verify that SecureFile throws a CryptographicException if the
                // public key was not saved to the file.

                keyChain.Add(privateKey);

                secure = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
                secure.SavePublicKey = false;

                original.Position = 0;

                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                secure.Close();
                secure = null;

                try
                {
                    secure = new SecureFile(encryptName, keyChain);
                    secure.DecryptTo(decrypted);
                    Assert.Fail("Expecting a CryptographicException");
                }
                catch (CryptographicException)
                {
                    // Expecting this
                }
                finally
                {
                    if (secure != null)
                    {
                        secure.Close();
                        secure = null;
                    }
                }
            }
            finally
            {
                System.IO.File.Delete(encryptName);
            }
        }
コード例 #7
0
        public void SecureFile_File_Metadata()
        {
            string         originalName = Path.GetTempFileName();
            string         encryptName  = Path.GetTempFileName();
            string         decryptName  = Path.GetTempFileName();
            string         privateKey   = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string         publicKey    = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedStream original     = null;
            EnhancedStream encrypted    = null;
            EnhancedStream decrypted    = null;
            SecureFile     secure       = null;
            DateTime       createTime   = Helper.UtcNowRounded - TimeSpan.FromMinutes(1);
            DateTime       writeTime    = Helper.UtcNowRounded;

            try
            {
                original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite);

                for (int i = 0; i < 100; i++)
                {
                    original.WriteByte((byte)i);
                }

                original.Close();
                original = null;

                Directory.SetCreationTimeUtc(originalName, createTime);
                Directory.SetLastWriteTimeUtc(originalName, writeTime);

                secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey);
                secure.Properties["Foo"]   = "Bar";
                secure.Properties["Hello"] = "World";
                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                Assert.AreEqual(Path.GetFileName(originalName), secure.FileName);
                Assert.AreEqual(createTime, secure.CreateTimeUtc);
                Assert.AreEqual(writeTime, secure.WriteTimeUtc);
                secure.Close();
                secure = null;

                secure = new SecureFile(encryptName, SecureFileMode.Decrypt, privateKey);
                Assert.AreEqual("Bar", secure.Properties["Foo"]);
                Assert.AreEqual("World", secure.Properties["Hello"]);
                Assert.AreEqual(Path.GetFileName(originalName), secure.FileName);
                Assert.AreEqual(createTime, secure.CreateTimeUtc);
                Assert.AreEqual(writeTime, secure.WriteTimeUtc);
                secure.DecryptTo(decryptName);
                secure.Close();
                secure = null;

                Assert.AreEqual(createTime, Directory.GetCreationTimeUtc(decryptName));
                Assert.AreEqual(writeTime, Directory.GetLastWriteTimeUtc(decryptName));

                original  = new EnhancedFileStream(originalName, FileMode.Open, FileAccess.Read);
                encrypted = new EnhancedFileStream(encryptName, FileMode.Open, FileAccess.Read);
                decrypted = new EnhancedFileStream(decryptName, FileMode.Open, FileAccess.Read);

                original.Position  = 0;
                encrypted.Position = 0;
                Assert.AreNotEqual(original.ReadBytesToEnd(), encrypted.ReadBytesToEnd());

                original.Position  = 0;
                decrypted.Position = 0;
                CollectionAssert.AreEqual(original.ReadBytesToEnd(), decrypted.ReadBytesToEnd());
            }
            finally
            {
                if (original != null)
                {
                    original.Close();
                }

                if (encrypted != null)
                {
                    encrypted.Close();
                }

                if (decrypted != null)
                {
                    decrypted.Close();
                }

                System.IO.File.Delete(originalName);
                System.IO.File.Delete(encryptName);
                System.IO.File.Delete(decryptName);
            }
        }
コード例 #8
0
        public void SecureFile_File_BadHash()
        {
            string         originalName = Path.GetTempFileName();
            string         encryptName  = Path.GetTempFileName();
            string         decryptName  = Path.GetTempFileName();
            string         privateKey   = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string         publicKey    = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedStream original     = null;
            EnhancedStream encrypted    = null;
            SecureFile     secure       = null;
            byte           b;

            try
            {
                original = new EnhancedFileStream(originalName, FileMode.Create, FileAccess.ReadWrite);

                for (int i = 0; i < 100; i++)
                {
                    original.WriteByte((byte)i);
                }

                original.Close();
                original = null;

                secure = new SecureFile(originalName, SecureFileMode.Encrypt, publicKey);
                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                secure.Close();
                secure = null;

                // Munge the last byte of the hash digest and then confirm
                // that the bad hash is detected.

                encrypted          = new EnhancedFileStream(encryptName, FileMode.Open, FileAccess.ReadWrite);
                encrypted.Position = encrypted.Length - 1;
                b = (byte)encrypted.ReadByte();
                encrypted.Position = encrypted.Length - 1;
                encrypted.WriteByte((byte)(~b));
                encrypted.Close();
                encrypted = null;

                ExtendedAssert.Throws <CryptographicException>(
                    () =>
                {
                    secure = new SecureFile(encryptName, SecureFileMode.Decrypt, privateKey);
                    secure.DecryptTo(decryptName);
                });
            }
            finally
            {
                if (original != null)
                {
                    original.Close();
                }

                if (encrypted != null)
                {
                    encrypted.Close();
                }

                try { System.IO.File.Delete(originalName); } catch { }
                try { System.IO.File.Delete(encryptName); } catch { }
                try { System.IO.File.Delete(decryptName); } catch { }
            }
        }
コード例 #9
0
        private static int DecryptSecureFile(string[] args)
        {
            CommandLine cmdLine        = new CommandLine(args, false);
            string      inPath         = cmdLine.GetOption("in", null);
            string      outPath        = cmdLine.GetOption("out", null);
            string      keyChainOption = cmdLine.GetOption("keychain", null);
            KeyChain    keyChain       = null;

            if (inPath == null)
            {
                Program.Error("[-in:<path>] command line option is required.");
                return(1);
            }

            if (outPath == null)
            {
                Program.Error("[-out:<path>] command line option is required.");
                return(1);
            }

            if (keyChainOption != null)
            {
                string       keyPath;
                int          pos;
                SymmetricKey symkey;

                pos = keyChainOption.IndexOf(';');
                if (pos != -1)
                {
                    // Keychain file is encrypted.

                    keyPath  = keyChainOption.Substring(0, pos);
                    symkey   = new SymmetricKey(keyChainOption.Substring(pos + 1));
                    keyChain = new KeyChain(symkey, File.ReadAllBytes(keyPath));
                }
                else
                {
                    // Keychain file is not encrypted.

                    keyChain = new KeyChain();

                    using (var input = new StreamReader(keyChainOption))
                    {
                        for (var line = input.ReadLine(); line != null; line = input.ReadLine())
                        {
                            var trimmed = line.Trim();

                            if (trimmed.Length == 0 || trimmed.StartsWith("//") || trimmed.StartsWith("--"))
                            {
                                continue;
                            }

                            keyChain.Add(trimmed);
                        }
                    }
                }

                if (keyChain.Count == 0)
                {
                    Program.Error("The keychain is empty.");
                    return(1);
                }
            }
            else
            {
                keyChain = new KeyChain();
            }

            var keys = cmdLine.GetOptionValues("key");

            foreach (var key in keys)
            {
                keyChain.Add(key);
            }

            if (keyChain.Count == 0)
            {
                Program.Error("A private RSA key must be specified using a [-key] or [-keychain] option.");
                return(1);
            }

            using (var secureFile = new SecureFile(inPath, keyChain))
            {
                secureFile.DecryptTo(outPath);
            }

            return(0);
        }