2

I'm porting an app from Node to ASP.NET Core, and discovered that the .NET Core framework doesn't have a bcrypt implementation. There are community supported bcrypt implementations but they are very old or have not undergone review, like those written by Microsoft - so I'd prefer a "worse" algorithm that has MS' backing.

The System.Security.Cryptography namespace has lots of algorithms to choose from.

bcrypt is the preferred password hashing algorithm in the Node ecosystem - it also has various features like the "slowness" and workfactor and handy salting routines. I hope I don't have to give up too much when choosing something else.

I'm not a hashing expert - which is the best alternative password hashing algorithm from that link? (Which will get me as close as possible to what I'm used to with bcrypt.)

lonix
  • 363
  • 3
  • 11
  • 2
    [Microsoft.AspNetCore.Cryptography.KeyDerivation.Pbkdf2](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2?view=aspnetcore-2.2) – Xander Apr 26 '19 at 17:52
  • @Xander PBKDF2... Does it do that workfactor "slowdown" like bcrypt does? – lonix Apr 26 '19 at 17:53
  • Yes, it does. That's the iterationCount parameter. – Xander Apr 26 '19 at 17:54
  • 1
    @Xander Thanks! Now I need to write code for converting the old membership database to the new... fun times. :) – lonix Apr 26 '19 at 17:55

2 Answers2

6

The preffered algorithm from that namespace seems to be PasswordDeriveBytes, though this is PBKDF1, which is nowhere as good as Bcrypt and probably should not be used.

PBKDF2 from a different namespace is probably preferable. Just note that the work factor there is linear, not exponential like in BCrypt and should be quite large.

I would consider using Argon2 from LibSodium with a C# wrapper. Libsodium is a reputable and well maintained library focused on ease of use.

Peter Harmann
  • 7,728
  • 5
  • 20
  • 28
  • Alternatively, just use the extremely active [bcrypt.net](https://github.com/BcryptNet/bcrypt.net) project. It's completely fine. – Stephen Touset Apr 26 '19 at 18:00
  • What MS calls "PasswordDerivedBytes" is [PBKDEF1](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.passwordderivebytes?view=netcore-2.2), should I not opt for what they call "Rfc2898DeriveBytes" which is [PBKDEF2](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=netcore-2.2)? – lonix Apr 26 '19 at 18:01
  • 1
    @lonix almost certainly yes. Honestly, the main point of my answer is use Libsodium if at all possible. Argon2 is much better then PBKDF and possibly even better than bCrypt. – Peter Harmann Apr 26 '19 at 18:02
  • 1
    You should not use PBKDF1. But you should also just use the argon2 implementation in libsodium or bcrypt.net. – Stephen Touset Apr 26 '19 at 18:02
  • @StephenTouset It seems like a good implementation, but there's only one guy behind it. Would you use it in production, i.e. would you recommend it? – lonix Apr 26 '19 at 18:03
  • I'm gonna check out those options, thanks guys! – lonix Apr 26 '19 at 18:03
  • 2
    @lonix well, it is a gamble using a smaller project like that. Just because it is active now does not mean it will be in a few years. Libsodium is so widely used in many programing languages, that it will likely remain supported for a very long time. – Peter Harmann Apr 26 '19 at 18:04
  • @PeterHarmann Yeah that's what I was thinking. I was initially tempted to use it out of laziness - but I want to use something that's maintained and has undergone code review. No insult to the library's author of course, just you don't take chances when it comes to this sort of thing. Guess I need to learn something new then... thanks! :) – lonix Apr 26 '19 at 18:07
  • I would personally use it. Being mostly one person isn't really a sign of anything. BCrypt the algorithm isn't ever going to change, so any maintenance work is just mostly just making sure it builds against and adds features for newer versions of the SDK. But Argon2 is preferable if possible. – Stephen Touset Apr 26 '19 at 18:21
  • @StephenTouset What I meant is that is hasn't undergone any review, so although the algo is solid, I don't know about the library. Then again it has ~300k downloads on nuget, so many devs are actively using it. I'll need to think closely about this... Thanks for your advice! – lonix Apr 26 '19 at 18:24
  • @StephenTouset Also all the .net argon libs I've found have similar problems (not maintained in years, etc.) including the libsodium mentioned above... so I'll need to do the best with what's available. Thanks again, appreciate it. – lonix Apr 26 '19 at 18:26
  • 1
    @lonix well the great thing about libsodium is that the core is alwas C and the unmaintained part is just the wrapper for C#, where there is not much chance to mess up. While there may be issues with it not being maintained, it is unlikely they will compromise security and libsodium as such has maintanance and extended usage. Not sure about review right now but I thought it had one. – Peter Harmann Apr 26 '19 at 19:32
  • A password hashing library is probably one of the few things in all of cryptography that's relatively resistant to implementation problems. I wouldn't recommend writing your own AES implementation or a TLS stack, but it's hard to imagine much in the way of damage that could be done by even the most naïve implementation of a password hash, as long as it's faithful to the underlying algorithm. – Stephen Touset Apr 28 '19 at 01:37
  • I have made a good wrapper on top of Microsoft implementation that you guys can check, please see my answer below – Ilya Chernomordik Jan 15 '20 at 08:48
3

What you can use in .NetCore is Rfc2898DeriveBytes that implements PBKDF2 but it is unfortunately a bit low level and hard to use.

I have made a library SimpleHashing.Net that makes use of Rfc2898DeriveBytes in .Net easier. The interface that resembles the one of bcrypt and as easy to use (it is possible to set the number of iterations as well). It's available on nuget.

P.S. I did not implement crypto, just wrapped the existing Microsoft implementation to be able to use it in an easy way, e.g.:

ISimpleHash simpleHash = new SimpleHash();

// Creating a user hash, hashedPassword can be stored in a database
// hashedPassword contains the number of iterations and salt inside it similar to bcrypt format
string hashedPassword = simpleHash.Compute("Password123");

// Validating user's password by first loading it from database by username
string storedHash = _repository.GetUserPasswordHash(username);
bool isPasswordValid = simpleHash.Verify("Password123", storedHash);
Ilya Chernomordik
  • 2,197
  • 1
  • 21
  • 36
  • It was stated above already that PasswordDerivedBytes is PBKDF1 which should not be used. I edited my answer to make it explicit – Peter Harmann Jan 15 '20 at 16:38
  • 1
    I made an error, it is Rfc2898DeriveBytes that I use, I'll fix the answer. I thought it's the same thing and forgot the name of the class, apparently it is not :) – Ilya Chernomordik Jan 15 '20 at 16:52