示例#1
0
        public override byte *AcquirePagePointer(IPagerLevelTransactionState tx, long pageNumber, PagerState pagerState = null)
        {
            var state = GetTransactionState(tx);

            if (state.LoadedBuffers.TryGetValue(pageNumber, out var buffer))
            {
                return(buffer.Pointer);
            }

            var pagePointer = Inner.AcquirePagePointerWithOverflowHandling(tx, pageNumber, pagerState);

            var pageHeader = (PageHeader *)pagePointer;

            var size = VirtualPagerLegacyExtensions.GetNumberOfPages(pageHeader) * Constants.Storage.PageSize;

            buffer = GetBufferAndAddToTxState(pageNumber, state, size);

            Memory.Copy(buffer.Pointer, pagePointer, buffer.Size);

            DecryptPage((PageHeader *)buffer.Pointer);

            if (Sodium.crypto_generichash(buffer.Hash, EncryptionBuffer.HashSize, buffer.Pointer, (ulong)buffer.Size, null, UIntPtr.Zero) != 0)
            {
                ThrowInvalidHash();
            }

            return(buffer.Pointer);
        }
示例#2
0
        private int EncryptPage(PageHeader *page)
        {
            var num         = page->PageNumber;
            var destination = (byte *)page;
            var subKeyLen   = Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes();
            var subKey      = stackalloc byte[(int)subKeyLen];

            fixed(byte *ctx = Context)
            fixed(byte *mk = _masterKey)
            {
                if (Sodium.crypto_kdf_derive_from_key(subKey, subKeyLen, (ulong)num, ctx, mk) != 0)
                {
                    throw new InvalidOperationException("Unable to generate derived key");
                }

                var dataSize = VirtualPagerLegacyExtensions.GetNumberOfPages(page) * Constants.Storage.PageSize;

                var npub = (byte *)page + PageHeader.NonceOffset;

                // here we generate 128(!) bits of random data, but xchacha20poly1305 needs
                // 192 bits, we go to backward from the radnom nonce to  get more bits that
                // are not really random for the algorithm.
                Sodium.randombytes_buf(npub, (UIntPtr)(PageHeader.MacOffset - PageHeader.NonceOffset));

                ulong macLen = MacLen;
                var   rc     = Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
                    destination + PageHeader.SizeOf,
                    destination + PageHeader.MacOffset,
                    &macLen,
                    (byte *)page + PageHeader.SizeOf,
                    (ulong)dataSize - PageHeader.SizeOf,
                    (byte *)page,
                    (ulong)PageHeader.NonceOffset,
                    null,
                    // got back a bit to allow for 192 bits nonce, even if the first
                    // 8 bytes aren't really random, the last 128 bits are securely
                    // radnom
                    (byte *)page + PageHeader.NonceOffset - sizeof(long),
                    subKey
                    );

                Debug.Assert(macLen == MacLen);

                if (rc != 0)
                {
                    throw new InvalidOperationException($"Unable to encrypt page {num}, rc={rc}");
                }

                return(dataSize);
            }
        }
示例#3
0
        private void TxOnCommit(IPagerLevelTransactionState tx)
        {
            if (tx.IsWriteTransaction == false)
            {
                return;
            }

            if (tx.CryptoPagerTransactionState == null)
            {
                return;
            }

            if (tx.CryptoPagerTransactionState.TryGetValue(this, out var state) == false)
            {
                return;
            }

            var pageHash = stackalloc byte[EncryptionBuffer.HashSizeInt];

            foreach (var buffer in state.LoadedBuffers)
            {
                if (buffer.Value.SkipOnTxCommit)
                {
                    continue;
                }

                if (Sodium.crypto_generichash(pageHash, EncryptionBuffer.HashSize, buffer.Value.Pointer, (ulong)buffer.Value.Size, null, UIntPtr.Zero) != 0)
                {
                    ThrowInvalidHash();
                }

                if (Sodium.sodium_memcmp(pageHash, buffer.Value.Hash, EncryptionBuffer.HashSize) == 0)
                {
                    continue; // No modification
                }
                // Encrypt the local buffer, then copy the encrypted value to the pager
                var pageHeader = (PageHeader *)buffer.Value.Pointer;
                var dataSize   = EncryptPage(pageHeader);
                var numPages   = VirtualPagerLegacyExtensions.GetNumberOfOverflowPages(dataSize);

                Inner.EnsureContinuous(buffer.Key, numPages);
                Inner.EnsureMapped(tx, buffer.Key, numPages);

                var pagePointer = Inner.AcquirePagePointer(tx, buffer.Key);

                Memory.Copy(pagePointer, buffer.Value.Pointer, dataSize);
            }
        }
示例#4
0
        protected int CopyPageImpl(I4KbBatchWrites destwI4KbBatchWrites, long p, PagerState pagerState)
        {
            var src           = AcquirePagePointer(null, p, pagerState);
            var pageHeader    = (PageHeader *)src;
            int numberOfPages = 1;

            if ((pageHeader->Flags & PageFlags.Overflow) == PageFlags.Overflow)
            {
                numberOfPages = VirtualPagerLegacyExtensions.GetNumberOfOverflowPages(pageHeader->OverflowSize);
            }
            const int adjustPageSize = (Constants.Storage.PageSize) / (4 * Constants.Size.Kilobyte);

            destwI4KbBatchWrites.Write(pageHeader->PageNumber * (long)adjustPageSize, numberOfPages * adjustPageSize, src);

            return(numberOfPages);
        }
示例#5
0
        private void DecryptPage(PageHeader *page)
        {
            var num = page->PageNumber;

            var destination = (byte *)page;
            var subKeyLen   = Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes();
            var subKey      = stackalloc byte[(int)subKeyLen];

            fixed(byte *ctx = Context)
            fixed(byte *mk = _masterKey)
            {
                if (Sodium.crypto_kdf_derive_from_key(subKey, subKeyLen, (ulong)num, ctx, mk) != 0)
                {
                    throw new InvalidOperationException("Unable to generate derived key");
                }

                var dataSize = (ulong)VirtualPagerLegacyExtensions.GetNumberOfPages(page) * Constants.Storage.PageSize;
                var rc       = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt_detached(
                    destination + PageHeader.SizeOf,
                    null,
                    (byte *)page + PageHeader.SizeOf,
                    dataSize - PageHeader.SizeOf,
                    (byte *)page + PageHeader.MacOffset,
                    (byte *)page,
                    (ulong)PageHeader.NonceOffset,
                    // we need to go 8 bytes before the nonce to get where
                    // the full nonce (fixed 8 bytes + random 16 bytes).
                    (byte *)page + PageHeader.NonceOffset - sizeof(long),
                    subKey
                    );

                if (rc != 0)
                {
                    throw new InvalidOperationException($"Unable to decrypt page {num}, rc={rc}");
                }
            }
        }
示例#6
0
        public override int CopyPage(I4KbBatchWrites destI4KbBatchWrites, long pageNumber, PagerState pagerState)
        {
            var distanceFromStart       = (pageNumber % NumberOfPagesInAllocationGranularity);
            var allocationStartPosition = pageNumber - distanceFromStart;

            var offset = new WindowsMemoryMapPager.SplitValue {
                Value = (ulong)allocationStartPosition * (ulong)Constants.Storage.PageSize
            };
            var result = MapViewOfFileEx(_hFileMappingObject, _mmFileAccessType, offset.High,
                                         offset.Low,
                                         (UIntPtr)AllocationGranularity, null);

            try
            {
                if (result == null)
                {
                    var lastWin32Error = Marshal.GetLastWin32Error();
                    throw new Win32Exception($"Unable to map (default view size) {AllocationGranularity / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}",
                                             new Win32Exception(lastWin32Error));
                }

                var pageHeader = (PageHeader *)(result + distanceFromStart * Constants.Storage.PageSize);

                int numberOfPages = 1;
                if ((pageHeader->Flags & PageFlags.Overflow) == PageFlags.Overflow)
                {
                    numberOfPages = VirtualPagerLegacyExtensions.GetNumberOfOverflowPages(pageHeader->OverflowSize);
                }

                if (numberOfPages + distanceFromStart > NumberOfPagesInAllocationGranularity)
                {
                    UnmapViewOfFile(result);
                    result = null;

                    var newSize = NearestSizeToAllocationGranularity((numberOfPages + distanceFromStart) * Constants.Storage.PageSize);
                    result = MapViewOfFileEx(_hFileMappingObject, _mmFileAccessType, offset.High,
                                             offset.Low,
                                             (UIntPtr)newSize, null);

                    if (result == null)
                    {
                        var lastWin32Error = Marshal.GetLastWin32Error();
                        throw new Win32Exception($"Unable to map {newSize / Constants.Size.Kilobyte:#,#0} kb for page {pageNumber} starting at {allocationStartPosition} on {FileName}",
                                                 new Win32Exception(lastWin32Error));
                    }

                    pageHeader = (PageHeader *)(result + (distanceFromStart * Constants.Storage.PageSize));
                }
                const int adjustPageSize = (Constants.Storage.PageSize) / (4 * Constants.Size.Kilobyte);

                destI4KbBatchWrites.Write(pageHeader->PageNumber * adjustPageSize, numberOfPages * adjustPageSize, (byte *)pageHeader);

                return(numberOfPages);
            }
            finally
            {
                if (result != null)
                {
                    UnmapViewOfFile(result);
                }
            }
        }