public void TestStreamReadWrite() { var rnd = new Random(); for (var c = 0; c < count; c++) { var memSize = rnd.Next(1, 10_000); var mem = new byte[(memSize + 4) * writeRepeatCount]; var answer = new byte[memSize * writeRepeatCount]; rnd.NextBytes(answer); for (var bc = 1; bc < writeRepeatCount; bc++) { for (var offset = 0; offset < bc; offset++) { var span1 = new SpanStream(mem); var span2 = new SpanStream(mem); span1.Write(answer, offset, bc - offset); var buffer = new byte[bc + offset]; span2.Read(buffer, offset, bc - offset); Assert.Equal(new Span <byte>(answer).Slice(offset, bc - offset).ToArray(), new Span <byte>(buffer).Slice(offset, bc - offset).ToArray()); } } Assert.Throws <ArgumentNullException>(() => { var s = new SpanStream(mem); s.Read(null, 0, 1); }); } }
internal static DatabaseInfo ParseHeader(SpanStream io, byte[] compositeKey) { var header = io.Read <Header>(); if (header.Signature1 != Magic1) { throw MakeInvalidFormatError($"primary file signature is invalid: {header.Signature1:x8}"); } if (!Magic2.Contains(header.Signature2)) { throw MakeInvalidFormatError($"secondary file signature is invalid: {header.Signature2:x8}"); } if (header.MajorVersion != Version4) { throw MakeUnsupportedError($"Version {header.MajorVersion}.{header.MinorVersion}"); } var info = ReadEncryptionInfo(ref io); var headerSize = io.Position; io.Rewind(); var headerBytes = io.ReadBytes(headerSize); var computedHash = Crypto.Sha256(headerBytes); var storedHash = io.ReadBytes(32); if (!Crypto.AreEqual(storedHash, computedHash)) { throw MakeInvalidFormatError("Header hash doesn't match"); } var storedHeaderMac = io.ReadBytes(32); var derivedKey = DeriveMasterKey(compositeKey, info.Kdf); var(encryptionKey, hmacKey) = Util.DeriveDatabaseKeys(derivedKey, info.Seed); var blockHmacKey = Util.ComputeBlockHmacKey(hmacKey, ulong.MaxValue); var computedHeaderMac = Crypto.HmacSha256(blockHmacKey, headerBytes); if (!Crypto.AreEqual(storedHeaderMac, computedHeaderMac)) { throw MakeInvalidFormatError("Header MAC doesn't match"); } return(new DatabaseInfo(headerSize: io.Position, isCompressed: info.IsCompressed, cipher: info.Cipher, encryptionKey: encryptionKey, iv: info.Iv, hmacKey: hmacKey)); }