Skip to content

Commit

Permalink
fix Invalid Password exception caused due to corruption of hidden pag…
Browse files Browse the repository at this point in the history
…e in encrypted files.
  • Loading branch information
Anurakt Ghosh committed Jul 18, 2023
1 parent 84faf67 commit 5afa254
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 4 deletions.
83 changes: 82 additions & 1 deletion LiteDB.Tests/Internals/Aes_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using FluentAssertions;
using LiteDB.Engine;
using Xunit;
Expand Down Expand Up @@ -61,5 +64,83 @@ public void Encrypt_Decrypt_Stream()
output2.All(x => x == 102).Should().BeTrue();
}
}

/// <summary>
/// Test whether AesStream can handle stream that has invalid page size.
/// </summary>
[Fact]
public void AesStream_Invalid_Page_Size()
{
var fakeContent = new byte[] {
1,22,222,184,3,227,126,129,205,182,182,143,201,181,242,107,36,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
20,88,18,70,65,77,202,50,184,177,167,59,80,255,67,66,20,
88,18,70,65,77,202,50,184,177,167,59,80,255,67,66
};

// stream of 64bytes (invalid page size)
using (var memoryStream = new MemoryStream())
{
memoryStream.Write(fakeContent, 0, fakeContent.Length);
memoryStream.Position = 0;

using (var crypto = new AesStream("password", memoryStream))
{
// 1st page is hidden, so AesStream.Length returns (stream.Length - PAGE_SIZE)
Assert.Equal(0, crypto.Length);

// AesStream should add padding to the underlying stream to make its size equivalent to PAGE_SIZE
Assert.Equal(8192, memoryStream.Length);
}
}
}

/// <summary>
/// Test whether AesStream can handle stream where bytes 32-64 are empty.
/// </summary>
[Fact]
public void AesStream_Invalid_Password()
{
// stream of 8192 bytes where bytes 32 to 64 is empty.
using (var memoryStream = new MemoryStream())
{
// 1st byte to indicate the stream is encrypted
memoryStream.WriteByte(1);

// next 16 bytes contain salt
var salt = new byte[16];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
memoryStream.Write(salt, 0, salt.Length);

// remaining (8192 - 17) bytes are empty
var emptyContent = new byte[8175];
memoryStream.Write(emptyContent, 0, emptyContent.Length);

// reset the stream position to 0
memoryStream.Position = 0;

using (var crypto = new AesStream("password", memoryStream))
{
// 1st page is hidden, so AesStream.Length returns (stream.Length - PAGE_SIZE)
Assert.Equal(0, crypto.Length);

// AesStream should add padding to the underlying stream to make its size equivalent to PAGE_SIZE
Assert.Equal(8192, memoryStream.Length);

// AesStream should fill bytes 32-64 with encrypted 1s
var checkBytes = new byte[32];
var cryptoReader = typeof(AesStream)
.GetField("_reader", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(crypto) as CryptoStream;

memoryStream.Position = 32;
cryptoReader.Read(checkBytes, 0, checkBytes.Length);
Assert.All(checkBytes, b => Assert.Equal(1, b));
}
}
}
}
}
14 changes: 11 additions & 3 deletions LiteDB/Engine/Disk/Streams/AesStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ public AesStream(string password, Stream stream)
// first byte =1 means this datafile is encrypted
_stream.WriteByte(1);
_stream.Write(this.Salt, 0, ENCRYPTION_SALT_SIZE);

// fill with 0 full PAGE_SIZE
_stream.Write(_emptyContent, 0, _emptyContent.Length);
}
else
{
Expand Down Expand Up @@ -109,6 +106,17 @@ public AesStream(string password, Stream stream)

var checkBuffer = new byte[32];

if (!isNew)
{
// check whether bytes 32 to 64 is empty. This indicates LiteDb was unable to write encrypted 1s during last attempt.
_stream.Read(checkBuffer, 0, checkBuffer.Length);
isNew = checkBuffer.All(x => x == 0);

// reset checkBuffer and stream position
Array.Clear(checkBuffer, 0, checkBuffer.Length);
_stream.Position = 32;
}

// fill checkBuffer with encrypted 1 to check when open
if (isNew)
{
Expand Down

0 comments on commit 5afa254

Please # to comment.