[RFC,BZ,2100] blowfish support in libcrypt

Message ID 79469eab-c809-a5b8-3297-2536320a834d@gmail.com
State New, archived
Headers

Commit Message

Björn Esser May 31, 2017, 5:33 p.m. UTC
  From f781e7f3e151ed89edd357734dd457bd4cd39ec0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Wed, 31 May 2017 13:37:36 +0200
Subject: [PATCH] This is an implementation of a password hashing method,
  provided via the crypt(3) and a reentrant interface.  It is fully 
compatible
  with OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
  David Mazieres.

	[BZ #2100]
	* crypt/Makefile: Add new files and tests.
	* crypt/README.crypt_blowfish: New file.
	* crypt/Versions [GLIBC_2.26]: Add new symbols.
	* crypt/badsalttest.c: Add tests for crypt_r(a|n).  Print the return
	value of the tested hash, if not NULL.
	* crypt/blowfish-test.c: New test.
	* crypt/crypt-entry.c: Add support for bcrypt prefixes "$2a$", "$2b$",
	"$2x$", "$2y$".
	(crypt_gensalt): New function.  Compiles a string for use as setting
	with the given prefix, the iteration count, if supported by the chosen
         method, and up to size cryptographically random	input bytes for 
use as
	the actual salt.
	(crypt_gensalt_r): Likewise.  Reentrant version, behaves like
	crypt_gensalt_rn.
	(crypt_gensalt_ra): Likewise. Reentrant version, allocates memory for
	its result dynamically.
	(crypt_gensalt_rn): Likewise. Reentrant version, places its result in
	the output buffer of output_size bytes.
	(crypt_ra): Likewise.  Reentrant version of crypt, *data can be NULL.
	When called with a NULL *data or insufficient *size for the requested
	hashing	algorithm, it uses realloc to allocate the required amount of
	memory dynamically.
	(crypt_rn): Likewise.  Reentrant version of crypt, requires that the
	entire data area to be zeroed, where crypt_r requires that only
	data->initialized be reset to zero.
	* crypt/crypt.h: Add new functions introduced in <crypt/crypt-entry.c>.
	* crypt/crypt_blowfish.c: New file.
	* crypt/crypt_blowfish.h: Likewise.
	* crypt/crypt_gensalt.c: Likewise.
	* crypt/crypt_gensalt.h: Likewise.
	* crypt/des-crypt.c: New file split out from <crypt/crypt-entry.c>.
	* crypt/gensalt-test.c: New file.
	* sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist: New functions.
	* sysdeps/unix/sysv/linux/alpha/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist: Likewise.
---
  ChangeLog                                          |  64 ++
  crypt/Makefile                                     |   9 +-
  crypt/README.crypt_blowfish                        |  68 ++
  crypt/Versions                                     |  16 +-
  crypt/badsalttest.c                                |  39 +-
  crypt/blowfish-test.c                              | 322 ++++++++
  crypt/crypt-entry.c                                | 256 ++++--
  crypt/crypt.h                                      |  26 +
  crypt/crypt_blowfish.c                             | 904 
+++++++++++++++++++++
  crypt/crypt_blowfish.h                             |  30 +
  crypt/crypt_gensalt.c                              | 183 +++++
  crypt/crypt_gensalt.h                              |  31 +
  crypt/des-crypt.c                                  | 106 +++
  crypt/gensalt-test.c                               | 109 +++
  sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist   |   7 +
  sysdeps/unix/sysv/linux/alpha/libcrypt.abilist     |   7 +
  sysdeps/unix/sysv/linux/arm/libcrypt.abilist       |   7 +
  sysdeps/unix/sysv/linux/hppa/libcrypt.abilist      |   7 +
  sysdeps/unix/sysv/linux/i386/libcrypt.abilist      |   7 +
  sysdeps/unix/sysv/linux/ia64/libcrypt.abilist      |   7 +
  .../unix/sysv/linux/m68k/coldfire/libcrypt.abilist |   7 +
  .../unix/sysv/linux/m68k/m680x0/libcrypt.abilist   |   7 +
  .../unix/sysv/linux/microblaze/libcrypt.abilist    |   7 +
  .../unix/sysv/linux/mips/mips32/libcrypt.abilist   |   7 +
  .../unix/sysv/linux/mips/mips64/libcrypt.abilist   |   7 +
  sysdeps/unix/sysv/linux/nios2/libcrypt.abilist     |   7 +
  .../sysv/linux/powerpc/powerpc32/libcrypt.abilist  |   7 +
  .../linux/powerpc/powerpc64/libcrypt-le.abilist    |   7 +
  .../sysv/linux/powerpc/powerpc64/libcrypt.abilist  |   7 +
  .../unix/sysv/linux/s390/s390-32/libcrypt.abilist  |   7 +
  .../unix/sysv/linux/s390/s390-64/libcrypt.abilist  |   7 +
  sysdeps/unix/sysv/linux/sh/libcrypt.abilist        |   7 +
  .../unix/sysv/linux/sparc/sparc32/libcrypt.abilist |   7 +
  .../unix/sysv/linux/sparc/sparc64/libcrypt.abilist |   7 +
  .../linux/tile/tilegx/tilegx32/libcrypt.abilist    |   7 +
  .../linux/tile/tilegx/tilegx64/libcrypt.abilist    |   7 +
  .../unix/sysv/linux/tile/tilepro/libcrypt.abilist  |   7 +
  sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist |   7 +
  .../unix/sysv/linux/x86_64/x32/libcrypt.abilist    |   7 +
  39 files changed, 2260 insertions(+), 78 deletions(-)
  create mode 100644 crypt/README.crypt_blowfish
  create mode 100644 crypt/blowfish-test.c
  create mode 100644 crypt/crypt_blowfish.c
  create mode 100644 crypt/crypt_blowfish.h
  create mode 100644 crypt/crypt_gensalt.c
  create mode 100644 crypt/crypt_gensalt.h
  create mode 100644 crypt/des-crypt.c
  create mode 100644 crypt/gensalt-test.c
  

Comments

Adhemerval Zanella May 31, 2017, 8:48 p.m. UTC | #1
On 31/05/2017 14:33, Björn Esser wrote:
> From f781e7f3e151ed89edd357734dd457bd4cd39ec0 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
> Date: Wed, 31 May 2017 13:37:36 +0200
> Subject: [PATCH] This is an implementation of a password hashing method,
>  provided via the crypt(3) and a reentrant interface.  It is fully compatible
>  with OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
>  David Mazieres.

I would like to hear from someone more experienced with licenses if we actually
use the license on some file as-is or if we should re-license it before actually
reviewing it.
  
Björn Esser June 1, 2017, 8:08 a.m. UTC | #2
Am 31.05.2017 um 22:48 schrieb Adhemerval Zanella:
>
> On 31/05/2017 14:33, Björn Esser wrote:
>>  From f781e7f3e151ed89edd357734dd457bd4cd39ec0 Mon Sep 17 00:00:00 2001
>> From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
>> Date: Wed, 31 May 2017 13:37:36 +0200
>> Subject: [PATCH] This is an implementation of a password hashing method,
>>   provided via the crypt(3) and a reentrant interface.  It is fully compatible
>>   with OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
>>   David Mazieres.
> I would like to hear from someone more experienced with licenses if we actually
> use the license on some file as-is or if we should re-license it before actually
> reviewing it.

When running `licensecheck -r .` on the glibc source-tree, there are 
many files being licensed MIT/X11 and/or BSD 3-clause.  I don't see any 
reason Public Domain isn't suitable then.

Anyways, since Public Domain doesn't restrict relicensing, I can add a 
`LGPL v2.1 or later` license to the files in question.
  
Florian Weimer June 1, 2017, 9:23 a.m. UTC | #3
On 05/31/2017 07:33 PM, Björn Esser wrote:
> +Solar Designer <solar at openwall.com>

I think we generally prefer patch submission from the original author or
copyright holder.

Are the crypt_gensalt functions strongly related to Blowfish support?
In any case, they need documentation, and I'm not sure if the interfaces
are properly designed (haven't looked in detail, admittedly).

The FIPS changes in the patch appear to be incorrect.  Surely Blowfish
should be disabled in FIPS mode, too.

The other question is why we should add Blowfish support when the cipher
is pretty much on everyone's banned list.

Thanks,
Florian
  
Dmitry V. Levin June 1, 2017, 10:39 a.m. UTC | #4
On Thu, Jun 01, 2017 at 11:23:36AM +0200, Florian Weimer wrote:
> On 05/31/2017 07:33 PM, Björn Esser wrote:
> > +Solar Designer <solar at openwall.com>
> 
> I think we generally prefer patch submission from the original author or
> copyright holder.

I'm quite sure the original author has no time for this, but you
definitely can contact him on this subject.

> Are the crypt_gensalt functions strongly related to Blowfish support?

Not really.

> In any case, they need documentation,

JFYI, crypt_blowfish comes with its own crypt(3) manual page documenting them.

> and I'm not sure if the interfaces
> are properly designed (haven't looked in detail, admittedly).

They are properly designed, no doubts about it,
unlike the infamous change of crypt(3) to return NULL for bad salt.

As to this API extension, it's arguably even more important than having
bcrypt support in libcrypt.

The only drawback of adding crypt_gensalt et al functions without bcrypt
is potential breakage of various configure scripts that decide whether
to rely on bcrypt support in libcrypt or not based on the crypt_gensalt
availability in libcrypt.

> The other question is why we should add Blowfish support when the cipher
> is pretty much on everyone's banned list.

Is there any link between bcrypt support in libcrypt and Blowfish support
in ssh/ssl/etc, besides a psychological one?
  
Adhemerval Zanella June 1, 2017, 12:03 p.m. UTC | #5
On 01/06/2017 05:08, Björn Esser wrote:
> Am 31.05.2017 um 22:48 schrieb Adhemerval Zanella:
>>
>> On 31/05/2017 14:33, Björn Esser wrote:
>>>  From f781e7f3e151ed89edd357734dd457bd4cd39ec0 Mon Sep 17 00:00:00 2001
>>> From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
>>> Date: Wed, 31 May 2017 13:37:36 +0200
>>> Subject: [PATCH] This is an implementation of a password hashing method,
>>>   provided via the crypt(3) and a reentrant interface.  It is fully compatible
>>>   with OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
>>>   David Mazieres.
>> I would like to hear from someone more experienced with licenses if we actually
>> use the license on some file as-is or if we should re-license it before actually
>> reviewing it.
> 
> When running `licensecheck -r .` on the glibc source-tree, there are many files being licensed MIT/X11 and/or BSD 3-clause.  I don't see any reason Public Domain isn't suitable then.

What I am not sure is which is the correct current policy for new additions,
which might be different that previous code integrations done in the past.

> 
> Anyways, since Public Domain doesn't restrict relicensing, I can add a `LGPL v2.1 or later` license to the files in question.

It makes thing easier if it is the case then.
  
Björn Esser June 1, 2017, 12:44 p.m. UTC | #6
Am 01.06.2017 um 12:39 schrieb Dmitry V. Levin:
> On Thu, Jun 01, 2017 at 11:23:36AM +0200, Florian Weimer wrote:
>> On 05/31/2017 07:33 PM, Björn Esser wrote:
>>> +Solar Designer <solar at openwall.com>
>> I think we generally prefer patch submission from the original author or
>> copyright holder.

Before submitting this patch, I discussed it with the original author.  
The outcome about it was, that he tried to get this in some 10 years 
ago, but Ulrich Depper rejected it; he was fine with me submitting this 
again.

>> I'm quite sure the original author has no time for this, but you
>> definitely can contact him on this subject.
>>
>> Are the crypt_gensalt functions strongly related to Blowfish support?
> Not really.

They are not, but however most vendor patches to glibc (like SUSE, 
openwall, etc.) implement them.  Thus I added those crypt_gensalt 
functions for the sake of common usage along Blowfish support.

>
>> In any case, they need documentation,
> JFYI, crypt_blowfish comes with its own crypt(3) manual page documenting them.

As soon as there is an agreement about including this patch, I'll add 
the needed documentation to it.

>> and I'm not sure if the interfaces
>> are properly designed (haven't looked in detail, admittedly).
> They are properly designed, no doubts about it,
> unlike the infamous change of crypt(3) to return NULL for bad salt.
>
> As to this API extension, it's arguably even more important than having
> bcrypt support in libcrypt.
>
> The only drawback of adding crypt_gensalt et al functions without bcrypt
> is potential breakage of various configure scripts that decide whether
> to rely on bcrypt support in libcrypt or not based on the crypt_gensalt
> availability in libcrypt.
>
>> The other question is why we should add Blowfish support when the cipher
>> is pretty much on everyone's banned list.
> Is there any link between bcrypt support in libcrypt and Blowfish support
> in ssh/ssl/etc, besides a psychological one?

There is not link between them, but the cipher itself;  this 
implementation has been developed independently and was written with 
focus on password hashing instead of encryption of data streams.
  
Björn Esser June 1, 2017, 1:02 p.m. UTC | #7
Am 01.06.2017 um 11:23 schrieb Florian Weimer:
> On 05/31/2017 07:33 PM, Björn Esser wrote:
>> +Solar Designer <solar at openwall.com>
> I think we generally prefer patch submission from the original author or
> copyright holder.
>
> Are the crypt_gensalt functions strongly related to Blowfish support?
> In any case, they need documentation, and I'm not sure if the interfaces
> are properly designed (haven't looked in detail, admittedly).
>
> The FIPS changes in the patch appear to be incorrect.  Surely Blowfish
> should be disabled in FIPS mode, too.

I'll change this in the next version of this patch.

> The other question is why we should add Blowfish support when the cipher
> is pretty much on everyone's banned list.

Well, it depends on it's use case.  If we're talking about encrypting 
large data streams then it's to be considered deprecated or vulnerable 
(SWEET32);  talking about password hashing it still offers some 
advantages over other algorithms (brute forcing takes unlikely much more 
time on bcrypt hashed passwords) and excellent security.  Look at 
OpenBSD, SUSE, OpenWall, etc. still using bcrypt as the default password 
hashing algorithm.

>
> Thanks,
> Florian
  
Joseph Myers June 1, 2017, 1:55 p.m. UTC | #8
On Wed, 31 May 2017, Björn Esser wrote:

> From f781e7f3e151ed89edd357734dd457bd4cd39ec0 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
> Date: Wed, 31 May 2017 13:37:36 +0200
> Subject: [PATCH] This is an implementation of a password hashing method,
>  provided via the crypt(3) and a reentrant interface.  It is fully compatible
>  with OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
>  David Mazieres.

This patch appears to add various new public APIs.

* Patches adding new public APIs need to include a proper explanation of 
those APIs, and the justification for adding them to glibc, in the patch 
submission mail (which would become the commit message); any new API that 
is also an ABI, as here, is permanent and we need to be very careful about 
making sure that we do want to add the interface and that the interface 
being added is the best one to add for that functionality.  Especially, 
since no other crypt algorithm needs its own APIs, you need to explain 
what's special about this algorithm to require such APIs.  If the APIs are 
independent of the new algorithm support, the new algorithm support and 
the APIs should be submitted and considered separately.

* New APIs (and other new features, as here) need to be mentioned in a 
NEWS entry.

* New APIs need to be documented in the glibc manual (crypt.texi in this 
case).

* I don't see any tests of the new function crypt_gensalt_rn.

* Please don't add any miscellaneous README files like 
crypt/README.crypt_blowfish, especially not ones with a load of text that 
appears to be about an external package rather than a description of the 
current state of glibc-with-this-patch-applied.  Documentation of features 
in glibc should be integrated into the glibc manual and kept up to date 
there.  Descriptions of changes in a release go in the NEWS file.

* All new tests should use the support/test-driver.c mechanism, see 
support/README-testing.c, rather than defining their own main function.

* Unless the code is intended to be maintained in sync verbatim with some 
external package, the new code should be formatted according to the GNU 
Coding Standards.

* Given that crypt.h already has __USE_GNU-conditional declarations, I'd 
expect these interfaces to be conditional on __USE_GNU as well.  
(Although, strictly, crypt.h is not a standard header so the standards say 
nothing about conditions for functions in it; the functions POSIX has are 
declared by POSIX in unistd.h.)
  
Zack Weinberg June 1, 2017, 6:44 p.m. UTC | #9
Here are some high-level comments; I have not reviewed the code in detail.

First, if we were designing from scratch today, we wouldn't have
crypt(3) in the C library at all; it would make more sense to keep it
with the implementations of login(1) and passwd(1), i.e. the PAM
suite.  Indeed, I see that PAM independently implements the $1$
md5-based format and something called "bigcrypt".  We're stuck with
crypt(3), the function, in glibc forever because it's in POSIX, but I
have to wonder whether it might make more sense to move _all_ of the
modern password hashes into PAM and _drop_ them from glibc.  And
perhaps move the now-legacy-DES-only function into libc proper and
drop libcrypt, freeing the library name for PAM or some other project
to adopt. That would render the question of OpenWall's additional APIs
moot.

It would make sense to keep many password-hashing algorithms in libc
if there are a substantial number of programs _other_ than PAM that
use our crypt(), and/or if we think that we can keep up with password
hashing algorithms more efficiently than PAM can -- it's not clear to
me how actively maintained that project is.  Can you, or anyone
comment on that?

I agree with Joseph and Florian that we want to review the new APIs
independently from the addition of bcrypt support, and I would suggest
that you look at implementing crypt_checkpass and crypt_genhash [see
http://man.openbsd.org/crypt_checkpass.3] as well.  We would ensure
that everything was laid down together for the same _release_, but
review will be much simpler if we can look at the APIs and the
algorithms independently.

I also agree that documentation for the new APIs is required, and I
would add that the existing documentation for crypt() itself fails to
describe all of the hash formats that we already have.  (Relatedly,
what exactly are the differences among formats 2a, 2b, 2x, and 2y?
That needs to be documented as well.  If, as is hopefully the case,
only one should be used for new hashes, say so.)

To avoid confusion I strongly recommend referring to the new algorithm
as "bcrypt" and never as "blowfish-based".

Are there any other algorithms we should be adding at the same time?
PBKDF2-something?  Argon2?

zw
  
Florian Weimer June 1, 2017, 6:52 p.m. UTC | #10
On 06/01/2017 08:44 PM, Zack Weinberg wrote:
> First, if we were designing from scratch today, we wouldn't have
> crypt(3) in the C library at all; it would make more sense to keep it
> with the implementations of login(1) and passwd(1), i.e. the PAM
> suite.  Indeed, I see that PAM independently implements the $1$
> md5-based format and something called "bigcrypt".  We're stuck with
> crypt(3), the function, in glibc forever because it's in POSIX, but I
> have to wonder whether it might make more sense to move _all_ of the
> modern password hashes into PAM and _drop_ them from glibc.

We could build an ABI-compatible version of libcrypt from a suitable
cryptographic library (probably OpenSSL) because that's where all the
algorithms live anyway (PAM doesn't have that advantage).  There is
nothing glibc-specific in libcrypt, and glibc does not otherwise use it.

Thanks,
Florian
  
Zack Weinberg June 1, 2017, 6:59 p.m. UTC | #11
On Thu, Jun 1, 2017 at 2:52 PM, Florian Weimer <fweimer@redhat.com> wrote:
> On 06/01/2017 08:44 PM, Zack Weinberg wrote:
>> First, if we were designing from scratch today, we wouldn't have
>> crypt(3) in the C library at all; it would make more sense to keep it
>> with the implementations of login(1) and passwd(1), i.e. the PAM
>> suite.  Indeed, I see that PAM independently implements the $1$
>> md5-based format and something called "bigcrypt".  We're stuck with
>> crypt(3), the function, in glibc forever because it's in POSIX, but I
>> have to wonder whether it might make more sense to move _all_ of the
>> modern password hashes into PAM and _drop_ them from glibc.
>
> We could build an ABI-compatible version of libcrypt from a suitable
> cryptographic library (probably OpenSSL) because that's where all the
> algorithms live anyway (PAM doesn't have that advantage).  There is
> nothing glibc-specific in libcrypt, and glibc does not otherwise use it.

And libcrypt is also the only thing that cares about FIPS and NSS,
right?  So there's a significant dependency-graph win if we kick it
out of the glibc source tree, as well.

I wouldn't want to do this without having maintainers lined up for the
independent libcrypt, though (and no, I'm not volunteering ;-)

zw
  
Björn Esser June 1, 2017, 7:05 p.m. UTC | #12
Am 01.06.2017 um 20:59 schrieb Zack Weinberg:
> On Thu, Jun 1, 2017 at 2:52 PM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 06/01/2017 08:44 PM, Zack Weinberg wrote:
>>> First, if we were designing from scratch today, we wouldn't have
>>> crypt(3) in the C library at all; it would make more sense to keep it
>>> with the implementations of login(1) and passwd(1), i.e. the PAM
>>> suite.  Indeed, I see that PAM independently implements the $1$
>>> md5-based format and something called "bigcrypt".  We're stuck with
>>> crypt(3), the function, in glibc forever because it's in POSIX, but I
>>> have to wonder whether it might make more sense to move _all_ of the
>>> modern password hashes into PAM and _drop_ them from glibc.
>> We could build an ABI-compatible version of libcrypt from a suitable
>> cryptographic library (probably OpenSSL) because that's where all the
>> algorithms live anyway (PAM doesn't have that advantage).  There is
>> nothing glibc-specific in libcrypt, and glibc does not otherwise use it.
> And libcrypt is also the only thing that cares about FIPS and NSS,
> right?  So there's a significant dependency-graph win if we kick it
> out of the glibc source tree, as well.
>
> I wouldn't want to do this without having maintainers lined up for the
> independent libcrypt, though (and no, I'm not volunteering ;-)
>
> zw

There is libxcrypt [1] around in some distros (e.g. Debian, Gentoo, 
Arch, among other small ones) which would serve this approach pretty 
well and already implements all my changes from this patch.  I'd 
volunteer to refactor this being the new libcrypt as a separate project.

During the refactoring, I can throw out all stuff being already provided 
by OpenSSL and wrap those in the established crypt function.

What do you think?
  
Zack Weinberg June 1, 2017, 7:14 p.m. UTC | #13
On Thu, Jun 1, 2017 at 2:44 PM, Zack Weinberg <zackw@panix.com> wrote:
> Here are some high-level comments; I have not reviewed the code in detail.
>
> First, if we were designing from scratch today, we wouldn't have
> crypt(3) in the C library at all; it would make more sense to keep it
> with the implementations of login(1) and passwd(1), i.e. the PAM
> suite.  Indeed, I see that PAM independently implements the $1$
> md5-based format and something called "bigcrypt".  We're stuck with
> crypt(3), the function, in glibc forever because it's in POSIX, but I
> have to wonder whether it might make more sense to move _all_ of the
> modern password hashes into PAM and _drop_ them from glibc.  And
> perhaps move the now-legacy-DES-only function into libc proper and
> drop libcrypt, freeing the library name for PAM or some other project
> to adopt. That would render the question of OpenWall's additional APIs
> moot.

I think I should make clear that I'm proposing this as a _solution_ to
the problem of glibc being unconscionably slow to adopt modern
password hashing.  glibc is very slow to do _anything_, because it's a
big sprawling library, constrained by standards and by ABI
compatibility, and because we have some nasty process problems (in a
sentence: nobody feels empowered to say "yes" to anything).  And
people are understandably very cautious about upgrading it.

An independent project, focused on providing password hashing and
nothing else, should be able to work much more efficiently.

zw
  
Joseph Myers June 1, 2017, 8:16 p.m. UTC | #14
On Thu, 1 Jun 2017, Florian Weimer wrote:

> On 06/01/2017 08:44 PM, Zack Weinberg wrote:
> > First, if we were designing from scratch today, we wouldn't have
> > crypt(3) in the C library at all; it would make more sense to keep it
> > with the implementations of login(1) and passwd(1), i.e. the PAM
> > suite.  Indeed, I see that PAM independently implements the $1$
> > md5-based format and something called "bigcrypt".  We're stuck with
> > crypt(3), the function, in glibc forever because it's in POSIX, but I
> > have to wonder whether it might make more sense to move _all_ of the
> > modern password hashes into PAM and _drop_ them from glibc.
> 
> We could build an ABI-compatible version of libcrypt from a suitable
> cryptographic library (probably OpenSSL) because that's where all the
> algorithms live anyway (PAM doesn't have that advantage).  There is
> nothing glibc-specific in libcrypt, and glibc does not otherwise use it.

(Some of) the interfaces are POSIX interfaces, declared (per POSIX) in 
unistd.h, although that's only indicative of possible glibc suitability 
(after all, we don't implement ndbm.h, and XFAIL the relevant conform/ 
tests; it's left to other libraries to implement those interfaces).

Using OpenSSL in a crypt implementation does of course bring in the same 
namespace issues as with NSS modules linked with external libraries.

I have wondered if there should be a system for crypt loading .so files 
for hash algorithms, so they could be built independently of glibc, but no 
doubt building ABI-compatible libcrypt (complete with the right 
architecture-specific symbol versions) from separate sources would be 
simpler.
  
Florian Weimer June 1, 2017, 8:28 p.m. UTC | #15
On 06/01/2017 10:16 PM, Joseph Myers wrote:
> Using OpenSSL in a crypt implementation does of course bring in the same 
> namespace issues as with NSS modules linked with external libraries.

That's why I want to build the replacement *from* (or as part of) a
cryptographic library, not using it.  This way, the internal mechanics
can be hidden easily, and we still can use tried-and-test (and
optimized) implementations of the cryptographic primitives.

We may have a technical namespace violation with
pthread_mutex_lock/pthread_mutex_unlock if there is a PRNG for salt
generation, but I don't think that's particularly worrisome.

Thanks,
Florian
  
Florian Weimer June 2, 2017, 6:18 a.m. UTC | #16
On 06/01/2017 08:59 PM, Zack Weinberg wrote:
> On Thu, Jun 1, 2017 at 2:52 PM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 06/01/2017 08:44 PM, Zack Weinberg wrote:
>>> First, if we were designing from scratch today, we wouldn't have
>>> crypt(3) in the C library at all; it would make more sense to keep it
>>> with the implementations of login(1) and passwd(1), i.e. the PAM
>>> suite.  Indeed, I see that PAM independently implements the $1$
>>> md5-based format and something called "bigcrypt".  We're stuck with
>>> crypt(3), the function, in glibc forever because it's in POSIX, but I
>>> have to wonder whether it might make more sense to move _all_ of the
>>> modern password hashes into PAM and _drop_ them from glibc.
>>
>> We could build an ABI-compatible version of libcrypt from a suitable
>> cryptographic library (probably OpenSSL) because that's where all the
>> algorithms live anyway (PAM doesn't have that advantage).  There is
>> nothing glibc-specific in libcrypt, and glibc does not otherwise use it.
> 
> And libcrypt is also the only thing that cares about FIPS and NSS,
> right?  So there's a significant dependency-graph win if we kick it
> out of the glibc source tree, as well.

Yes, at least until we implement arc4random.

Florian
  
Thorsten Kukuk June 20, 2017, 11:26 a.m. UTC | #17
On Thu, Jun 01, Florian Weimer wrote:

> The other question is why we should add Blowfish support when the cipher
> is pretty much on everyone's banned list.

We should not add it. The whole interface is poorly designed and complicated
to use. And there are today better cipher. Blowfish is outdated today.

  Thorsten
  
Thorsten Kukuk June 20, 2017, 11:33 a.m. UTC | #18
On Thu, Jun 01, Björn Esser wrote:

> Look at OpenBSD, SUSE, OpenWall, etc. still using bcrypt as the default password hashing algorithm.

At least for SUSE this is not correct.
Blowfish is only there for compatibility reasons with existing passwords.
With the default configuration, you cannot even create new passwords with blowfish
since many years.
The last time we discussed the topic with the blowfish author, he was surprised
that there is still somebody using it.

  Thorsten
  
Björn Esser June 20, 2017, 11:37 a.m. UTC | #19
Am 20.06.2017 um 13:33 schrieb Thorsten Kukuk:
> On Thu, Jun 01, Björn Esser wrote:
>
>> Look at OpenBSD, SUSE, OpenWall, etc. still using bcrypt as the default password hashing algorithm.
> At least for SUSE this is not correct.
> Blowfish is only there for compatibility reasons with existing passwords.
> With the default configuration, you cannot even create new passwords with blowfish
> since many years.
> The last time we discussed the topic with the blowfish author, he was surprised
> that there is still somebody using it.
>
>    Thorsten

What do you think about the `crypt_gensalt`-functions, then?  Those are 
actually used in YaST2, afaik…
Shall we at least add these to libcrypt, then?
  
Dmitry V. Levin June 20, 2017, 11:51 a.m. UTC | #20
On Tue, Jun 20, 2017 at 01:26:02PM +0200, Thorsten Kukuk wrote:
> On Thu, Jun 01, Florian Weimer wrote:
> 
> > The other question is why we should add Blowfish support when the cipher
> > is pretty much on everyone's banned list.
> 
> We should not add it. The whole interface is poorly designed and complicated
> to use.

For more than 16 years that this interface (crypt_rn, crypt_ra, and
crypt_gensalt*) is in use, it's called poorly designed and complicated
to use for the first time AFAIK.  Thorsten, could you elaborate, please?

> And there are today better cipher. Blowfish is outdated today.

Well, bcrypt is not blowfish. :)
  
Dmitry V. Levin Sept. 8, 2017, 9:19 p.m. UTC | #21
On Tue, Jun 20, 2017 at 02:51:51PM +0300, Dmitry V. Levin wrote:
> On Tue, Jun 20, 2017 at 01:26:02PM +0200, Thorsten Kukuk wrote:
> > On Thu, Jun 01, Florian Weimer wrote:
> > 
> > > The other question is why we should add Blowfish support when the cipher
> > > is pretty much on everyone's banned list.
> > 
> > We should not add it. The whole interface is poorly designed and complicated
> > to use.
> 
> For more than 16 years that this interface (crypt_rn, crypt_ra, and
> crypt_gensalt*) is in use, it's called poorly designed and complicated
> to use for the first time AFAIK.  Thorsten, could you elaborate, please?
> 
> > And there are today better cipher. Blowfish is outdated today.
> 
> Well, bcrypt is not blowfish. :)

I think blanket objections like this don't help to reach a consensus.
  
Zack Weinberg Sept. 8, 2017, 9:39 p.m. UTC | #22
On Fri, Sep 8, 2017 at 5:19 PM, Dmitry V. Levin <ldv@altlinux.org> wrote:
> On Tue, Jun 20, 2017 at 02:51:51PM +0300, Dmitry V. Levin wrote:
>> On Tue, Jun 20, 2017 at 01:26:02PM +0200, Thorsten Kukuk wrote:
>> >
>> > And there are today better cipher. Blowfish is outdated today.
>>
>> Well, bcrypt is not blowfish. :)
>
> I think blanket objections like this don't help to reach a consensus.

This whole discussion has left me very, very confused.  In the larger
community of people hashing passwords (larger than the community of
people using crypt(3) to do it, that is), you can find plenty of
glowing recommendations for bcrypt, e.g.
https://codahale.com/how-to-safely-store-a-password/ and
https://security.stackexchange.com/a/6415 (both from circa 2010,
admittedly). There are newer things out there, like Argon2
(https://password-hashing.net/#argon2) but I haven't heard anyone
saying bcrypt is _broken_.

_Blowfish_, the block cipher, is indeed too weak to use as a
general-purpose symmetric cryptosystem anymore, but only because its
block size is too small, not because the algorithm is bad (AFAIK,
anyway) and as used in bcrypt it's still sound.  It's kinda like how
HMAC-SHA1 is still secure even though SHA1 itself isn't trustworthy
anymore.

Is there some _other_ password hash, confusingly also called "bcrypt",
that is no good anymore?

zw
  

Patch

diff --git a/ChangeLog b/ChangeLog
index 1dc6d5c8e3..8ad9c06256 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,67 @@ 
+2017-05-31  Björn Esser  <besser82@fedoraproject.org>
+
+	[BZ #2100]
+	* crypt/Makefile: Add new files and tests.
+	* crypt/README.crypt_blowfish: New file.
+	* crypt/Versions [GLIBC_2.26]: Add new symbols.
+	* crypt/badsalttest.c: Add tests for crypt_r(a|n).  Print the return
+	value of the tested hash, if not NULL.
+	* crypt/blowfish-test.c: New test.
+	* crypt/crypt-entry.c: Add support for bcrypt prefixes "$2a$", "$2b$",
+	"$2x$", "$2y$".
+	(crypt_gensalt): New function.  Compiles a string for use as setting
+	with the given prefix, the iteration count, if supported by the chosen
+	method, and up to size cryptographically random input bytes for use as
+	the actual salt.
+	(crypt_gensalt_r): Likewise.  Reentrant version, behaves like
+	crypt_gensalt_rn.
+	(crypt_gensalt_ra): Likewise. Reentrant version, allocates memory for
+	its result dynamically.
+	(crypt_gensalt_rn): Likewise. Reentrant version, places its result in
+	the output buffer of output_size bytes.
+	(crypt_ra): Likewise.  Reentrant version of crypt, *data can be NULL.
+	When called with a NULL *data or insufficient *size for the requested
+	hashing algorithm, it uses realloc to allocate the required amount of
+	memory dynamically.
+	(crypt_rn): Likewise.  Reentrant version of crypt, requires that the
+	entire data area to be zeroed, where crypt_r requires that only
+	data->initialized be reset to zero.
+	* crypt/crypt.h: Add new functions introduced in <crypt/crypt-entry.c>.
+	* crypt/crypt_blowfish.c: New file.
+	* crypt/crypt_blowfish.h: Likewise.
+	* crypt/crypt_gensalt.c: Likewise.
+	* crypt/crypt_gensalt.h: Likewise.
+	* crypt/des-crypt.c: New file split out from <crypt/crypt-entry.c>.
+	* crypt/gensalt-test.c: New file.
+	* sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist: New functions.
+	* sysdeps/unix/sysv/linux/alpha/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/arm/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/hppa/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/i386/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/ia64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/nios2/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sh/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist: Likewise.
+
  2017-05-31  Andreas Schwab  <schwab@suse.de>
   	* nptl/tst-fork3.c: Include <support/test-driver.c>.
diff --git a/crypt/Makefile b/crypt/Makefile
index 0280fba8a7..45299ef17e 100644
--- a/crypt/Makefile
+++ b/crypt/Makefile
@@ -27,10 +27,11 @@  headers := crypt.h
  extra-libs := libcrypt
  extra-libs-others := $(extra-libs)
  -libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt 
crypt \
-		     crypt_util
+libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt 
crypt  \
+		     crypt_util des-crypt crypt_blowfish crypt_gensalt
  -tests := cert md5c-test sha256c-test sha512c-test badsalttest
+tests := cert md5c-test sha256c-test sha512c-test badsalttest 
blowfish-test \
+	 gensalt-test
   ifeq ($(crypt-in-libc),yes)
  routines += $(libcrypt-routines)
@@ -42,7 +43,7 @@  CPPFLAGS-sha512-crypt.c = -DUSE_NSS -I$(shell 
nss-config --includedir)
  CPPFLAGS-md5-crypt.c = -DUSE_NSS -I$(shell nss-config --includedir)
  LDLIBS-crypt.so = -lfreebl3
  else
-libcrypt-routines += md5 sha256 sha512
+libcrypt-routines += md5 sha256 sha512 des-crypt crypt_blowfish 
crypt_gensalt
   tests += md5test sha256test sha512test
  diff --git a/crypt/README.crypt_blowfish b/crypt/README.crypt_blowfish
new file mode 100644
index 0000000000..ed555b2d27
--- /dev/null
+++ b/crypt/README.crypt_blowfish
@@ -0,0 +1,68 @@ 
+This is an implementation of a password hashing method, provided via the
+crypt(3) and a reentrant interface.  It is fully compatible with
+OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
+David Mazieres.  (Please refer to the included crypt(3) man page for
+information on minor compatibility issues for other bcrypt prefixes.)
+
+I've placed this code in the public domain, with fallback to a
+permissive license.  Please see the comment in crypt_blowfish.c for
+more information.
+
+You can use the provided routines in your own packages, or link them
+into a C library.  I've provided hooks for linking into GNU libc, but
+it shouldn't be too hard to get this into another C library.  Note
+that simply adding this code into your libc is probably not enough to
+make your system use the new password hashing algorithm.  Changes to
+passwd(1), PAM modules, or whatever else your system uses will likely
+be needed as well.  These are not a part of this package, but see
+LINKS for a pointer to our tcb suite.
+
+Instructions on using the routines in one of the two common ways are
+given below.  It is recommended that you test the routines on your
+system before you start.  Type "make check" or "make check_threads"
+(if you have the POSIX threads library), then "make clean".
+
+
+1. Using the routines in your programs.
+
+The available interfaces are in ow-crypt.h, and this is the file you
+should include.  You won't need crypt.h.  When linking, add all of the
+C files and x86.S (you can compile and link it even on a non-x86, it
+will produce no code in this case).
+
+
+2. Building the routines into GNU C library.
+
+For versions 2.13 and 2.14 (and likely other nearby ones), extract the
+library sources as usual.  Apply the patch for glibc 2.14 provided in
+this package.  Enter crypt/ and rename crypt.h to gnu-crypt.h within
+that directory.  Copy the C sources, header, and assembly (x86.S) files
+from this package in there as well (but be sure you don't overwrite the
+Makefile).  Configure, build, and install the library as usual.
+
+For versions 2.2 to 2.3.6 (and likely also for some newer ones),
+extract the library sources and maybe its optional add-ons as usual.
+Apply the patch for glibc 2.3.6 provided in this package.  Enter
+crypt/ and rename crypt.h to gnu-crypt.h within that directory.  Copy
+the C sources, header, and assembly (x86.S) files from this package in
+there as well (but be sure you don't overwrite the Makefile).
+Configure, build, and install the library as usual.
+
+For versions 2.1 to 2.1.3, extract the library sources and the crypt
+and linuxthreads add-ons as usual.  Apply the patch for glibc 2.1.3
+provided in this package.  Enter crypt/sysdeps/unix/, and rename
+crypt.h to gnu-crypt.h within that directory.  Copy C sources, header,
+and assembly (x86.S) files from this package in there as well (but be
+sure you don't overwrite the Makefile).  Configure, build, and install
+the library as usual.
+
+Programs that want to use the provided interfaces will need to include
+crypt.h (but not ow-crypt.h directly).  By default, prototypes for the
+new routines aren't defined (but the extra functionality of crypt(3)
+is indeed available).  You need to define _OW_SOURCE to obtain the new
+routines as well.
+
+--
+Solar Designer <solar at openwall.com>
+
+$Owl: Owl/packages/glibc/crypt_blowfish/README,v 1.10 2014/07/07 
15:19:04 solar Exp $
diff --git a/crypt/Versions b/crypt/Versions
index 389e7d544a..0086753f21 100644
--- a/crypt/Versions
+++ b/crypt/Versions
@@ -1,5 +1,19 @@ 
  libcrypt {
    GLIBC_2.0 {
-    crypt; crypt_r; encrypt; encrypt_r; fcrypt; setkey; setkey_r;
+    crypt;
+    crypt_r;
+    encrypt;
+    encrypt_r;
+    fcrypt;
+    setkey;
+    setkey_r;
+  }
+  GLIBC_2.26 {
+    crypt_gensalt;
+    crypt_gensalt_r;
+    crypt_gensalt_ra;
+    crypt_gensalt_rn;
+    crypt_ra;
+    crypt_rn;
    }
  }
diff --git a/crypt/badsalttest.c b/crypt/badsalttest.c
index f27e39316e..5ca12fd59d 100644
--- a/crypt/badsalttest.c
+++ b/crypt/badsalttest.c
@@ -38,6 +38,8 @@  do_test (void)
  {
    int result = 0;
    struct crypt_data cd;
+  int cd_size = sizeof(cd);
+  void *cd_ptr = &cd;
    size_t n = sizeof (tests) / sizeof (*tests);
    size_t pagesize = (size_t) sysconf (_SC_PAGESIZE);
    char *page;
@@ -63,18 +65,43 @@  do_test (void)
     for (size_t i = 0; i < n; i++)
      {
-      if (crypt (tests[i][0], tests[i][1]))
+      char *output;
+
+      output = crypt (tests[i][0], tests[i][1]);
+      if (output)
+	{
+	  result++;
+	  printf ("%s: crypt returned non-NULL with salt \"%s\", value:\"%s\"\n",
+		  tests[i][0], tests[i][1], output);
+	  output = NULL;
+
+	}
+
+      output = crypt_r (tests[i][0], tests[i][1], &cd);
+      if (output)
+	{
+	  result++;
+	  printf ("%s: crypt_r returned non-NULL with salt \"%s\", 
value:\"%s\"\n",
+		  tests[i][0], tests[i][1], output);
+	  output = NULL;
+	}
+
+      output = crypt_ra (tests[i][0], tests[i][1], &cd_ptr, &cd_size);
+      if (output)
  	{
  	  result++;
-	  printf ("%s: crypt returned non-NULL with salt \"%s\"\n",
-		  tests[i][0], tests[i][1]);
+	  printf ("%s: crypt_ra returned non-NULL with salt \"%s\", 
value:\"%s\"\n",
+		  tests[i][0], tests[i][1], output);
+	  output = NULL;
  	}
  -      if (crypt_r (tests[i][0], tests[i][1], &cd))
+      output = crypt_rn (tests[i][0], tests[i][1], &cd, cd_size);
+      if (output)
  	{
  	  result++;
-	  printf ("%s: crypt_r returned non-NULL with salt \"%s\"\n",
-		  tests[i][0], tests[i][1]);
+	  printf ("%s: crypt_rn returned non-NULL with salt \"%s\", 
value:\"%s\"\n",
+		  tests[i][0], tests[i][1], output);
+	  output = NULL;
  	}
      }
  diff --git a/crypt/blowfish-test.c b/crypt/blowfish-test.c
new file mode 100644
index 0000000000..bd6f0c2a63
--- /dev/null
+++ b/crypt/blowfish-test.c
@@ -0,0 +1,322 @@ 
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2014.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.	In case this attempt to disclaim copyright and place the 
software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#include "crypt.h"
+#include "crypt_blowfish.c"
+
+struct crypt_data _ufc_foobar;
+
+static int _crypt_data_alloc (void **data, int *size, int need)
+{
+	void *updated;
+
+	if (*data && *size >= need) return 0;
+
+	updated = realloc (*data, need);
+
+	if (!updated) return -1;
+
+	if (need >= sizeof (struct crypt_data))
+		((struct crypt_data *) updated)->initialized = 0;
+
+	*data = updated;
+	*size = need;
+
+	return 0;
+}
+
+static char *_crypt_retval_magic(char *retval, const char *setting,
+					char *output, int size)
+{
+	if (retval) return retval;
+
+	if (_crypt_output_magic(setting, output, size))
+		return NULL; /* shouldn't happen */
+
+	return output;
+}
+
+char *_crypt_rn_test(const char *key, const char *setting, void *data, 
int size)
+{
+	return _crypt_blowfish_rn(key, setting, (char *)data, size);
+}
+
+char *_crypt_ra_test(const char *key, const char *setting, void **data, 
int *size)
+{
+	if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE)) return NULL;
+	return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
+}
+
+char *_crypt_r_test(const char *key, const char *setting, struct 
crypt_data *data)
+{
+	return _crypt_retval_magic(_crypt_rn_test(key, setting, data, 
sizeof(*data)),
+				   setting, (char*)data, sizeof(*data));
+}
+
+char *_crypt_test(const char *key, const char *setting)
+{
+	return _crypt_r_test(key, setting, &_ufc_foobar);
+}
+
+static const char *tests[][3] = {
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", "U*U"},
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", "U*U*"},
+	{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", "U*U*U"},
+	{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
+	 "0123456789abcdefghijklmnopqrstuvwxyz"
+	 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	 "chars after 72 are ignored"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", "\xa3"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+	 "\xff\xff\xa3"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+	 "\xff\xff\xa3"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
+	 "\xff\xff\xa3"},
+	{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+	 "\xff\xff\xa3"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3"},
+	{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+	 "1\xa3" "345"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+	 "\xff\xa3" "345"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+	 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+	 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
+	 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
+	 "\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
+	 "\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+	 "\xa3" "ab"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+	 "\xa3" "ab"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+	 "\xa3" "ab"},
+	{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
+	 "\xd1\x91"},
+	{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
+	 "\xd0\xc1\xd2\xcf\xcc\xd8"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+	 "chars after 72 are ignored as usual"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+	 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+	 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", ""},
+	{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*1", "", "*0"},
+	{NULL}
+};
+
+#define which tests[0]
+
+static volatile sig_atomic_t running;
+
+static void handle_timer(int signum)
+{
+	(void) signum;
+	running = 0;
+}
+
+static void *run(void *arg)
+{
+	unsigned long count = 0;
+	int i = 0;
+	void *data = NULL;
+	int size = 0x12345678;
+
+	do {
+		const char *hash = tests[i][0];
+		const char *key = tests[i][1];
+		const char *setting = tests[i][2];
+
+		if (!tests[++i][0]) i = 0;
+
+		if (setting && strlen(hash) < 30) /* not for benchmark */
+			continue;
+
+		if (strcmp(_crypt_ra_test(key, hash, &data, &size), hash)) {
+			printf("%d: FAILED (crypt_ra/%d/%lu)\n",
+			(int)((char *)arg - (char *)0), i, count);
+			free(data);
+			return NULL;
+		}
+		count++;
+	} while (running);
+
+	free(data);
+	return count + (char *)0;
+}
+
+int main(void)
+{
+	struct itimerval it;
+	struct tms buf;
+	clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
+	unsigned long count;
+	void *data;
+	int size;
+	char *setting1, *setting2;
+	int i;
+
+	data = NULL;
+	size = 0x12345678;
+
+	for (i = 0; tests[i][0]; i++) {
+		const char *hash = tests[i][0];
+		const char *key = tests[i][1];
+		const char *setting = tests[i][2];
+		const char *p;
+		int ok = !setting || strlen(hash) >= 30;
+		int o_size;
+		char s_buf[30], o_buf[61];
+		if (!setting) {
+			memcpy(s_buf, hash, sizeof(s_buf) - 1);
+			s_buf[sizeof(s_buf) - 1] = 0;
+			setting = s_buf;
+		}
+
+		__set_errno(0);
+		p = _crypt_test(key, setting);
+		if ((!ok && !errno) || strcmp(p, hash)) {
+			printf("FAILED (crypt/%d)\n", i);
+			return 1;
+		}
+
+		if (ok && strcmp(_crypt_test(key, hash), hash)) {
+			printf("FAILED (crypt/%d)\n", i);
+			return 1;
+		}
+
+		for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
+			int ok_n = ok && o_size == (int)sizeof(o_buf);
+			const char *x = "abc";
+			strcpy(o_buf, x);
+			if (o_size >= 3) {
+				x = "*0";
+				if (setting[0] == '*' && setting[1] == '0') x = "*1";
+			}
+			__set_errno(0);
+			p = _crypt_rn_test(key, setting, o_buf, o_size);
+			if ((ok_n && (!p || strcmp(p, hash))) ||
+					(!ok_n && (!errno || p || strcmp(o_buf, x)))) {
+				printf("FAILED (crypt_rn/%d)\n", i);
+				return 1;
+			}
+		}
+
+		__set_errno(0);
+		p = _crypt_ra_test(key, setting, &data, &size);
+		if ((ok && (!p || strcmp(p, hash))) ||
+				(!ok && (!errno || p || strcmp((char *)data, hash)))) {
+			printf("FAILED (crypt_ra/%d)\n", i);
+			return 1;
+		}
+	}
+
+	setting1 = crypt_gensalt(which[0], 12, data, size);
+	if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
+		puts("FAILED (crypt_gensalt)\n");
+		return 1;
+	}
+
+	setting2 = crypt_gensalt_ra(setting1, 12, data, size);
+	if (strcmp(setting1, setting2)) {
+		puts("FAILED (crypt_gensalt_ra/1)\n");
+		return 1;
+	}
+
+	(*(char *)data)++;
+	setting1 = crypt_gensalt_ra(setting2, 12, data, size);
+	if (!strcmp(setting1, setting2)) {
+		puts("FAILED (crypt_gensalt_ra/2)\n");
+		return 1;
+	}
+
+	free(setting1);
+	free(setting2);
+	free(data);
+
+#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
+	clk_tck = sysconf(_SC_CLK_TCK);
+#else
+	clk_tck = CLK_TCK;
+#endif
+
+	running = 1;
+	signal(SIGALRM, handle_timer);
+
+	memset(&it, 0, sizeof(it));
+	it.it_value.tv_sec = 5;
+	setitimer(ITIMER_REAL, &it, NULL);
+
+	start_real = times(&buf);
+	start_virtual = buf.tms_utime + buf.tms_stime;
+
+	count = (char *)run((char *)0) - (char *)0;
+
+	end_real = times(&buf);
+	end_virtual = buf.tms_utime + buf.tms_stime;
+	if (end_virtual == start_virtual) end_virtual++;
+
+	printf("%.1f c/s real, %.1f c/s virtual\n",
+				 (float)count * clk_tck / (end_real - start_real),
+				 (float)count * clk_tck / (end_virtual - start_virtual));
+
+	return 0;
+}
diff --git a/crypt/crypt-entry.c b/crypt/crypt-entry.c
index 2271665af2..9ccb1f9a48 100644
--- a/crypt/crypt-entry.c
+++ b/crypt/crypt-entry.c
@@ -35,13 +35,11 @@ 
  #endif
   #include "crypt-private.h"
+#include "crypt_blowfish.h"
+#include "crypt_gensalt.h"
  -/* Prototypes for local functions.  */
-#ifndef __GNU_LIBRARY__
-void _ufc_clearmem (char *start, int cnt);
-#else
-#define _ufc_clearmem(start, cnt)   memset(start, 0, cnt)
-#endif
+extern char *__des_crypt_r (const char *key, const char *salt,
+			    struct crypt_data *data);
  extern char *__md5_crypt_r (const char *key, const char *salt, char 
*buffer,
  			    int buflen);
  extern char *__md5_crypt (const char *key, const char *salt);
@@ -57,6 +55,21 @@  extern char *__sha512_crypt (const char *key, const 
char *salt);
     encryption implementations.  */
  static const char md5_salt_prefix[] = "$1$";
  +/* Magic string for blowfish encryption.  */
+/* unsafe for 8-bit character passwords on some system-architectures */
+static const char blowfish_salt_prefix_a[] = "$2a$";
+
+/* for full compat with OpenBSD 5.5, same as $2y$ */
+static const char blowfish_salt_prefix_b[] = "$2b$";
+
+/* always buggy with 8-bit characters, reference whether system
+   is affected by $2a$-bug */
+static const char blowfish_salt_prefix_x[] = "$2x$";
+
+/* guarantees correct handling of both 7- and 8-bit characters,
+   preferred algorithm */
+static const char blowfish_salt_prefix_y[] = "$2y$";
+
  /* Magic string for SHA256 encryption.  */
  static const char sha256_salt_prefix[] = "$5$";
  @@ -66,17 +79,53 @@ static const char sha512_salt_prefix[] = "$6$";
  /* For use by the old, non-reentrant routines (crypt/encrypt/setkey)  */
  extern struct crypt_data _ufc_foobar;
  +
+static int
+__crypt_data_alloc (void **data, int *size, int need)
+{
+  void *updated;
+
+  if (*data && *size >= need)
+    return 0;
+
+  updated = realloc (*data, need);
+
+  if (!updated)
+    {
+      return -1;
+    }
+
+  if (need >= sizeof (struct crypt_data))
+    ((struct crypt_data *) updated)->initialized = 0;
+
+  *data = updated;
+  *size = need;
+
+  return 0;
+}
+
+
  /*
- * UNIX crypt function
+ * Applications may re-use the same instance of struct crypt_data without
+ * resetting the initialized field in order to let crypt_r() skip some of
+ * its initialization code. Thus, it is important that our multiple hashing
+ * algorithms either don't conflict with each other in their use of the
+ * data area or reset the initialized field themselves whenever required.
+ * Currently, the hashing algorithms simply have no conflicts: the first
+ * field of struct crypt_data is the 128-byte large DES key schedule which
+ * __des_crypt_r() calculates each time it is called while the two other
+ * hashing algorithms use less than 128 bytes of the data area.
   */
   char *
-__crypt_r (const char *key, const char *salt,
-	   struct crypt_data * __restrict data)
+__crypt_rn (const char *key, const char *salt, void *data, int size)
  {
-  ufc_long res[4];
-  char ktab[9];
-  ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
+  /* Try to find out whether we have to use blowfish encryption 
replacement.  */
+  if (strncmp (blowfish_salt_prefix_a, salt, sizeof 
(blowfish_salt_prefix_a) - 1) == 0 ||
+      strncmp (blowfish_salt_prefix_b, salt, sizeof 
(blowfish_salt_prefix_b) - 1) == 0 ||
+      strncmp (blowfish_salt_prefix_x, salt, sizeof 
(blowfish_salt_prefix_x) - 1) == 0 ||
+      strncmp (blowfish_salt_prefix_y, salt, sizeof 
(blowfish_salt_prefix_y) - 1) == 0)
+    return _crypt_blowfish_rn (key, salt, (char *) data, size);
   #ifdef _LIBC
    /* Try to find out whether we have to use MD5 encryption 
replacement.  */
@@ -103,78 +152,151 @@  __crypt_r (const char *key, const char *salt,
  			     sizeof (struct crypt_data));
  #endif
  -  /*
-   * Hack DES tables according to salt
-   */
-  if (!_ufc_setup_salt_r (salt, data))
+  if (size >= sizeof (struct crypt_data))
+    return __des_crypt_r (key, salt, (struct crypt_data *) data);
+
+  __set_errno (ERANGE);
+  return NULL;
+}
+weak_alias (__crypt_rn, crypt_rn)
+
+
+char *
+__crypt_ra (const char *key, const char *salt, void **data, int *size)
+{
+  if (*size == sizeof (struct crypt_data))
+    {
+      if (__crypt_data_alloc (data, size, sizeof (struct crypt_data)))
+        return NULL;
+    }
+
+    if (__crypt_data_alloc (data, size, CRYPT_OUTPUT_SIZE))
+      return NULL;
+
+    return __crypt_rn (key, salt, (char *) *data, *size);
+}
+weak_alias (__crypt_ra, crypt_ra)
+
+
+/*
+ * UNIX crypt function
+ */
+
+char *
+__crypt_r (const char *key, const char *salt,
+	   struct crypt_data * __restrict data)
+{
+  return __crypt_rn (key, salt, data, sizeof (*data));
+}
+weak_alias (__crypt_r, crypt_r)
+
+
+char *
+crypt (const char *key, const char *salt)
+{
+  return __crypt_r (key, salt, &_ufc_foobar);
+}
+
+
+char *
+__crypt_gensalt_rn (const char *prefix, unsigned long count,
+		    const char *input, int size, char *output,
+		    int output_size)
+{
+  char *(*use) (const char *prefix, unsigned long count, const char *input,
+		int size, char *output, int output_size);
+
+  /* This may be supported on some platforms in the future */
+  if (!input)
      {
        __set_errno (EINVAL);
        return NULL;
      }
  -  /* FIPS rules out DES password encryption.  */
-  if (fips_enabled_p ())
+  if (strncmp (prefix, blowfish_salt_prefix_a, sizeof 
(blowfish_salt_prefix_a) - 1) == 0 ||
+      strncmp (prefix, blowfish_salt_prefix_b, sizeof 
(blowfish_salt_prefix_b) - 1) == 0 ||
+      strncmp (prefix, blowfish_salt_prefix_x, sizeof 
(blowfish_salt_prefix_x) - 1) == 0 ||
+      strncmp (prefix, blowfish_salt_prefix_y, sizeof 
(blowfish_salt_prefix_y) - 1) == 0)
+    use = _crypt_gensalt_blowfish_rn;
+  else if (strncmp (prefix, md5_salt_prefix, sizeof (md5_salt_prefix) - 
1) == 0)
+    use = _crypt_gensalt_md5_rn;
+  else if (strncmp (prefix, sha256_salt_prefix, strlen 
(sha256_salt_prefix) - 1) == 0 ||
+	   strncmp (prefix, sha512_salt_prefix, strlen (sha512_salt_prefix) - 
1) == 0)
+    use = _crypt_gensalt_sha2_rn;
+  else if (strncmp (prefix, "_", 1) == 0)
+    use = _crypt_gensalt_extended_rn;
+  else if (!prefix[0] || (prefix[0] && prefix[1] &&
+                          memchr (_crypt_itoa64, prefix[0], 64) &&
+                          memchr (_crypt_itoa64, prefix[1], 64)))
+    use = _crypt_gensalt_traditional_rn;
+  else
      {
-      __set_errno (EPERM);
+      __set_errno (EINVAL);
        return NULL;
      }
  -  /*
-   * Setup key schedule
-   */
-  _ufc_clearmem (ktab, (int) sizeof (ktab));
-  (void) strncpy (ktab, key, 8);
-  _ufc_mk_keytab_r (ktab, data);
-
-  /*
-   * Go for the 25 DES encryptions
-   */
-  _ufc_clearmem ((char*) res, (int) sizeof (res));
-  _ufc_doit_r (xx,  data, &res[0]);
-
-  /*
-   * Do final permutations
-   */
-  _ufc_dofinalperm_r (res, data);
-
-  /*
-   * And convert back to 6 bit ASCII
-   */
-  _ufc_output_conversion_r (res[0], res[1], salt, data);
-
-  /*
-   * Erase key-dependent intermediate data.  Data dependent only on
-   * the salt is not considered sensitive.
-   */
-  explicit_bzero (ktab, sizeof (ktab));
-  explicit_bzero (data->keysched, sizeof (data->keysched));
-  explicit_bzero (res, sizeof (res));
-
-  return data->crypt_3_buf;
+  return use (prefix, count, input, size, output, output_size);
  }
-weak_alias (__crypt_r, crypt_r)
+weak_alias (__crypt_gensalt_rn, crypt_gensalt_rn)
+
   char *
-crypt (const char *key, const char *salt)
+__crypt_gensalt_ra (const char *prefix, unsigned long count,
+		    const char *input, int size)
  {
-#ifdef _LIBC
-  /* Try to find out whether we have to use MD5 encryption replacement.  */
-  if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0
-      /* Let __crypt_r deal with the error code if FIPS is enabled.  */
-      && !fips_enabled_p ())
-    return __md5_crypt (key, salt);
+  char output[CRYPT_GENSALT_OUTPUT_SIZE];
+  char *retval;
  -  /* Try to find out whether we have to use SHA256 encryption 
replacement.  */
-  if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 
1) == 0)
-    return __sha256_crypt (key, salt);
+  retval = __crypt_gensalt_rn (prefix, count, input, size,
+			       output, sizeof (output));
  -  /* Try to find out whether we have to use SHA512 encryption 
replacement.  */
-  if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 
1) == 0)
-    return __sha512_crypt (key, salt);
-#endif
+  if (retval)
+    {
+      retval = strdup (retval);
+    }
  -  return __crypt_r (key, salt, &_ufc_foobar);
+  return retval;
+}
+weak_alias (__crypt_gensalt_ra, crypt_gensalt_ra)
+
+
+char *
+__crypt_gensalt_r (const char *prefix, unsigned long count,
+		   const char *input, int size, char *output,
+		   int output_size)
+{
+  char *retval;
+
+  retval = __crypt_gensalt_rn (prefix, count, input, size,
+                               output, output_size);
+
+  if (retval)
+    {
+      retval = strdup (retval);
+    }
+
+  return retval;
+}
+weak_alias (__crypt_gensalt_r, crypt_gensalt_r)
+
+
+char *
+__crypt_gensalt (const char *prefix, unsigned long count,
+		 const char *input, int size)
+{
+  static char output[CRYPT_GENSALT_OUTPUT_SIZE];
+  char *retval;
+
+  retval = __crypt_gensalt_rn (prefix, count, input, size,
+                               output, sizeof (output));
+  if (retval)
+    {
+      retval = strdup (retval);
+    }
+
+  return retval;
  }
+weak_alias (__crypt_gensalt, crypt_gensalt)
    /*
diff --git a/crypt/crypt.h b/crypt/crypt.h
index 51d6e8f210..51b5eaf506 100644
--- a/crypt/crypt.h
+++ b/crypt/crypt.h
@@ -70,6 +70,32 @@  extern void encrypt_r (char *__glibc_block, int __edflag,
       __THROW __nonnull ((1, 3));
  #endif
  +extern char *crypt_rn (const char *__key, const char *__setting,
+		       void * __restrict __data, int __size)
+     __THROW __nonnull ((1, 2, 3));
+
+extern char *crypt_ra (const char *__key, const char *__setting,
+		       void ** __restrict __data, int *__size)
+     __THROW __nonnull ((1, 2, 3, 4));
+
+extern char *crypt_gensalt (const char *__prefix, unsigned long __count,
+			    const char *__input, int __size)
+     __THROW __nonnull ((1, 3));
+
+extern char *crypt_gensalt_r (const char *__prefix, unsigned long __count,
+			      const char *__input, int size, char *__output,
+			      int __output_size)
+     __THROW __nonnull ((1, 3, 5));
+
+extern char *crypt_gensalt_rn (const char *__prefix, unsigned long __count,
+			       const char *__input, int size, char *__output,
+			       int __output_size)
+     __THROW __nonnull ((1, 3, 5));
+
+extern char *crypt_gensalt_ra (const char *__prefix, unsigned long __count,
+			       const char *__input, int __size)
+     __THROW __nonnull ((1, 3));
+
  __END_DECLS
   #endif	/* crypt.h */
diff --git a/crypt/crypt_blowfish.c b/crypt/crypt_blowfish.c
new file mode 100644
index 0000000000..27eeb2a220
--- /dev/null
+++ b/crypt/crypt_blowfish.c
@@ -0,0 +1,904 @@ 
+/*
+ * The crypt_blowfish homepage is:
+ *
+ *	http://www.openwall.com/crypt/
+ *
+ * This code comes from John the Ripper password cracker, with reentrant
+ * and crypt(3) interfaces added, but optimizations specific to password
+ * cracking removed.
+ *
+ * Written by Solar Designer <solar at openwall.com> in 1998-2014.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the 
software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * It is my intent that you should be able to use this on your system,
+ * as part of a software package, or anywhere else to improve security,
+ * ensure compatibility, or for any other purpose.  I would appreciate
+ * it if you give credit where it is due and keep your modifications in
+ * the public domain as well, but I don't require that in order to let
+ * you place this code and any modifications you make under a license
+ * of your choice.
+ *
+ * This implementation is fully compatible with OpenBSD's bcrypt.c for 
prefix
+ * "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and 
it uses
+ * some of his ideas.  The password hashing algorithm was designed by David
+ * Mazieres <dm at lcs.mit.edu>.  For information on the level of
+ * compatibility for bcrypt hash prefixes other than "$2b$", please 
refer to
+ * the comments in BF_set_key() below and to the included crypt(3) man 
page.
+ *
+ * There's a paper on the algorithm that explains its design decisions:
+ *
+ *	http://www.usenix.org/events/usenix99/provos.html
+ *
+ * Some of the tricks in BF_ROUND might be inspired by Eric Young's
+ * Blowfish library (I can't be sure if I would think of something if I
+ * hadn't seen his code).
+ */
+
+#include <string.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+/* Just to make sure the prototypes match the actual definitions */
+#include "crypt_blowfish.h"
+
+#define BF_ASM				0
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__alpha__) || 
defined(__hppa__)
+#define BF_SCALE			1
+#else
+#define BF_SCALE			0
+#endif
+
+typedef unsigned int BF_word;
+typedef signed int BF_word_signed;
+
+/* Number of Blowfish rounds, this is also hardcoded into a few places */
+#define BF_N				16
+
+typedef BF_word BF_key[BF_N + 2];
+
+typedef struct {
+	BF_word S[4][0x100];
+	BF_key P;
+} BF_ctx;
+
+/*
+ * Magic IV for 64 Blowfish encryptions that we do at the end.
+ * The string is "OrpheanBeholderScryDoubt" on big-endian.
+ */
+static const BF_word BF_magic_w[6] = {
+	0x4F727068, 0x65616E42, 0x65686F6C,
+	0x64657253, 0x63727944, 0x6F756274
+};
+
+/*
+ * P-box and S-box tables initialized with digits of Pi.
+ */
+static const BF_ctx BF_init_state = {
+	{
+		{
+			0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+			0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+			0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+			0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+			0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+			0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+			0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+			0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+			0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+			0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+			0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+			0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+			0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+			0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+			0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+			0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+			0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+			0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+			0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+			0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+			0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+			0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+			0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+			0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+			0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+			0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+			0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+			0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+			0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+			0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+			0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+			0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+			0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+			0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+			0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+			0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+			0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+			0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+			0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+			0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+			0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+			0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+			0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+			0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+			0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+			0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+			0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+			0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+			0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+			0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+			0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+			0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+			0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+			0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+			0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+			0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+			0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+			0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+			0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+			0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+			0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+			0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+			0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+			0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
+		}, {
+			0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+			0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+			0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+			0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+			0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+			0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+			0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+			0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+			0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+			0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+			0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+			0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+			0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+			0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+			0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+			0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+			0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+			0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+			0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+			0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+			0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+			0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+			0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+			0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+			0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+			0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+			0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+			0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+			0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+			0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+			0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+			0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+			0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+			0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+			0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+			0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+			0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+			0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+			0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+			0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+			0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+			0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+			0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+			0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+			0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+			0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+			0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+			0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+			0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+			0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+			0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+			0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+			0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+			0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+			0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+			0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+			0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+			0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+			0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+			0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+			0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+			0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+			0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+			0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
+		}, {
+			0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+			0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+			0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+			0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+			0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+			0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+			0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+			0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+			0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+			0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+			0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+			0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+			0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+			0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+			0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+			0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+			0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+			0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+			0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+			0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+			0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+			0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+			0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+			0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+			0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+			0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+			0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+			0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+			0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+			0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+			0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+			0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+			0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+			0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+			0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+			0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+			0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+			0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+			0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+			0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+			0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+			0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+			0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+			0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+			0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+			0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+			0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+			0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+			0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+			0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+			0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+			0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+			0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+			0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+			0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+			0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+			0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+			0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+			0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+			0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+			0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+			0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+			0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+			0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
+		}, {
+			0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+			0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+			0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+			0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+			0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+			0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+			0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+			0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+			0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+			0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+			0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+			0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+			0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+			0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+			0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+			0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+			0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+			0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+			0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+			0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+			0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+			0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+			0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+			0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+			0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+			0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+			0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+			0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+			0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+			0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+			0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+			0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+			0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+			0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+			0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+			0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+			0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+			0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+			0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+			0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+			0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+			0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+			0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+			0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+			0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+			0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+			0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+			0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+			0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+			0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+			0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+			0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+			0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+			0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+			0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+			0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+			0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+			0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+			0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+			0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+			0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+			0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+			0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+			0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+		}
+	}, {
+		0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+		0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+		0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+		0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+		0x9216d5d9, 0x8979fb1b
+	}
+};
+
+static const unsigned char BF_itoa64[64 + 1] =
+	"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+static const unsigned char BF_atoi64[0x60] = {
+	64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
+	54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
+	64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
+	64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+	43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
+};
+
+#define BF_safe_atoi64(dst, src) \
+{ \
+	tmp = (unsigned char)(src); \
+	if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
+	tmp = BF_atoi64[tmp]; \
+	if (tmp > 63) return -1; \
+	(dst) = tmp; \
+}
+
+static int BF_decode(BF_word *dst, const char *src, int size)
+{
+	unsigned char *dptr = (unsigned char *)dst;
+	unsigned char *end = dptr + size;
+	const unsigned char *sptr = (const unsigned char *)src;
+	unsigned int tmp, c1, c2, c3, c4;
+
+	do {
+		BF_safe_atoi64(c1, *sptr++);
+		BF_safe_atoi64(c2, *sptr++);
+		*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
+		if (dptr >= end) break;
+
+		BF_safe_atoi64(c3, *sptr++);
+		*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
+		if (dptr >= end) break;
+
+		BF_safe_atoi64(c4, *sptr++);
+		*dptr++ = ((c3 & 0x03) << 6) | c4;
+	} while (dptr < end);
+
+	return 0;
+}
+
+static void BF_encode(char *dst, const BF_word *src, int size)
+{
+	const unsigned char *sptr = (const unsigned char *)src;
+	const unsigned char *end = sptr + size;
+	unsigned char *dptr = (unsigned char *)dst;
+	unsigned int c1, c2;
+
+	do {
+		c1 = *sptr++;
+		*dptr++ = BF_itoa64[c1 >> 2];
+		c1 = (c1 & 0x03) << 4;
+		if (sptr >= end) {
+			*dptr++ = BF_itoa64[c1];
+			break;
+		}
+
+		c2 = *sptr++;
+		c1 |= c2 >> 4;
+		*dptr++ = BF_itoa64[c1];
+		c1 = (c2 & 0x0f) << 2;
+		if (sptr >= end) {
+			*dptr++ = BF_itoa64[c1];
+			break;
+		}
+
+		c2 = *sptr++;
+		c1 |= c2 >> 6;
+		*dptr++ = BF_itoa64[c1];
+		*dptr++ = BF_itoa64[c2 & 0x3f];
+	} while (sptr < end);
+}
+
+static void BF_swap(BF_word *x, int count)
+{
+	static const int endianness_check = 1;
+	const char *is_little_endian = (char *)&endianness_check;
+	BF_word tmp;
+
+	if (*is_little_endian)
+	do {
+		tmp = *x;
+		tmp = (tmp << 16) | (tmp >> 16);
+		*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
+	} while (--count);
+}
+
+#if BF_SCALE
+/* Architectures which can shift addresses left by 2 bits with no extra 
cost */
+#define BF_ROUND(L, R, N) \
+	tmp1 = L & 0xFF; \
+	tmp2 = L >> 8; \
+	tmp2 &= 0xFF; \
+	tmp3 = L >> 16; \
+	tmp3 &= 0xFF; \
+	tmp4 = L >> 24; \
+	tmp1 = data.ctx.S[3][tmp1]; \
+	tmp2 = data.ctx.S[2][tmp2]; \
+	tmp3 = data.ctx.S[1][tmp3]; \
+	tmp3 += data.ctx.S[0][tmp4]; \
+	tmp3 ^= tmp2; \
+	R ^= data.ctx.P[N + 1]; \
+	tmp3 += tmp1; \
+	R ^= tmp3;
+#else
+/* Architectures with no complicated addressing modes supported */
+#define BF_INDEX(S, i) \
+	(*((BF_word *)(((unsigned char *)S) + (i))))
+#define BF_ROUND(L, R, N) \
+	tmp1 = L & 0xFF; \
+	tmp1 <<= 2; \
+	tmp2 = L >> 6; \
+	tmp2 &= 0x3FC; \
+	tmp3 = L >> 14; \
+	tmp3 &= 0x3FC; \
+	tmp4 = L >> 22; \
+	tmp4 &= 0x3FC; \
+	tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
+	tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
+	tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
+	tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
+	tmp3 ^= tmp2; \
+	R ^= data.ctx.P[N + 1]; \
+	tmp3 += tmp1; \
+	R ^= tmp3;
+#endif
+
+/*
+ * Encrypt one block, BF_N is hardcoded here.
+ */
+#define BF_ENCRYPT \
+	L ^= data.ctx.P[0]; \
+	BF_ROUND(L, R, 0); \
+	BF_ROUND(R, L, 1); \
+	BF_ROUND(L, R, 2); \
+	BF_ROUND(R, L, 3); \
+	BF_ROUND(L, R, 4); \
+	BF_ROUND(R, L, 5); \
+	BF_ROUND(L, R, 6); \
+	BF_ROUND(R, L, 7); \
+	BF_ROUND(L, R, 8); \
+	BF_ROUND(R, L, 9); \
+	BF_ROUND(L, R, 10); \
+	BF_ROUND(R, L, 11); \
+	BF_ROUND(L, R, 12); \
+	BF_ROUND(R, L, 13); \
+	BF_ROUND(L, R, 14); \
+	BF_ROUND(R, L, 15); \
+	tmp4 = R; \
+	R = L; \
+	L = tmp4 ^ data.ctx.P[BF_N + 1];
+
+#if BF_ASM
+#define BF_body() \
+	_BF_body_r(&data.ctx);
+#else
+#define BF_body() \
+	L = R = 0; \
+	ptr = data.ctx.P; \
+	do { \
+		ptr += 2; \
+		BF_ENCRYPT; \
+		*(ptr - 2) = L; \
+		*(ptr - 1) = R; \
+	} while (ptr < &data.ctx.P[BF_N + 2]); \
+\
+	ptr = data.ctx.S[0]; \
+	do { \
+		ptr += 2; \
+		BF_ENCRYPT; \
+		*(ptr - 2) = L; \
+		*(ptr - 1) = R; \
+	} while (ptr < &data.ctx.S[3][0xFF]);
+#endif
+
+static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
+    unsigned char flags)
+{
+	const char *ptr = key;
+	unsigned int bug, i, j;
+	BF_word safety, sign, diff, tmp[2];
+
+/*
+ * There was a sign extension bug in older revisions of this function. 
While
+ * we would have liked to simply fix the bug and move on, we have to 
provide
+ * a backwards compatibility feature (essentially the bug) for some 
systems and
+ * a safety measure for some others.  The latter is needed because for 
certain
+ * multiple inputs to the buggy algorithm there exist easily found 
inputs to
+ * the correct algorithm that produce the same hash.  Thus, we optionally
+ * deviate from the correct algorithm just enough to avoid such collisions.
+ * While the bug itself affected the majority of passwords containing
+ * characters with the 8th bit set (although only a percentage of those 
in a
+ * collision-producing way), the anti-collision safety measure affects
+ * only a subset of passwords containing the '\xff' character (not even 
all of
+ * those passwords, just some of them).  This character is not found in 
valid
+ * UTF-8 sequences and is rarely used in popular 8-bit character encodings.
+ * Thus, the safety measure is unlikely to cause much annoyance, and is a
+ * reasonable tradeoff to use when authenticating against existing 
hashes that
+ * are not reliably known to have been computed with the correct algorithm.
+ *
+ * We use an approach that tries to minimize side-channel leaks of password
+ * information - that is, we mostly use fixed-cost bitwise operations 
instead
+ * of branches or table lookups.  (One conditional branch based on password
+ * length remains.  It is not part of the bug aftermath, though, and is
+ * difficult and possibly unreasonable to avoid given the use of C 
strings by
+ * the caller, which results in similar timing leaks anyway.)
+ *
+ * For actual implementation, we set an array index in the variable "bug"
+ * (0 means no bug, 1 means sign extension bug emulation) and a flag in the
+ * variable "safety" (bit 16 is set when the safety measure is requested).
+ * Valid combinations of settings are:
+ *
+ * Prefix "$2a$": bug = 0, safety = 0x10000
+ * Prefix "$2b$": bug = 0, safety = 0
+ * Prefix "$2x$": bug = 1, safety = 0
+ * Prefix "$2y$": bug = 0, safety = 0
+ */
+	bug = (unsigned int)flags & 1;
+	safety = ((BF_word)flags & 2) << 15;
+
+	sign = diff = 0;
+
+	for (i = 0; i < BF_N + 2; i++) {
+		tmp[0] = tmp[1] = 0;
+		for (j = 0; j < 4; j++) {
+			tmp[0] <<= 8;
+			tmp[0] |= (unsigned char)*ptr; /* correct */
+			tmp[1] <<= 8;
+			tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
+/*
+ * Sign extension in the first char has no effect - nothing to 
overwrite yet,
+ * and those extra 24 bits will be fully shifted out of the 32-bit 
word.  For
+ * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
+ * extension in tmp[1] occurs.  Once this flag is set, it remains set.
+ */
+			if (j)
+				sign |= tmp[1] & 0x80;
+			if (!*ptr)
+				ptr = key;
+			else
+				ptr++;
+		}
+		diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
+
+		expanded[i] = tmp[bug];
+		initial[i] = BF_init_state.P[i] ^ tmp[bug];
+	}
+
+/*
+ * At this point, "diff" is zero iff the correct and buggy algorithms 
produced
+ * exactly the same result.  If so and if "sign" is non-zero, which 
indicates
+ * that there was a non-benign sign extension, this means that we have a
+ * collision between the correctly computed hash for this password and 
a set of
+ * passwords that could be supplied to the buggy algorithm.  Our safety 
measure
+ * is meant to protect from such many-buggy to one-correct collisions, by
+ * deviating from the correct algorithm in such cases.  Let's check for 
this.
+ */
+	diff |= diff >> 16; /* still zero iff exact match */
+	diff &= 0xffff; /* ditto */
+	diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
+	sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
+	sign &= ~diff & safety; /* action needed? */
+
+/*
+ * If we have determined that we need to deviate from the correct 
algorithm,
+ * flip bit 16 in initial expanded key.  (The choice of 16 is 
arbitrary, but
+ * let's stick to it now.  It came out of the approach we used above, 
and it's
+ * not any worse than any other choice we could make.)
+ *
+ * It is crucial that we don't do the same to the expanded key used in 
the main
+ * Eksblowfish loop.  By doing it to only one of these two, we deviate 
from a
+ * state that could be directly specified by a password to the buggy 
algorithm
+ * (and to the fully correct one as well, but that's a side-effect).
+ */
+	initial[0] ^= sign;
+}
+
+static const unsigned char flags_by_subtype[26] =
+	{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
+
+static char *BF_crypt(const char *key, const char *setting,
+	char *output, int size,
+	BF_word min)
+{
+#if BF_ASM
+	extern void _BF_body_r(BF_ctx *ctx);
+#endif
+	struct {
+		BF_ctx ctx;
+		BF_key expanded_key;
+		union {
+			BF_word salt[4];
+			BF_word output[6];
+		} binary;
+	} data;
+	BF_word L, R;
+	BF_word tmp1, tmp2, tmp3, tmp4;
+	BF_word *ptr;
+	BF_word count;
+	int i;
+
+	if (size < 7 + 22 + 31 + 1) {
+		__set_errno(ERANGE);
+		return NULL;
+	}
+
+	if (setting[0] != '$' ||
+	    setting[1] != '2' ||
+	    setting[2] < 'a' || setting[2] > 'z' ||
+	    !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
+	    setting[3] != '$' ||
+	    setting[4] < '0' || setting[4] > '3' ||
+	    setting[5] < '0' || setting[5] > '9' ||
+	    (setting[4] == '3' && setting[5] > '1') ||
+	    setting[6] != '$') {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+
+	count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
+	if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+	BF_swap(data.binary.salt, 4);
+
+	BF_set_key(key, data.expanded_key, data.ctx.P,
+	    flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
+
+	memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
+
+	L = R = 0;
+	for (i = 0; i < BF_N + 2; i += 2) {
+		L ^= data.binary.salt[i & 2];
+		R ^= data.binary.salt[(i & 2) + 1];
+		BF_ENCRYPT;
+		data.ctx.P[i] = L;
+		data.ctx.P[i + 1] = R;
+	}
+
+	ptr = data.ctx.S[0];
+	do {
+		ptr += 4;
+		L ^= data.binary.salt[(BF_N + 2) & 3];
+		R ^= data.binary.salt[(BF_N + 3) & 3];
+		BF_ENCRYPT;
+		*(ptr - 4) = L;
+		*(ptr - 3) = R;
+
+		L ^= data.binary.salt[(BF_N + 4) & 3];
+		R ^= data.binary.salt[(BF_N + 5) & 3];
+		BF_ENCRYPT;
+		*(ptr - 2) = L;
+		*(ptr - 1) = R;
+	} while (ptr < &data.ctx.S[3][0xFF]);
+
+	do {
+		int done;
+
+		for (i = 0; i < BF_N + 2; i += 2) {
+			data.ctx.P[i] ^= data.expanded_key[i];
+			data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
+		}
+
+		done = 0;
+		do {
+			BF_body();
+			if (done)
+				break;
+			done = 1;
+
+			tmp1 = data.binary.salt[0];
+			tmp2 = data.binary.salt[1];
+			tmp3 = data.binary.salt[2];
+			tmp4 = data.binary.salt[3];
+			for (i = 0; i < BF_N; i += 4) {
+				data.ctx.P[i] ^= tmp1;
+				data.ctx.P[i + 1] ^= tmp2;
+				data.ctx.P[i + 2] ^= tmp3;
+				data.ctx.P[i + 3] ^= tmp4;
+			}
+			data.ctx.P[16] ^= tmp1;
+			data.ctx.P[17] ^= tmp2;
+		} while (1);
+	} while (--count);
+
+	for (i = 0; i < 6; i += 2) {
+		L = BF_magic_w[i];
+		R = BF_magic_w[i + 1];
+
+		count = 64;
+		do {
+			BF_ENCRYPT;
+		} while (--count);
+
+		data.binary.output[i] = L;
+		data.binary.output[i + 1] = R;
+	}
+
+	memcpy(output, setting, 7 + 22 - 1);
+	output[7 + 22 - 1] = BF_itoa64[(int)
+		BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
+
+/* This has to be bug-compatible with the original implementation, so
+ * only encode 23 of the 24 bytes. :-) */
+	BF_swap(data.binary.output, 6);
+	BF_encode(&output[7 + 22], data.binary.output, 23);
+	output[7 + 22 + 31] = '\0';
+
+	return output;
+}
+
+int _crypt_output_magic(const char *setting, char *output, int size)
+{
+	if (size < 3)
+		return -1;
+
+	output[0] = '*';
+	output[1] = '0';
+	output[2] = '\0';
+
+	if (setting[0] == '*' && setting[1] == '0')
+		output[1] = '1';
+
+	return 0;
+}
+
+/*
+ * Please preserve the runtime self-test.  It serves two purposes at once:
+ *
+ * 1. We really can't afford the risk of producing incompatible hashes e.g.
+ * when there's something like gcc bug 26587 again, whereas an 
application or
+ * library integrating this code might not also integrate our external 
tests or
+ * it might not run them after every build.  Even if it does, the 
miscompile
+ * might only occur on the production build, but not on a testing build 
(such
+ * as because of different optimization settings).  It is painful to 
recover
+ * from incorrectly-computed hashes - merely fixing whatever broke is not
+ * enough.  Thus, a proactive measure like this self-test is needed.
+ *
+ * 2. We don't want to leave sensitive data from our actual password hash
+ * computation on the stack or in registers.  Previous revisions of the 
code
+ * would do explicit cleanups, but simply running the self-test after hash
+ * computation is more reliable.
+ *
+ * The performance cost of this quick self-test is around 0.6% at the 
"$2a$08"
+ * setting.
+ */
+char *_crypt_blowfish_rn(const char *key, const char *setting,
+	char *output, int size)
+{
+	const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
+	const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
+	static const char * const test_hashes[2] =
+		{"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */
+		"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */
+	const char *test_hash = test_hashes[0];
+	char *retval;
+	const char *p;
+	int save_errno, ok;
+	struct {
+		char s[7 + 22 + 1];
+		char o[7 + 22 + 31 + 1 + 1 + 1];
+	} buf;
+
+/* Hash the supplied password */
+	_crypt_output_magic(setting, output, size);
+	retval = BF_crypt(key, setting, output, size, 16);
+	save_errno = errno;
+
+/*
+ * Do a quick self-test.  It is important that we make both calls to 
BF_crypt()
+ * from the same scope such that they likely use the same stack locations,
+ * which makes the second call overwrite the first call's sensitive 
data on the
+ * stack and makes it more likely that any alignment related issues 
would be
+ * detected by the self-test.
+ */
+	memcpy(buf.s, test_setting, sizeof(buf.s));
+	if (retval) {
+		unsigned int flags = flags_by_subtype[
+		    (unsigned int)(unsigned char)setting[2] - 'a'];
+		test_hash = test_hashes[flags & 1];
+		buf.s[2] = setting[2];
+	}
+	memset(buf.o, 0x55, sizeof(buf.o));
+	buf.o[sizeof(buf.o) - 1] = 0;
+	p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
+
+	ok = (p == buf.o &&
+	    !memcmp(p, buf.s, 7 + 22) &&
+	    !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1));
+
+	{
+		const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
+		BF_key ae, ai, ye, yi;
+		BF_set_key(k, ae, ai, 2); /* $2a$ */
+		BF_set_key(k, ye, yi, 4); /* $2y$ */
+		ai[0] ^= 0x10000; /* undo the safety (for comparison) */
+		ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
+		    !memcmp(ae, ye, sizeof(ae)) &&
+		    !memcmp(ai, yi, sizeof(ai));
+	}
+
+	__set_errno(save_errno);
+	if (ok)
+		return retval;
+
+/* Should not happen */
+	_crypt_output_magic(setting, output, size);
+	__set_errno(EINVAL); /* pretend we don't support this hash type */
+	return NULL;
+}
+
+char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	if (size < 16 || output_size < 7 + 22 + 1 ||
+	    (count && (count < 4 || count > 31)) ||
+	    prefix[0] != '$' || prefix[1] != '2' ||
+	    (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	if (!count) count = 5;
+
+	output[0] = '$';
+	output[1] = '2';
+	output[2] = prefix[2];
+	output[3] = '$';
+	output[4] = '0' + count / 10;
+	output[5] = '0' + count % 10;
+	output[6] = '$';
+
+	BF_encode(&output[7], (const BF_word *)input, 16);
+	output[7 + 22] = '\0';
+
+	return output;
+}
diff --git a/crypt/crypt_blowfish.h b/crypt/crypt_blowfish.h
new file mode 100644
index 0000000000..468a58e468
--- /dev/null
+++ b/crypt/crypt_blowfish.h
@@ -0,0 +1,30 @@ 
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the 
software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifndef _CRYPT_BLOWFISH_H
+#define _CRYPT_BLOWFISH_H
+
+#define CRYPT_OUTPUT_SIZE         (7 + 22 + 31 + 1)
+#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
+
+extern const int _crypt_output_magic(const char *setting, char *output, 
int size);
+extern char *_crypt_blowfish_rn(const char *key, const char *setting,
+	char *output, int size);
+extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+
+#endif
diff --git a/crypt/crypt_gensalt.c b/crypt/crypt_gensalt.c
new file mode 100644
index 0000000000..cba2c54e01
--- /dev/null
+++ b/crypt/crypt_gensalt.c
@@ -0,0 +1,183 @@ 
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the 
software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ *
+ * This file contains salt generation functions for the traditional and
+ * other common crypt(3) algorithms, except for bcrypt which is defined
+ * entirely in crypt_blowfish.c.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+/* Just to make sure the prototypes match the actual definitions */
+#include "crypt_gensalt.h"
+
+unsigned char _crypt_itoa64[64 + 1] =
+	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long 
count,
+	const char *input, int size, char *output, int output_size)
+{
+	(void) prefix;
+
+	if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
+	output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
+	output[2] = '\0';
+
+	return output;
+}
+
+char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	unsigned long value;
+
+	(void) prefix;
+
+/* Even iteration counts make it easier to detect weak DES keys from a look
+ * at the hash, so they should be avoided */
+	if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
+	    (count && (count > 0xffffff || !(count & 1)))) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	if (!count) count = 725;
+
+	output[0] = '_';
+	output[1] = _crypt_itoa64[count & 0x3f];
+	output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
+	output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
+	output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
+	value = (unsigned long)(unsigned char)input[0] |
+		((unsigned long)(unsigned char)input[1] << 8) |
+		((unsigned long)(unsigned char)input[2] << 16);
+	output[5] = _crypt_itoa64[value & 0x3f];
+	output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
+	output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
+	output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
+	output[9] = '\0';
+
+	return output;
+}
+
+char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	unsigned long value;
+
+	(void) prefix;
+
+	if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	output[0] = '$';
+	output[1] = '1';
+	output[2] = '$';
+	value = (unsigned long)(unsigned char)input[0] |
+		((unsigned long)(unsigned char)input[1] << 8) |
+		((unsigned long)(unsigned char)input[2] << 16);
+	output[3] = _crypt_itoa64[value & 0x3f];
+	output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
+	output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
+	output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
+	output[7] = '\0';
+
+	if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
+		value = (unsigned long)(unsigned char)input[3] |
+			((unsigned long)(unsigned char)input[4] << 8) |
+			((unsigned long)(unsigned char)input[5] << 16);
+		output[7] = _crypt_itoa64[value & 0x3f];
+		output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
+		output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
+		output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
+		output[11] = '\0';
+	}
+
+	return output;
+}
+
+#define SHA2_SALT_LEN_MAX 16
+#define SHA2_ROUNDS_MIN   1000
+#define SHA2_ROUNDS_MAX   999999999
+
+char *_crypt_gensalt_sha2_rn (const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+
+{
+	char *o = output;
+	const char *i = input;
+	unsigned needed = 3 + MIN(size/3*4, SHA2_SALT_LEN_MAX) + 1;
+
+	if (size < 3 || output_size < needed)
+		goto error;
+
+	size = MIN(size, SHA2_SALT_LEN_MAX/4*3);
+
+	o[0] = prefix[0];
+	o[1] = prefix[1];
+	o[2] = prefix[2];
+	o += 3;
+
+	if (count) {
+		count = MAX(SHA2_ROUNDS_MIN, MIN(count, SHA2_ROUNDS_MAX));
+		int n = snprintf (o, output_size-3, "rounds=%ld$", count);
+		if (n < 0 || n >= output_size-3)
+			goto error;
+		needed += n;
+		o += n;
+	}
+
+	if (output_size < needed)
+		goto error;
+
+	while (size >= 3) {
+		unsigned long value =
+			(unsigned long)(unsigned char)i[0] |
+			((unsigned long)(unsigned char)i[1] << 8) |
+			((unsigned long)(unsigned char)i[2] << 16);
+		o[0] = _crypt_itoa64[value & 0x3f];
+		o[1] = _crypt_itoa64[(value >> 6) & 0x3f];
+		o[2] = _crypt_itoa64[(value >> 12) & 0x3f];
+		o[3] = _crypt_itoa64[(value >> 18) & 0x3f];
+		size -= 3;
+		i += 3;
+		o += 3;
+	}
+	o[0] = '\0';
+
+	return output;
+
+error:
+	if (output_size > 0)
+		output[0] = '\0';
+	errno = ENOMEM;
+	return NULL;
+}
diff --git a/crypt/crypt_gensalt.h b/crypt/crypt_gensalt.h
new file mode 100644
index 0000000000..dac484f0cc
--- /dev/null
+++ b/crypt/crypt_gensalt.h
@@ -0,0 +1,31 @@ 
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the 
software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifndef _CRYPT_GENSALT_H
+#define _CRYPT_GENSALT_H
+
+extern unsigned char _crypt_itoa64[];
+extern char *_crypt_gensalt_traditional_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+extern char *_crypt_gensalt_extended_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size);
+extern char *_crypt_gensalt_sha2_rn(const char *prefix, unsigned long 
count,
+	const char *input, int size, char *output, int output_size);
+#endif
diff --git a/crypt/des-crypt.c b/crypt/des-crypt.c
new file mode 100644
index 0000000000..38c18dc6c3
--- /dev/null
+++ b/crypt/des-crypt.c
@@ -0,0 +1,106 @@ 
+/*
+ * UFC-crypt: ultra fast crypt(3) implementation
+ *
+ * Copyright (C) 1991-2016 Free Software Foundation, Inc.
+ *
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the GNU C Library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * des crypt algorithm
+ *
+ * @(#)des-crypt.c	1.2 12/20/96
+ *
+ */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <fips-private.h>
+
+#ifndef STATIC
+#define STATIC static
+#endif
+
+#include "crypt-private.h"
+
+/* Prototypes for local functions.  */
+#ifndef __GNU_LIBRARY__
+void _ufc_clearmem (char *start, int cnt);
+#else
+#define _ufc_clearmem(start, cnt)   memset(start, 0, cnt)
+#endif
+
+/*
+ * UNIX des crypt function
+ */
+
+char *
+__des_crypt_r (const char *__key, const char *__salt,
+	   struct crypt_data * __restrict __data)
+{
+  ufc_long res[4];
+  char ktab[9];
+  ufc_long xx = 25; /* to cope with GCC long long compiler bugs */
+
+  /*
+   * Hack DES tables according to salt
+   */
+  if (!_ufc_setup_salt_r (__salt, __data))
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  /* FIPS rules out DES password encryption.  */
+  if (fips_enabled_p ())
+    {
+      __set_errno (EPERM);
+      return NULL;
+    }
+
+  /*
+   * Setup key schedule
+   */
+  _ufc_clearmem (ktab, (int) sizeof (ktab));
+  (void) strncpy (ktab, __key, 8);
+  _ufc_mk_keytab_r (ktab, __data);
+
+  /*
+   * Go for the 25 DES encryptions
+   */
+  _ufc_clearmem ((char*) res, (int) sizeof (res));
+  _ufc_doit_r (xx,  __data, &res[0]);
+
+  /*
+   * Do final permutations
+   */
+  _ufc_dofinalperm_r (res, __data);
+
+  /*
+   * And convert back to 6 bit ASCII
+   */
+  _ufc_output_conversion_r (res[0], res[1], __salt, __data);
+
+  /*
+   * Erase key-dependent intermediate data.  Data dependent only on
+   * the salt is not considered sensitive.
+   */
+  explicit_bzero (ktab, sizeof (ktab));
+  explicit_bzero (__data->keysched, sizeof (__data->keysched));
+  explicit_bzero (res, sizeof (res));
+
+  return __data->crypt_3_buf;
+}
diff --git a/crypt/gensalt-test.c b/crypt/gensalt-test.c
new file mode 100644
index 0000000000..96a448a7d2
--- /dev/null
+++ b/crypt/gensalt-test.c
@@ -0,0 +1,109 @@ 
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#include "crypt.h"
+
+#ifndef RANDOM_DEVICE
+#define RANDOM_DEVICE "/dev/urandom"
+#endif
+
+static int
+read_loop (int fd, char *buffer, int count)
+{
+  int offset, block;
+
+  offset = 0;
+  while (count > 0)
+    {
+      block = read(fd, &buffer[offset], count);
+
+      if (block < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          return block;
+        }
+      if (!block)
+        return offset;
+
+      offset += block;
+      count -= block;
+    }
+
+  return offset;
+}
+
+static char *
+make_crypt_salt (const char *crypt_prefix, int crypt_rounds)
+{
+#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
+  int fd;
+  char entropy[16];
+  char *retval;
+  char output[CRYPT_GENSALT_OUTPUT_SIZE];
+
+  fd = open (RANDOM_DEVICE, O_RDONLY);
+  if (fd < 0)
+    {
+      fprintf (stderr, "Can't open %s for reading: %s\n",
+	       RANDOM_DEVICE, strerror (errno));
+      return NULL;
+    }
+
+  if (read_loop (fd, entropy, sizeof(entropy)) != sizeof(entropy))
+    {
+      close (fd);
+      fprintf (stderr, "Unable to obtain entropy from %s\n",
+	       RANDOM_DEVICE);
+      return NULL;
+    }
+
+  close (fd);
+
+  retval = crypt_gensalt_r (crypt_prefix, crypt_rounds, entropy,
+                            sizeof (entropy), output, sizeof(output));
+
+  memset (entropy, 0, sizeof (entropy));
+
+  if (!retval)
+    {
+      fprintf (stderr,
+	       "Unable to generate a salt, check your crypt settings.\n");
+      return NULL;
+    }
+
+  return strdup (retval);
+}
+
+static const char *salt_input[] =
+  { "", "$1$", "$2a$" , "$5$", "$6$" };
+
+int
+main(void)
+{
+  int i;
+
+  for (i = 0; i < (int) (sizeof (salt_input) / sizeof (salt_input[0])); 
i++)
+    {
+      char *salt = make_crypt_salt (salt_input[i], 0);
+
+      if (salt_input[i][0] != '\0')
+	{
+	  if (strncmp (salt_input[i], salt, strlen (salt_input[i])) != 0)
+	    {
+	      fprintf (stderr, "ERROR: input=%s, output=%s\n",
+		       salt_input[i], salt);
+	      return 1;
+	    }
+	}
+    }
+
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist
index 58944b3d83..9ade9d5b92 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.17 encrypt_r F
  GLIBC_2.17 fcrypt F
  GLIBC_2.17 setkey F
  GLIBC_2.17 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/alpha/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/alpha/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/alpha/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/arm/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/arm/libcrypt.abilist
index 04f1f02fa3..33c92c22cd 100644
--- a/sysdeps/unix/sysv/linux/arm/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.4 encrypt_r F
  GLIBC_2.4 fcrypt F
  GLIBC_2.4 setkey F
  GLIBC_2.4 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/hppa/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/hppa/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/hppa/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/i386/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/i386/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/i386/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/ia64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/ia64/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/ia64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist
index 04f1f02fa3..33c92c22cd 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.4 encrypt_r F
  GLIBC_2.4 fcrypt F
  GLIBC_2.4 setkey F
  GLIBC_2.4 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist
index 75fa78890a..34111b9683 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.18 encrypt_r F
  GLIBC_2.18 fcrypt F
  GLIBC_2.18 setkey F
  GLIBC_2.18 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist
index c9d2e54530..cfe4332dd6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libcrypt.abilist
@@ -6,4 +6,11 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
  _gp_disp _gp_disp A
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/nios2/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/nios2/libcrypt.abilist
index dae6b522ac..b548f01179 100644
--- a/sysdeps/unix/sysv/linux/nios2/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.21 encrypt_r F
  GLIBC_2.21 fcrypt F
  GLIBC_2.21 setkey F
  GLIBC_2.21 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git 
a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist 
b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist
index 58944b3d83..9ade9d5b92 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt-le.abilist
@@ -6,3 +6,10 @@  GLIBC_2.17 encrypt_r F
  GLIBC_2.17 fcrypt F
  GLIBC_2.17 setkey F
  GLIBC_2.17 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist
index 52cf1ac766..1fe26af339 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.3 encrypt_r F
  GLIBC_2.3 fcrypt F
  GLIBC_2.3 setkey F
  GLIBC_2.3 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist
index f2854f3a0a..42b6f6fda9 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.2 encrypt_r F
  GLIBC_2.2 fcrypt F
  GLIBC_2.2 setkey F
  GLIBC_2.2 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/sh/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/sh/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/sh/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist
index 4db2639336..e9c1f50e87 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.0 encrypt_r F
  GLIBC_2.0 fcrypt F
  GLIBC_2.0 setkey F
  GLIBC_2.0 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git 
a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist
index d5643802b7..db386a0da7 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.12 encrypt_r F
  GLIBC_2.12 fcrypt F
  GLIBC_2.12 setkey F
  GLIBC_2.12 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git 
a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist
index d5643802b7..db386a0da7 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.12 encrypt_r F
  GLIBC_2.12 fcrypt F
  GLIBC_2.12 setkey F
  GLIBC_2.12 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist
index d5643802b7..db386a0da7 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.12 encrypt_r F
  GLIBC_2.12 fcrypt F
  GLIBC_2.12 setkey F
  GLIBC_2.12 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist
index df20c0f259..182de51bfd 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.2.5 encrypt_r F
  GLIBC_2.2.5 fcrypt F
  GLIBC_2.2.5 setkey F
  GLIBC_2.2.5 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist 
b/sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist
index d0f5c3b25d..e7fb813697 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libcrypt.abilist
@@ -6,3 +6,10 @@  GLIBC_2.16 encrypt_r F
  GLIBC_2.16 fcrypt F
  GLIBC_2.16 setkey F
  GLIBC_2.16 setkey_r F
+GLIBC_2.26 GLIBC_2.26 A
+GLIBC_2.26 crypt_gensalt F
+GLIBC_2.26 crypt_gensalt_r F
+GLIBC_2.26 crypt_gensalt_ra F
+GLIBC_2.26 crypt_gensalt_rn F
+GLIBC_2.26 crypt_ra F
+GLIBC_2.26 crypt_rn F