Passwd -a sha256|sha512 less secure than default

@jeff, @jow,

The behavior you describe in the original post is not correct anymore. The current version 19.07 rc2, with busybox 1.31.1 (as of December 2019), has a crypt() function that behaves as expected for a *nix system:
http://man7.org/linux/man-pages/man3/crypt.3.html
After disabling the hack and setting the default password algorithm to SHA256, the shadow file shows passwords correctly hashed and formatted. Luci, though, seems to have trouble checking passwords stored with the stronger hashing algorithms.

There is a significant increase in the security of password storage from MD5 to SHA256, and even more to SHA512. The latter is the current default in many systems today.

Given the current guidance for users to stop using routers with 4MB of flash memory, most, if not all routers should be able to handle either of the SHA algorithms, and it is really poor practice to keep an old and outdated hashing algorithm alive.

I created a separate post in the developer area, but we need to clear inaccurate information so that users don't get the wrong idea about password security.

This works as expected today and should be enabled by default. The SHA hack should be removed from the code, or at the very least, disabled by default.

2 Likes

I can confirm, works fine.

1 Like

On further inspection, the Luci issue is also shared by Dropbear, which leaves users unable to log in via SSH. However, the issue is not with either package above. The problem is due to uClibc not implementing SHA256/512, which both Luci and Dropbear depend on in order to verify logins.

Rebuilding the system with libc++ instead solved the issue, and surprisingly for me, did not increase the firmware size. My test was on a minimal system.

Thanks @shm0 for confirming this works in other routers.

I’m assuming you meant musl, as that is the standard C library used by OpenWrt at this time. So then it seems nothing of consequence has changed, correct?

I don't have the exact timeline, but I think that at some point busybox didn't have SHA implementations for password hashing. When they tried to implement them, they realized that their C library (uClibc) didn't have them either, so they built their own and forced their login routines to use the internal implementations. That works for logging in to busybox in a local terminal, but breaks SSH or any other remote login (i.e. Luci, in our case).

In the meantime, someone tried to implement the stronger passwords in OpenWrt, but realized that they did not work. They put in a patch that failed silently and downgraded security to DES, instead of MD5. I think that's the time when your first post in this thread was created. Later on, though, after some complaints, the patch was updated to fail, without downgrade. This the current state and a more graceful failure.

What I discovered now is that, if one disables the SHA patch and rebuilds busybox with libc++, everything works. Since I had a minimal system, with a bunch of disabled stuff, even in busybox, the final binaries are not bigger than the uClibc. I can't say that this will be the case for a fully blown system, where libc++ implementations might make a big difference in size.

So, to answer your question, I think something did change since the first post, and it is the default behavior now. The other change is that we now have evidence that it is possible to implement stronger password security, but may involve serious changes for a system with default configuration. It doesn't seem to be the case for a minimalistic system.

The commit history of that "SHA patch" shows three commits with messages explaining the changes. The first ones date to 2015, long before this thread, and the latest one to this year. So, something has indeed changed...
https://git.openwrt.org/?p=openwrt/openwrt.git;a=history;f=toolchain/musl/patches/901-crypt_size_hack.patch;h=75f196abca5f44c3d17400d83f9eef30057bdff7;hb=HEAD

After the last change (in Jan 2019), there is also a menuconfig config option in master (and 19.07) to enable the SHA256 and SHA512 support with the standard musl libc.

https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=ceb625439a84c7ea4ab1e39f126b6baffc48d1cd;hp=1211832977b98c491d1198ab66c4f8ffc0886a87

So, I am not sure if one needs currently to do anything else than just toggle the config option for musl, select the desired hash option for busybox and re-compile everything. (Note that musl is in the toolchain, so make sure to recompile also it.) Using the correctly configured musl should also reflect to dropbox etc., I think.

Ps.

Master branch has busybox 1.31.1, but unlike you say, 19.07 has busybox 1.30.1.

Pps.
uClibc has not been used for several years.

2 Likes

Thanks for clarifying the timeline. And the master vs rc2 bit too. I never installed rc2, I've always started by cloning the master branch, [re]configuring and then [re]building. Shouldn't have assumed that master and rc2 were the same.

I am confused, though, about uClibc not being used for years. When I first run make menuconfig right after downloading the source, uClibc appears as the default C library. It was only until after I changed that to libc++ and rebuilt the toolchain that my OpenWrt started working as expected with SHA256. Is this just an out of sync config option in the master branch?

PS. Yes, the rebuilt toolchain fixed all my problems at once, Luci and Dropbear didn't have any issues handling stronger hashes.

The default C library was switched from uclibc to musl in 2015:
https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=a7780603923fddec225c9f4b0990fede4c2695a9;hp=aaf4aea141a6c0b33d6f4261e90151a51ef02a78

Currently the available choices for the main C library are musl and glibc.

 .config - OpenWrt Configuration
 > Advanced configuration options (for developers) > Toolchain Options ────────
...
  │ │          *** C Library ***                                          │ │  
  │ │          C Library implementation (Use musl)  --->                  │ │  
  │ │    [ ]   Include crypt() support for SHA256, SHA512 and Blowfish cip│ │  

You are probably mixing C++ libraries (like libc++) to the main C library in your analysis. The C++ libraries have a minor role in things. (And there the uClibc++ is still is use).

2 Likes

Thank you.

Yes, I must have not done a proper clean up between builds and then drew the wrong conclusions. This makes sense to me.

I'll start from scratch and only make the changes you suggest to confirm that's the proper way to enable stronger password hashing.

Thanks for your patience, this is very helpful :+1:

1 Like

I would think that this should be a 'default' I didn't know I had to go to the 'advanced' to enable the checksums. Thanks for the heads up though. Honestly, from a security perspective, if you they have your password file (physical access) its game over anyways.

Luci was broken with the 'defconfig' for x86_64. Hopefully someone will catch this and 'fix' in the next revision. Maybe sha256 should be a WORKING default?

I can confirm that sha256 indeed works if you choose 'advanced config' and 'enable crypt' as mentioned. I do think it should be a 'default' since the non-modifed config results in a brain-dead luci. Oh well.

From that discourse

All password hash algorithms except for MD5 (default) and DES (for
compatibility reasons) have been stripped from libc to cut down on
useless bloat.

If you care about password storage security, it's better to use a
function that was intentionally designed NOT to be fast, e.g. PBKDF2 or
bcrypt.

It does not make sense however to refer to bcrypt and then even compile it into the shadow package https://github.com/openwrt/packages/blob/master/utils/shadow/Makefile#L44 when at same time crypt_blowfish being stripped in the toolchain (in the same patch as SHA256|512).


Further from that discourse

I think switching from MD5 to SHA256/SHA512 is rather pointless.
It slows down password cracking by a small factor, but not by real
orders of magnitude,

That seems rather debatable as MD5 comes with fixed 64 rounds whilst SHA256|512 rounds are adjustable and even with the default of 5,000 rounds provides reasonable resistance. Increasing it to 15 <> 20 k makes it even difficult for quantum computing power.


Which leaves

been stripped from libc to cut down on useless bloat.

How much bloat?

14KB after LZMA on MIPS.

1 Like

Thank you for the input. Though it seems small probably every byte counts in the scheme of things.

Reconsider though

Either crypt_blowfish should be reinstated or bcrypt not compiled into shadow or else this setup makes no sense.

I have a PR in the works that switches shadow-utils to use libxcrypt and not the one in the libc.

1 Like

That would be splendid if accepted into the distro.

Currently waiting on https://github.com/openwrt/packages/pull/12530 to get accepted.

1 Like

Thank you @neheb for your contribution https://github.com/openwrt/packages/pull/12577/commits which has returned bcrypt | sha256 | 512 with shadow.

Just tested with brcypt (mind if using PAM to change the algo there too) and works fine.

Suppose that resolves/thread (least once OpenWrt 20.x) arrives.

Note that authentication against such hashes will fail for rpcd (LuCI) and uhttpd basic auth (if using the $p$user notation) since those still use libc's crypt() function. Not sure about Dropbear / OpenSSH etc.