public Page(byte *b, string source, ushort pageSize) { _base = b; _header = (PageHeader *)b; Source = source; _pageSize = pageSize; }
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); }
public Page(byte* b, string source, ushort pageSize) { _base = b; _header = (PageHeader*)b; Source = source; _pageSize = pageSize; }
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}"); } } }
public Page(byte* b, string source, ushort pageSize) { _base = b; _header = (PageHeader*)b; Source = source; _pageSize = pageSize; _prefixSection = (PrefixInfoSection*) (_base + _pageSize - Constants.PrefixInfoSectionSize); }
public Page(byte *b, string source, ushort pageSize) { _base = b; _header = (PageHeader *)b; Source = source; _pageSize = pageSize; _prefixSection = (PrefixInfoSection *)(_base + _pageSize - Constants.PrefixInfoSectionSize); }
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))); }
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); } }
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}"); } } }
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); }
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}"); } } }
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); }
public Page(byte *b, string source) { _base = b; _header = (PageHeader *)b; Source = source; }
public Page(byte* b, int pageMaxSpace) { _base = b; _pageMaxSpace = pageMaxSpace; _header = (PageHeader*)b; }
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}"); }
public Page(byte* b, string source) { _base = b; _header = (PageHeader*)b; Source = source; }