예제 #1
0
        public static string Encrypt(string srcDir)
        {
            var masterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());
            var dstDir    = Path.Combine(Path.GetDirectoryName(srcDir), "Temp.Encryption");

            var srcOptions = StorageEnvironmentOptions.ForPath(srcDir);
            var dstOptions = StorageEnvironmentOptions.ForPath(dstDir);

            dstOptions.Encryption.MasterKey = masterKey;

            var protect = new SecretProtection(new SecurityConfiguration()).Protect(masterKey);

            StorageCompaction.Execute(srcOptions, (StorageEnvironmentOptions.DirectoryStorageEnvironmentOptions)dstOptions);

            using (var f = File.OpenWrite(Path.Combine(dstDir, SecretKeyEncrypted)))
            {
                f.Write(protect, 0, protect.Length);
                f.Flush();
            }

            IOExtensions.DeleteDirectory(srcDir);
            Directory.Move(dstDir, srcDir);

            return($"Encrypt: {Path.Combine(dstDir, SecretKeyEncrypted)} Created Successfully");
        }
예제 #2
0
        public byte[] LoadMasterKeyFromPath()
        {
            try
            {
                var key             = File.ReadAllBytes(_config.MasterKeyPath);
                var expectedKeySize = (int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes();

                // we require that the key will exists (so admin will generate proper permissions)
                // but if the size is zero, we'll generate a radnom key and save it to the specified
                // file

                if (key.Length == 0)
                {
                    key = Sodium.GenerateRandomBuffer(expectedKeySize);
                    File.WriteAllBytes(_config.MasterKeyPath, key);
                }

                if (key.Length != expectedKeySize)
                {
                    throw new InvalidOperationException(
                              $"The size of the key must be {expectedKeySize * 8} bits, but was {key.Length * 8} bits.");
                }
                return(key);
            }
            catch (Exception e)
            {
                throw new CryptographicException(
                          $"Unable to open the master secret key at {_config.MasterKeyPath}, won't proceed because losing this key will lose access to all user encrypted information. Admin assistance required.",
                          e);
            }
        }
예제 #3
0
        public byte[] Protect(byte[] secret)
        {
            if (PlatformDetails.RunningOnPosix == false && _config.MasterKeyExec == null && _config.MasterKeyPath == null)
            {
                var tempKey = new byte[(int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes()];
                fixed(byte *pTempKey = tempKey)
                {
                    Sodium.randombytes_buf(pTempKey, Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());

                    var encryptProtectedData = EncryptProtectedData(secret, tempKey);
                    var dpapiEntropy         = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_npubbytes());

                    //DPAPI doesn't do AEAD, so we encrypt the data as usual, then encrypt the temp key we use with DPAPI
                    var protectedKey = ProtectedData.Protect(tempKey, dpapiEntropy, DataProtectionScope.CurrentUser);

                    Sodium.sodium_memzero(pTempKey, (UIntPtr)tempKey.Length);

                    var ms = new MemoryStream();
                    var bw = new BinaryWriter(ms);

                    bw.Write(protectedKey.Length);
                    bw.Write(protectedKey);
                    bw.Write(dpapiEntropy.Length);
                    bw.Write(dpapiEntropy);
                    bw.Write(encryptProtectedData.Length);
                    bw.Write(encryptProtectedData);
                    bw.Flush();
                    return(ms.ToArray());
                }
            }

            return(EncryptProtectedData(secret, _serverMasterKey.Value));
        }
예제 #4
0
        protected override void Configure(StorageEnvironmentOptions options)
        {
            base.Configure(options);

            options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());
            options.ManualFlushing       = true;
        }
예제 #5
0
        public static string PutKey(string destDir)
        {
            var base64Key = RecoverServerStoreKey(destDir);
            var entropy   = Sodium.GenerateRandomBuffer(256);
            var secret    = Convert.FromBase64String(base64Key);
            var protect   = new SecretProtection(new SecurityConfiguration()).Protect(secret, entropy);

            using (var f = File.OpenWrite(Path.Combine(destDir, SecretKeyEncrypted)))
            {
                f.Write(protect, 0, protect.Length);
                f.Write(entropy, 0, entropy.Length);
                f.Flush();
            }

            return($"PutKey: {Path.Combine(destDir, SecretKeyEncrypted)} Created Successfully");
        }
예제 #6
0
        public unsafe void RavenDB_15975()
        {
            using (var options = StorageEnvironmentOptions.ForPath(DataDir))
            {
                options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());

                using (var innerPager = LinuxTestUtils.GetNewPager(options, DataDir, "Raven.Voron"))
                {
                    AbstractPager cryptoPager;
                    using (cryptoPager = new CryptoPager(innerPager))
                    {
                        using (var tx = new TempPagerTransaction(isWriteTransaction: true))
                        {
                            var overflowSize = 4 * Constants.Storage.PageSize + 100;

                            cryptoPager.EnsureContinuous(26, 5);
                            var pagePointer = cryptoPager.AcquirePagePointerForNewPage(tx, 26, 5);

                            var header = (PageHeader *)pagePointer;
                            header->PageNumber   = 26;
                            header->Flags        = PageFlags.Overflow;
                            header->OverflowSize = overflowSize;

                            Memory.Set(pagePointer + PageHeader.SizeOf, (byte)'X', overflowSize);
                        }


                        using (var tx = new TempPagerTransaction())
                        {
                            var pagePointer = cryptoPager.AcquirePagePointer(tx, 26);

                            // Making sure that the data was decrypted and still holds those 'X' chars
                            Assert.True(pagePointer[PageHeader.SizeOf] == 'X');
                            Assert.True(pagePointer[666] == 'X');
                            Assert.True(pagePointer[1039] == 'X');
                        }
                    }
                }
            }
        }
예제 #7
0
        public unsafe void StreamsTempFile_With_Encryption_ShouldNotThrow_When_NotAllStreamsWereRead()
        {
            using (var options = StorageEnvironmentOptions.ForPath(DataDir))
            {
                options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());
                using (var environment = new StorageEnvironment(options))
                {
                    using (var temp = new StreamsTempFile(Path.Combine(DataDir, "EncryptedTempFile"), environment))
                    {
                        for (int j = 0; j < 10; j++)
                        {
                            using (temp.Scope())
                            {
                                var streams = new List <Stream>();
                                for (var i = 0; i < 10; i++)
                                {
                                    var stream = temp.StartNewStream();
                                    var bytes  = new byte[1024];
                                    fixed(byte *b = bytes)
                                    {
                                        Memory.Set(b, (byte)i, bytes.Length);
                                    }

                                    stream.Write(bytes, 0, bytes.Length);
                                    stream.Flush();
                                    streams.Add(stream);
                                }

                                streams[0].Seek(0, SeekOrigin.Begin);
                            }

                            Assert.Equal(0, temp._file.Position);
                            Assert.Equal(0, temp._file.Length);
                            Assert.True(temp._file.InnerStream.Length > 0);
                        }
                    }
                }
            }
        }
예제 #8
0
        public unsafe void WriteAndReadPageUsingCryptoPager()
        {
            using (var options = StorageEnvironmentOptions.ForPath(DataDir))
            {
                options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());

                using (var innerPager = LinuxTestUtils.GetNewPager(options, DataDir, "Raven.Voron"))
                {
                    AbstractPager cryptoPager;
                    using (cryptoPager = new CryptoPager(innerPager))
                    {
                        using (var tx = new TempPagerTransaction(isWriteTransaction: true))
                        {
                            cryptoPager.EnsureContinuous(17, 1); // We're gonna try to read and write to page 17
                            var pagePointer = cryptoPager.AcquirePagePointerForNewPage(tx, 17, 1);

                            var header = (PageHeader *)pagePointer;
                            header->PageNumber = 17;
                            header->Flags      = PageFlags.Single | PageFlags.FixedSizeTreePage;

                            Memory.Set(pagePointer + PageHeader.SizeOf, (byte)'X', Constants.Storage.PageSize - PageHeader.SizeOf);
                        }

                        using (var tx = new TempPagerTransaction())
                        {
                            var pagePointer = cryptoPager.AcquirePagePointer(tx, 17);

                            // Making sure that the data was decrypted and still holds those 'X' chars
                            Assert.True(pagePointer[PageHeader.SizeOf] == 'X');
                            Assert.True(pagePointer[666] == 'X');
                            Assert.True(pagePointer[1039] == 'X');
                        }
                    }
                }
            }
        }
예제 #9
0
        public unsafe void StreamsTempFile_With_Encryption_ShouldThrow_When_SeekAndWrite_AreMixed_Without_ExecutingReset()
        {
            using (var options = StorageEnvironmentOptions.ForPath(DataDir))
            {
                options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());
                using (var environment = new StorageEnvironment(options))
                {
                    using (var temp = new StreamsTempFile(Path.Combine(DataDir, "EncryptedTempFile"), environment))
                    {
                        var bytes = new byte[1024];
                        fixed(byte *b = bytes)
                        {
                            Memory.Set(b, (byte)'I', bytes.Length);
                        }

                        Stream stream;
                        using (temp.Scope())
                        {
                            stream = temp.StartNewStream();

                            stream.Write(bytes, 0, bytes.Length);
                            stream.Flush();

                            stream.Seek(0, SeekOrigin.Begin);

                            var read = stream.Read(new Span <byte>(new byte[10]));
                            Assert.Equal(10, read);

                            Assert.Throws <NotSupportedException>(() => stream.Write(bytes, 0, bytes.Length));
                        }

                        Assert.Throws <NotSupportedException>(() => stream.Write(bytes, 0, bytes.Length));
                    }
                }
            }
        }
예제 #10
0
        public static string GetKey(string srcDir)
        {
            var masterKey = Sodium.GenerateMasterKey();
            var dstDir    = Path.Combine(Path.GetDirectoryName(srcDir), "Temp.Encryption");

            var srcOptions = StorageEnvironmentOptions.ForPath(srcDir);
            var dstOptions = StorageEnvironmentOptions.ForPath(dstDir);

            dstOptions.MasterKey = masterKey;

            var entropy = Sodium.GenerateRandomBuffer(256);
            var protect = new SecretProtection(new SecurityConfiguration()).Protect(masterKey, entropy);

            StorageCompaction.Execute(srcOptions, (StorageEnvironmentOptions.DirectoryStorageEnvironmentOptions)dstOptions);

            using (var f = File.OpenWrite(Path.Combine(dstDir, SecretKeyEncrypted)))
            {
                f.Write(protect, 0, protect.Length);
                f.Write(entropy, 0, entropy.Length);
                f.Flush();
            }

            return($"GetKey: {Path.Combine(dstDir, SecretKeyEncrypted)} Created Successfully");
        }
예제 #11
0
        public async Task can_get_detailed_collection_statistics(bool compressed)
        {
            string strCollectionName = "Companies";

            using (var store = GetDocumentStore(new Options
            {
                ModifyDatabaseRecord = record =>
                {
                    if (!compressed)
                    {
                        record.DocumentsCompression = new DocumentsCompressionConfiguration
                        {
                            Collections = null,
                            CompressRevisions = false
                        };
                    }
                }
            }))
            {
                // configure revisions for the collection
                var configuration = new RevisionsConfiguration
                {
                    Collections = new Dictionary <string, RevisionsCollectionConfiguration>
                    {
                        {
                            "Companies", new RevisionsCollectionConfiguration()
                            {
                                Disabled = false
                            }
                        }
                    }
                };

                var result = await store.Maintenance.SendAsync(new ConfigureRevisionsOperation(configuration));



                // insert sample data
                using (var bulk = store.BulkInsert())
                {
                    for (var i = 0; i < 20; i++)
                    {
                        bulk.Store(new Company
                        {
                            Id   = "company/" + i,
                            Name = Convert.ToBase64String(Sodium.GenerateRandomBuffer(128 * 8))
                        });
                    }
                }

                // get detailed collection statistics before we are going to change some data
                // right now there shouldn't be any revisions
                var detailedCollectionStats_beforeDataChanged = await store.Maintenance.SendAsync(new GetDetailedCollectionStatisticsOperation());

                Assert.Equal(strCollectionName, detailedCollectionStats_beforeDataChanged.Collections[strCollectionName].Name);
                long sizeInBytesWithoutRevisions = detailedCollectionStats_beforeDataChanged.Collections[strCollectionName].Size.SizeInBytes;
                Assert.True(sizeInBytesWithoutRevisions > 0);

                // change some data
                for (int i = 0; i < 200; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        var company = await session.LoadAsync <Company>("company/1");

                        company.Name = Convert.ToBase64String(Sodium.GenerateRandomBuffer(128 * 8));
                        await session.StoreAsync(company);

                        await session.SaveChangesAsync();
                    }
                }

                // get the revisions for the changed document
                using (var session = store.OpenAsyncSession())
                {
                    var revisions = await session.Advanced.Revisions.GetForAsync <Company>("company/1", 0, 200);

                    Assert.Equal(200, revisions.Count);
                }

                // query the detailed collection statistics again, to check if the physical size changed after the revisions were created
                var detailedCollectionStats_afterDataChanged = await store.Maintenance.SendAsync(new GetDetailedCollectionStatisticsOperation());

                Assert.Equal(20, detailedCollectionStats_afterDataChanged.Collections[strCollectionName].CountOfDocuments);
                long sizeInBytesWithRevisions = detailedCollectionStats_afterDataChanged.Collections[strCollectionName].Size.SizeInBytes;
                Assert.True(sizeInBytesWithRevisions > sizeInBytesWithoutRevisions);
            }
        }
예제 #12
0
 protected override void Configure(StorageEnvironmentOptions options)
 {
     options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes());
     options.MaxScratchBufferSize = 65536 - 1; // to make ShouldReduceSizeOfCompressionPager() return true
     options.Encryption.RegisterForJournalCompressionHandler();
 }