Esempio n. 1
0
 public Page(byte *b, string source, ushort pageSize)
 {
     _base     = b;
     _header   = (PageHeader *)b;
     Source    = source;
     _pageSize = pageSize;
 }
Esempio n. 2
0
        private unsafe void UnlikelyValidatePage(long pageNumber, PageHeader *current, long index, long old, long bitToSet)
        {
            var spinner = new SpinWait();

            while (true)
            {
                long modified = Interlocked.CompareExchange(ref _validPages[index], old | bitToSet, old);
                if (modified == old || (modified & bitToSet) != 0)
                {
                    break;
                }

                old = modified;
                spinner.SpinOnce();
            }

            // No need to call EnsureMapped here. ValidatePageChecksum is only called for pages in the datafile,
            // which we already got using AcquirePagePointerWithOverflowHandling()

            ulong checksum = CalculatePageChecksum((byte *)current, current->PageNumber, current->Flags, current->OverflowSize);

            if (checksum == current->Checksum)
            {
                return;
            }

            ThrowInvalidChecksum(pageNumber, current, checksum);
        }
Esempio n. 3
0
        public Page(byte* b, string source, ushort pageSize)
        {
            _base = b;
            _header = (PageHeader*)b;
	        Source = source;
	        _pageSize = pageSize;
        }
Esempio n. 4
0
        private void DecryptPage(PageHeader *page)
        {
            var num = page->PageNumber;

            var destination = (byte *)page;
            var subKey      = stackalloc byte[32];

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

                var dataSize = (ulong)GetNumberOfPages(page) * Constants.Storage.PageSize;
                var rc       = Sodium.crypto_aead_chacha20poly1305_decrypt_detached(
                    destination + PageHeader.SizeOf,
                    null,
                    (byte *)page + PageHeader.SizeOf,
                    dataSize - PageHeader.SizeOf,
                    (byte *)page + PageHeader.MacOffset,
                    (byte *)page,
                    (ulong)PageHeader.NonceOffset,
                    (byte *)page + PageHeader.NonceOffset,
                    subKey
                    );

                if (rc != 0)
                {
                    throw new InvalidOperationException($"Unable to decrypt page {num}, rc={rc}");
                }
            }
        }
Esempio n. 5
0
 public Page(byte* b, string source, ushort pageSize)
 {
     _base = b;
     _header = (PageHeader*)b;
     Source = source;
     _pageSize = pageSize;
     _prefixSection = (PrefixInfoSection*) (_base + _pageSize - Constants.PrefixInfoSectionSize);
 }
Esempio n. 6
0
 public Page(byte *b, string source, ushort pageSize)
 {
     _base          = b;
     _header        = (PageHeader *)b;
     Source         = source;
     _pageSize      = pageSize;
     _prefixSection = (PrefixInfoSection *)(_base + _pageSize - Constants.PrefixInfoSectionSize);
 }
Esempio n. 7
0
        private static int GetNumberOfPages(PageHeader *header)
        {
            if ((header->Flags & PageFlags.Overflow) != PageFlags.Overflow)
            {
                return(1);
            }

            var overflowSize = header->OverflowSize + Constants.Tree.PageHeaderSize;

            return(checked ((overflowSize / Constants.Storage.PageSize) + (overflowSize % Constants.Storage.PageSize == 0 ? 0 : 1)));
        }
Esempio n. 8
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 = 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);
            }
        }
Esempio n. 9
0
        private void EncryptPage(PageHeader *page)
        {
            var num         = page->PageNumber;
            var destination = (byte *)page;
            var subKey      = stackalloc byte[32];

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

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

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

                if (*(long *)npub == 0)
                {
                    Sodium.randombytes_buf(npub, (UIntPtr)sizeof(long));
                }
                else
                {
                    *(long *)npub = *(long *)npub + 1;
                }

                ulong macLen = MacLen;
                var   rc     = Sodium.crypto_aead_chacha20poly1305_encrypt_detached(
                    destination + PageHeader.SizeOf,
                    destination + PageHeader.MacOffset,
                    &macLen,
                    (byte *)page + PageHeader.SizeOf,
                    dataSize - PageHeader.SizeOf,
                    (byte *)page,
                    (ulong)PageHeader.NonceOffset,
                    null,
                    npub,
                    subKey
                    );

                Debug.Assert(macLen == MacLen);

                if (rc != 0)
                {
                    throw new InvalidOperationException($"Unable to encrypt page {num}, rc={rc}");
                }
            }
        }
Esempio n. 10
0
        public unsafe void ValidatePageChecksum(long pageNumber, PageHeader *current)
        {
            long old;
            var  index    = pageNumber / (8 * sizeof(long));
            var  bitIndex = (int)(pageNumber % (8 * sizeof(long)));
            var  bitToSet = 1L << bitIndex;

            // If the page is beyond the initial size of the file we don't validate it.
            // We assume that it is valid since we wrote it in this run.
            if (index >= _validPages.Length)
            {
                return;
            }

            old = _validPages[index];
            if ((old & bitToSet) != 0)
            {
                return;
            }

            UnlikelyValidatePage(pageNumber, current, index, old, bitToSet);
        }
Esempio n. 11
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)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}");
                }
            }
        }
Esempio n. 12
0
        private void ThrowInvalidChecksumOnPageFromJournal(long pageNumber, TransactionHeader *current, ulong expectedChecksum, ulong checksum, PageHeader *pageHeader)
        {
            var message =
                $"Invalid checksum for page {pageNumber} in transaction {current->TransactionId}, journal file {_journalPager} might be corrupted, expected hash to be {expectedChecksum} but was {checksum}." +
                $"Data from journal has not been applied to data file {_dataPager} yet. ";

            message += $"Page flags: {pageHeader->Flags}. ";

            if ((pageHeader->Flags & PageFlags.Overflow) == PageFlags.Overflow)
            {
                message += $"Overflow size: {pageHeader->OverflowSize}. ";
            }


            throw new InvalidDataException(message);
        }
Esempio n. 13
0
 public Page(byte *b, string source)
 {
     _base   = b;
     _header = (PageHeader *)b;
     Source  = source;
 }
Esempio n. 14
0
 public Page(byte* b, int pageMaxSpace)
 {
     _base = b;
     _pageMaxSpace = pageMaxSpace;
     _header = (PageHeader*)b;
 }
Esempio n. 15
0
 private unsafe void ThrowInvalidChecksum(long pageNumber, PageHeader *current, ulong checksum)
 {
     throw new InvalidDataException(
               $"Invalid checksum for page {pageNumber}, data file {_options.DataPager} might be corrupted, expected hash to be {current->Checksum} but was {checksum}");
 }
Esempio n. 16
0
        public Page(byte* b, string source)
        {
            _base = b;
            _header = (PageHeader*)b;
	        Source = source;
        }