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"); }
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); } }
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)); }
protected override void Configure(StorageEnvironmentOptions options) { base.Configure(options); options.Encryption.MasterKey = Sodium.GenerateRandomBuffer((int)Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes()); options.ManualFlushing = true; }
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"); }
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'); } } } } }
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); } } } } }
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'); } } } } }
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)); } } } }
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"); }
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); } }
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(); }