LiteDB icon indicating copy to clipboard operation
LiteDB copied to clipboard

[BUG]

Open q-bertsuit opened this issue 1 year ago • 1 comments

LiteDB version 5.0.21 Microsoft Windows Embedded Standard 6.1.7601.NULL, 64 bit.

We've developed an application in .Net Core 6 that works fine on most machines, but I got a report that it fails with this exception on certain machines:

Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Unknown error (0xc1000001)
at Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(String hashAlgorithmId, BCryptOpenAlgorithmProviderFlags flags, Int32& hashSizeInBytes)
at Internal.Cryptography.HashProviderCng..ctor(String hashAlgId, ReadOnlySpan`1 key, Boolean isHmac)
at System.Security.Cryptography.SHA1.Implementation..ctor()
at LiteDB.StringExtensions.Sha1(String value)
at LiteDB.SharedEngine..ctor(EngineSettings settings)
at LiteDB.ConnectionString.CreateEngine(Action`1 engineSettingsAction)
at LiteDB.LiteDatabase..ctor(ConnectionString connectionString, BsonMapper mapper)
at LiteDB.LiteDatabase..ctor(String connectionString, BsonMapper mapper)

I'm starting LiteDb in shared mode, and as the exception shows, something goes wrong when creating the name for the mutex. Any idea what could be causing this?

The error only happens once in a while, and if the app is restarted it typically works fine again

q-bertsuit avatar Sep 13 '24 06:09 q-bertsuit

Looks like your issue arises from the following code:

var name = Path.GetFullPath(settings.Filename).ToLower().Sha1();
public static string Sha1(this string value)
{
    var data = Encoding.UTF8.GetBytes(value);

    using (var sha = SHA1.Create())
    {
        var hashData = sha.ComputeHash(data);
        var hash = new StringBuilder();

        foreach (var b in hashData)
        {
            hash.Append(b.ToString("X2"));
        }

        return hash.ToString();
    }
}

The .Sha1() seems to be necessary because if you remove it, it tries to create a mutex with an invalid name like Global\c:\users\user\documents\github\litedb\litedb.tests\bin\debug\net8\demo.db.Mutex, so to avoid this it hashes the database filepath with SHA1.

To me that seems like a sketchy workaround, especially when SHA1 has known collisions.

I would avoid hashing entirely by using URL encoding, which I've tested correctly encodes all invalid file path characters:

string name = Uri.EscapeDataString(Path.GetFullPath(settings.Filename).ToLowerInvariant());

Joy-less avatar Oct 22 '24 15:10 Joy-less