[crypt - a library implementing the hopelessly outdated 56 bit DES encryption] branch master, updated. 77fe77f090be305171dc5adcc6720b793e3e184b

yselkowitz-9JcytcrH/[email protected]
Newsgroups gmane.os.cygwin.cvs.apps
Message-ID <[email protected]>


https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=77fe77f090be305171dc5adcc6720b793e3e184b

commit 77fe77f090be305171dc5adcc6720b793e3e184b
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:49:40 2017 -0500

    Add .gitignore

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=85b161ed37742b570ed03cc0984cacfb391eda14

commit 85b161ed37742b570ed03cc0984cacfb391eda14
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:49:21 2017 -0500

    Update README

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=6f936d0128f32320957d0e1d5488c4eb03967f7f

commit 6f936d0128f32320957d0e1d5488c4eb03967f7f
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:41:29 2017 -0500

    Update Makefile

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=5782c473ae3440d44eca8e91afd82cb7798b27b2

commit 5782c473ae3440d44eca8e91afd82cb7798b27b2
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:37:37 2017 -0500

    Guard GNU extensions in header, declare other functions

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=d9b5c092d670d526900161bddc05d4c499c59ba8

commit d9b5c092d670d526900161bddc05d4c499c59ba8
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:37:12 2017 -0500

    Export crypt_r

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=5d1a6930db02b1eb2b238cf809291d29c2513e07

commit 5d1a6930db02b1eb2b238cf809291d29c2513e07
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 21:36:46 2017 -0500

    Port sources to Cygwin

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/crypt.git;h=b736f34a81dcc7bdc94677f7d366b2a0128956a8

commit b736f34a81dcc7bdc94677f7d366b2a0128956a8
Author: Yaakov Selkowitz <[email protected]>
Date:   Thu Aug 3 01:01:30 2017 -0500

    Import musl sources


Diff:
---
 .gitignore       |    4 +
 COPYRIGHT        |  163 +++++++++
 Makefile         |   30 +-
 crypt.README     |   32 +--
 crypt.c          |   44 +--
 crypt.def        |    1 +
 crypt.h          |   27 ++
 crypt_blowfish.c |  798 ++++++++++++++++++++++++++++++++++++++++++
 crypt_des.c      | 1018 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 crypt_md5.c      |  285 +++++++++++++++
 crypt_r.c        |   29 ++
 crypt_sha256.c   |  322 +++++++++++++++++
 crypt_sha512.c   |  371 ++++++++++++++++++++
 encrypt.c        |  343 +++----------------
 encrypt.h        |   35 --
 15 files changed, 3089 insertions(+), 413 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..359ff5e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+cygcrypt-0.dll
+libcrypt.a
+libcrypt.dll.a
+*.o
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..f0ee3b7
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,163 @@
+musl as a whole is licensed under the following standard MIT license:
+
+----------------------------------------------------------------------
+Copyright © 2005-2014 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+----------------------------------------------------------------------
+
+Authors/contributors include:
+
+Alex Dowad
+Alexander Monakov
+Anthony G. Basile
+Arvid Picciani
+Bobby Bingham
+Boris Brezillon
+Brent Cook
+Chris Spiegel
+Clément Vasseur
+Daniel Micay
+Denys Vlasenko
+Emil Renner Berthing
+Felix Fietkau
+Felix Janda
+Gianluca Anzolin
+Hauke Mehrtens
+Hiltjo Posthuma
+Isaac Dunham
+Jaydeep Patil
+Jens Gustedt
+Jeremy Huntwork
+Jo-Philipp Wich
+Joakim Sindholt
+John Spencer
+Josiah Worcester
+Justin Cormack
+Khem Raj
+Kylie McClain
+Luca Barbato
+Luka Perkov
+M Farkas-Dyck (Strake)
+Mahesh Bodapati
+Michael Forney
+Natanael Copa
+Nicholas J. Kain
+orc
+Pascal Cuoq
+Petr Hosek
+Pierre Carrier
+Rich Felker
+Richard Pennington
+Shiz
+sin
+Solar Designer
+Stefan Kristiansson
+Szabolcs Nagy
+Timo Teräs
+Trutz Behn
+Valentin Ochs
+William Haddon
+
+Portions of this software are derived from third-party works licensed
+under terms compatible with the above MIT license:
+
+The TRE regular expression implementation (src/regex/reg* and
+src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
+under a 2-clause BSD license (license text in the source files). The
+included version has been heavily modified by Rich Felker in 2012, in
+the interests of size, simplicity, and namespace cleanliness.
+
+Much of the math library code (src/math/* and src/complex/*) is
+Copyright © 1993,2004 Sun Microsystems or
+Copyright © 2003-2011 David Schultz or
+Copyright © 2003-2009 Steven G. Kargl or
+Copyright © 2003-2009 Bruce D. Evans or
+Copyright © 2008 Stephen L. Moshier
+and labelled as such in comments in the individual source files. All
+have been licensed under extremely permissive terms.
+
+The ARM memcpy code (src/string/arm/memcpy_el.S) is Copyright © 2008
+The Android Open Source Project and is licensed under a two-clause BSD
+license. It was taken from Bionic libc, used on Android.
+
+The implementation of DES for crypt (src/crypt/crypt_des.c) is
+Copyright © 1994 David Burren. It is licensed under a BSD license.
+
+The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
+originally written by Solar Designer and placed into the public
+domain. The code also comes with a fallback permissive license for use
+in jurisdictions that may not recognize the public domain.
+
+The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
+Valentin Ochs and is licensed under an MIT-style license.
+
+The BSD PRNG implementation (src/prng/random.c) and XSI search API
+(src/search/*.c) functions are Copyright © 2011 Szabolcs Nagy and
+licensed under following terms: "Permission to use, copy, modify,
+and/or distribute this code for any purpose with or without fee is
+hereby granted. There is no warranty."
+
+The x86_64 port was written by Nicholas J. Kain and is licensed under
+the standard MIT terms.
+
+The mips and microblaze ports were originally written by Richard
+Pennington for use in the ellcc project. The original code was adapted
+by Rich Felker for build system and code conventions during upstream
+integration. It is licensed under the standard MIT terms.
+
+The mips64 port was contributed by Imagination Technologies and is
+licensed under the standard MIT terms.
+
+The powerpc port was also originally written by Richard Pennington,
+and later supplemented and integrated by John Spencer. It is licensed
+under the standard MIT terms.
+
+All other files which have no copyright comments are original works
+produced specifically for use as part of this library, written either
+by Rich Felker, the main author of the library, or by one or more
+contibutors listed above. Details on authorship of individual files
+can be found in the git version control history of the project. The
+omission of copyright and license comments in each file is in the
+interest of source tree size.
+
+In addition, permission is hereby granted for all public header files
+(include/* and arch/*/bits/*) and crt files intended to be linked into
+applications (crt/*, ldso/dlstart.c, and arch/*/crt_arch.h) to omit
+the copyright notice and permission notice otherwise required by the
+license, and to use these files without any requirement of
+attribution. These files include substantial contributions from:
+
+Bobby Bingham
+John Spencer
+Nicholas J. Kain
+Rich Felker
+Richard Pennington
+Stefan Kristiansson
+Szabolcs Nagy
+
+all of whom have explicitly granted such permission.
+
+This file previously contained text expressing a belief that most of
+the files covered by the above exception were sufficiently trivial not
+to be subject to copyright, resulting in confusion over whether it
+negated the permissions granted in the license. In the spirit of
+permissive licensing, and of not having licensing issues being an
+obstacle to adoption, that text has been removed.
diff --git a/Makefile b/Makefile
index 846ca2c..ee8d07b 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
 CC ?= gcc
 AR ?= ar
 CFLAGS ?= -g -O2
+CPPFLAGS = -I. -D_GNU_SOURCE
 
 prefix:=/usr
 bindir=$(prefix)/bin
@@ -9,43 +10,40 @@ libdir=$(prefix)/lib
 incdir=$(prefix)/include
 docdir=$(prefix)/share/doc/Cygwin
 DLLVER=0
-EXE=.exe
 
 STATICLIB=libcrypt.a
 SHAREDLIB=cygcrypt-$(DLLVER).dll
 IMPORTLIB=libcrypt.dll.a
 
-APPS=crypt$(EXE)
 LIBS=$(STATICLIB) $(SHAREDLIB)
 
-all: $(APPS) $(LIBS)
+SRCS=crypt.c crypt_blowfish.c crypt_des.c crypt_md5.c crypt_r.c \
+     crypt_sha256.c crypt_sha512.c encrypt.c
+OBJS=$(SRCS:.c=.o)
 
-crypt$(EXE): crypt.o $(LIBS)
-	$(CC) -o $@ crypt.o -L. -lcrypt
+all: $(LIBS)
 
-$(STATICLIB): encrypt.o
-	$(AR) rv $@ encrypt.o
+$(STATICLIB): $(OBJS)
+	$(AR) rv $@ $^
 
-$(SHAREDLIB): encrypt.o
-	$(CC) -shared -Wl,--enable-auto-image-base \
-	      -Wl,--gc-sections -Wl,--out-implib=$(IMPORTLIB) \
-	      crypt.def \
-	      $^ -o $@
+$(SHAREDLIB): $(OBJS) crypt.def
+	$(CC) -shared -Wl,--gc-sections -Wl,--out-implib=$(IMPORTLIB) $^ -o $@
 
-encrypt.o: encrypt.h
+crypt.o: crypt.h
+
+crypt_r.o: crypt.h
 
 distclean: clean
 
 clean:
-	-rm *.o *.exe *.a *.dll
+	-rm *.o *.a *.dll
 
 install: all
 	install -d $(DESTDIR)$(bindir)
 	install -d $(DESTDIR)$(libdir)
 	install -d $(DESTDIR)$(incdir)
 	install -d $(DESTDIR)$(docdir)
-	install -m 755 $(APPS)         $(DESTDIR)$(bindir)
-	install -m 644 encrypt.h       $(DESTDIR)$(incdir)/crypt.h
+	install -m 644 crypt.h         $(DESTDIR)$(incdir)/crypt.h
 	install -m 644 $(STATICLIB)    $(DESTDIR)$(libdir)
 	install -m 644 $(IMPORTLIB)    $(DESTDIR)$(libdir)
 	install -m 755 $(SHAREDLIB)    $(DESTDIR)$(bindir)
diff --git a/crypt.README b/crypt.README
index e20aff8..0467dc1 100644
--- a/crypt.README
+++ b/crypt.README
@@ -1,39 +1,17 @@
-This is the DES-crypt package Version 1.4
+This is the crypt package Version 2.0
 
 It provides a static library libcrypt.a as well as a shared library
 cygcrypt-0.dll together with a link lib libcrypt.dll.a, which export
 the functions
 
         crypt(3)
+        crypt_r(3)
         encrypt(3)
         setkey(3)
 
-The passwords created by crypt(3) are 56 bit DES encrypted and are
-100% identical to those created by the Linux crypt().
-
-Additionally, this package provides a command line tool crypt.exe 
-which is a tool to generate encrypted passwords from cleartext
-passwords.  The encrypted password is written to stdout with a trailing
-line feed. 
-
-Note that this tool does *not* provide the crypt(1) functionality known
-from e. g. SUN Solaris(tm) machines.  The encryption used here is
-incompatible with the encryption used there.
-
-The usage of "our" crypt is like this:
-
-crypt cleartext
-
-    generates a password with a random salt.
-
-crypt salt cleartext
-
-    generates a password with salt `salt'.  The result can be used to
-    compare a given encrypted password with a cleartext password eg.
-    typed by a user.
-
-The salt is a two character string which consists of the first two
-characters of the encrypted password.
+The passwords created by crypt(3) are 100% identical to those created by 
+the Linux crypt().  DES, MD5, Blowfish, SHA-256, and SHA-512 algorithms are 
+supported.
 
 Please send requests, error reports etc. to the mailing list
 [email protected]
diff --git a/crypt.c b/crypt.c
index bfc56be..4650073 100644
--- a/crypt.c
+++ b/crypt.c
@@ -1,36 +1,16 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "encrypt.h"
+#include <unistd.h>
+#include <crypt.h>
 
-const char *sc = "./"
-                 "01234567890"
-                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                 "abcdefghijklmnopqrstuvwxyz";
+char *__crypt_r(const char *, const char *, struct crypt_data *);
 
-int
-main (int argc, const char **argv)
+char *crypt(const char *key, const char *salt)
 {
-  char salt[3];
-
-  if (argc == 2)
-    {
-      srand (time (NULL));
-      salt[0] = sc[(rand() & 0x7e) >> 1];
-      salt[1] = sc[(rand() & 0x7e) >> 1];
-      salt[2] = '\0';
-      printf ("%s\n", crypt (argv[1], salt));
-      return 0;
-    }
-  if (argc == 3)
-    {
-      salt[0] = '\0';
-      strncat (salt, argv[1], 2);
-      printf ("%s\n", crypt (argv[2], salt));
-      return 0;
-    }
-  fprintf (stderr, "usage: %s passwd\n"
-                   "       %s salt passwd\n", argv[0], argv[0]);
-  return 1;
+	/* This buffer is sufficiently large for all
+	 * currently-supported hash types. It needs to be updated if
+	 * longer hashes are added. The cast to struct crypt_data * is
+	 * purely to meet the public API requirements of the crypt_r
+	 * function; the implementation of crypt_r uses the object
+	 * purely as a char buffer. */
+	static char buf[128];
+	return __crypt_r(key, salt, (struct crypt_data *)buf);
 }
diff --git a/crypt.def b/crypt.def
index d5fdf35..50bbc9c 100644
--- a/crypt.def
+++ b/crypt.def
@@ -4,3 +4,4 @@ EXPORTS
 encrypt
 setkey
 crypt
+crypt_r = __crypt_r
diff --git a/crypt.h b/crypt.h
new file mode 100644
index 0000000..921e45a
--- /dev/null
+++ b/crypt.h
@@ -0,0 +1,27 @@
+#ifndef _CRYPT_H
+#define _CRYPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void encrypt(char *, int);
+void setkey(char *);
+char *crypt(const char *, const char *);
+
+#ifdef _GNU_SOURCE
+
+struct crypt_data {
+	int initialized;
+	char __buf[256];
+};
+
+char *crypt_r(const char *, const char *, struct crypt_data *);
+
+#endif /* _GNU_SOURCE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypt_blowfish.c b/crypt_blowfish.c
new file mode 100644
index 0000000..d3f7985
--- /dev/null
+++ b/crypt_blowfish.c
@@ -0,0 +1,798 @@
+/* Modified by Rich Felker in for inclusion in musl libc, based on
+ * Solar Designer's second size-optimized version sent to the musl
+ * mailing list. */
+
+/*
+ * 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-2012.
+ * 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-2012 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 mostly compatible with OpenBSD's bcrypt.c (prefix
+ * "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
+ * ideas.  The password hashing algorithm was designed by David Mazieres
+ * <dm at lcs.mit.edu>.  For more information on the level of compatibility,
+ * 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 <stdint.h>
+
+typedef uint32_t BF_word;
+typedef int32_t 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 union {
+	struct {
+		BF_key P;
+		BF_word S[4][0x100];
+	} s;
+	BF_word PS[BF_N + 2 + 4 * 0x100];
+} 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 = {{
+	{
+		0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+		0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+		0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+		0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+		0x9216d5d9, 0x8979fb1b
+	}, {
+		{
+			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
+		}
+	}
+}};
+
+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)
+{
+	if ((union { int i; char c; }){1}.c)
+	do {
+		BF_word tmp = *x;
+		tmp = (tmp << 16) | (tmp >> 16);
+		*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
+	} while (--count);
+}
+
+#define BF_ROUND(L, R, N) \
+	tmp1 = L & 0xFF; \
+	tmp2 = L >> 8; \
+	tmp2 &= 0xFF; \
+	tmp3 = L >> 16; \
+	tmp3 &= 0xFF; \
+	tmp4 = L >> 24; \
+	tmp1 = ctx->s.S[3][tmp1]; \
+	tmp2 = ctx->s.S[2][tmp2]; \
+	tmp3 = ctx->s.S[1][tmp3]; \
+	tmp3 += ctx->s.S[0][tmp4]; \
+	tmp3 ^= tmp2; \
+	R ^= ctx->s.P[N + 1]; \
+	tmp3 += tmp1; \
+	R ^= tmp3;
+
+static BF_word BF_encrypt(BF_ctx *ctx,
+    BF_word L, BF_word R,
+    BF_word *start, BF_word *end)
+{
+	BF_word tmp1, tmp2, tmp3, tmp4;
+	BF_word *ptr = start;
+
+	do {
+		L ^= ctx->s.P[0];
+#if 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);
+#else
+		for (int i=0; i<16; i+=2) {
+			BF_ROUND(L, R, i);
+			BF_ROUND(R, L, i+1);
+		}
+#endif
+		tmp4 = R;
+		R = L;
+		L = tmp4 ^ ctx->s.P[BF_N + 1];
+		*ptr++ = L;
+		*ptr++ = R;
+	} while (ptr < end);
+
+	return L;
+}
+
+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 "$2x$": bug = 1, safety = 0
+ * Prefix "$2y$": bug = 0, safety = 0
+ */
+	bug = 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] |= (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.s.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 char *BF_crypt(const char *key, const char *setting,
+	char *output, BF_word min)
+{
+	static const unsigned char flags_by_subtype[26] =
+		{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
+	struct {
+		BF_ctx ctx;
+		BF_key expanded_key;
+		union {
+			BF_word salt[4];
+			BF_word output[6];
+		} binary;
+	} data;
+	BF_word count;
+	int i;
+
+	if (setting[0] != '$' ||
+	    setting[1] != '2' ||
+	    setting[2] - 'a' > 25U ||
+	    !flags_by_subtype[setting[2] - 'a'] ||
+	    setting[3] != '$' ||
+	    setting[4] - '0' > 1U ||
+	    setting[5] - '0' > 9U ||
+	    setting[6] != '$') {
+		return NULL;
+	}
+
+	count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
+	if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
+		return NULL;
+	}
+	BF_swap(data.binary.salt, 4);
+
+	BF_set_key(key, data.expanded_key, data.ctx.s.P,
+	    flags_by_subtype[setting[2] - 'a']);
+
+	memcpy(data.ctx.s.S, BF_init_state.s.S, sizeof(data.ctx.s.S));
+
+	{
+		BF_word L = 0, R = 0;
+		BF_word *ptr = &data.ctx.PS[0];
+		do {
+			L = BF_encrypt(&data.ctx,
+			    L ^ data.binary.salt[0], R ^ data.binary.salt[1],
+			    ptr, ptr);
+			R = *(ptr + 1);
+			ptr += 2;
+
+			if (ptr >= &data.ctx.PS[BF_N + 2 + 4 * 0x100])
+				break;
+
+			L = BF_encrypt(&data.ctx,
+			    L ^ data.binary.salt[2], R ^ data.binary.salt[3],
+			    ptr, ptr);
+			R = *(ptr + 1);
+			ptr += 2;
+		} while (1);
+	}
+
+	do {
+		int done;
+
+		for (i = 0; i < BF_N + 2; i += 2) {
+			data.ctx.s.P[i] ^= data.expanded_key[i];
+			data.ctx.s.P[i + 1] ^= data.expanded_key[i + 1];
+		}
+
+		done = 0;
+		do {
+			BF_encrypt(&data.ctx, 0, 0,
+			    &data.ctx.PS[0],
+			    &data.ctx.PS[BF_N + 2 + 4 * 0x100]);
+
+			if (done)
+				break;
+			done = 1;
+
+			{
+				BF_word tmp1, tmp2, tmp3, tmp4;
+
+				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.s.P[i] ^= tmp1;
+					data.ctx.s.P[i + 1] ^= tmp2;
+					data.ctx.s.P[i + 2] ^= tmp3;
+					data.ctx.s.P[i + 3] ^= tmp4;
+				}
+				data.ctx.s.P[16] ^= tmp1;
+				data.ctx.s.P[17] ^= tmp2;
+			}
+		} while (1);
+	} while (--count);
+
+	for (i = 0; i < 6; i += 2) {
+		BF_word L, LR[2];
+
+		L = BF_magic_w[i];
+		LR[1] = BF_magic_w[i + 1];
+
+		count = 64;
+		do {
+			L = BF_encrypt(&data.ctx, L, LR[1],
+			    &LR[0], &LR[0]);
+		} while (--count);
+
+		data.binary.output[i] = L;
+		data.binary.output[i + 1] = LR[1];
+	}
+
+	memcpy(output, setting, 7 + 22 - 1);
+	output[7 + 22 - 1] = BF_itoa64[
+		BF_atoi64[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;
+}
+
+/*
+ * 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(const char *key, const char *setting, char *output)
+{
+	const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
+	const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
+	static const char test_hash[2][34] =
+		{"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55", /* $2x$ */
+		"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55"}; /* $2a$, $2y$ */
+	char *retval;
+	const char *p;
+	int ok;
+	struct {
+		char s[7 + 22 + 1];
+		char o[7 + 22 + 31 + 1 + 1 + 1];
+	} buf;
+
+/* Hash the supplied password */
+	retval = BF_crypt(key, setting, output, 16);
+
+/*
+ * 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)
+		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, 1);
+
+	ok = (p == buf.o &&
+	    !memcmp(p, buf.s, 7 + 22) &&
+	    !memcmp(p + (7 + 22),
+	    test_hash[buf.s[2] & 1],
+	    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));
+	}
+
+	if (ok && retval)
+		return retval;
+
+	return "*";
+}
diff --git a/crypt_des.c b/crypt_des.c
new file mode 100644
index 0000000..d5766a7
--- /dev/null
+++ b/crypt_des.c
@@ -0,0 +1,1018 @@
+/*
+ * This version has been further modified by Rich Felker, primary author
+ * and maintainer of musl libc, to remove table generation code and
+ * replaced all runtime-generated constant tables with static-initialized
+ * tables in the binary, in the interest of minimizing non-shareable
+ * memory usage and stack size requirements.
+ */
+/*
+ * This version is derived from the original implementation of FreeSec
+ * (release 1.1) by David Burren.  I've made it reentrant, reduced its memory
+ * usage from about 70 KB to about 7 KB (with only minimal performance impact
+ * and keeping code size about the same), made the handling of invalid salts
+ * mostly UFC-crypt compatible, added a quick runtime self-test (which also
+ * serves to zeroize the stack from sensitive data), and added optional tests.
+ * - Solar Designer <solar at openwall.com>
+ */
+
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * Copyright (c) 2000,2002,2010,2012 Solar Designer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$Owl: Owl/packages/glibc/crypt_freesec.c,v 1.6 2010/02/20 14:45:06 solar Exp $
+ *	$Id: crypt.c,v 1.15 1994/09/13 04:58:49 davidb Exp $
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren.  It has been heavily re-worked by Solar Designer.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+struct expanded_key {
+	uint32_t l[16], r[16];
+};
+
+#define _PASSWORD_EFMT1 '_'
+
+static const unsigned char key_shifts[16] = {
+	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const uint32_t psbox[8][64] = {
+	{
+		0x00808200,0x00000000,0x00008000,0x00808202,
+		0x00808002,0x00008202,0x00000002,0x00008000,
+		0x00000200,0x00808200,0x00808202,0x00000200,
+		0x00800202,0x00808002,0x00800000,0x00000002,
+		0x00000202,0x00800200,0x00800200,0x00008200,
+		0x00008200,0x00808000,0x00808000,0x00800202,
+		0x00008002,0x00800002,0x00800002,0x00008002,
+		0x00000000,0x00000202,0x00008202,0x00800000,
+		0x00008000,0x00808202,0x00000002,0x00808000,
+		0x00808200,0x00800000,0x00800000,0x00000200,
+		0x00808002,0x00008000,0x00008200,0x00800002,
+		0x00000200,0x00000002,0x00800202,0x00008202,
+		0x00808202,0x00008002,0x00808000,0x00800202,
+		0x00800002,0x00000202,0x00008202,0x00808200,
+		0x00000202,0x00800200,0x00800200,0x00000000,
+		0x00008002,0x00008200,0x00000000,0x00808002,
+	},{
+		0x40084010,0x40004000,0x00004000,0x00084010,
+		0x00080000,0x00000010,0x40080010,0x40004010,
+		0x40000010,0x40084010,0x40084000,0x40000000,
+		0x40004000,0x00080000,0x00000010,0x40080010,
+		0x00084000,0x00080010,0x40004010,0x00000000,
+		0x40000000,0x00004000,0x00084010,0x40080000,
+		0x00080010,0x40000010,0x00000000,0x00084000,
+		0x00004010,0x40084000,0x40080000,0x00004010,
+		0x00000000,0x00084010,0x40080010,0x00080000,
+		0x40004010,0x40080000,0x40084000,0x00004000,
+		0x40080000,0x40004000,0x00000010,0x40084010,
+		0x00084010,0x00000010,0x00004000,0x40000000,
+		0x00004010,0x40084000,0x00080000,0x40000010,
+		0x00080010,0x40004010,0x40000010,0x00080010,
+		0x00084000,0x00000000,0x40004000,0x00004010,
+		0x40000000,0x40080010,0x40084010,0x00084000,
+	},{
+		0x00000104,0x04010100,0x00000000,0x04010004,
+		0x04000100,0x00000000,0x00010104,0x04000100,
+		0x00010004,0x04000004,0x04000004,0x00010000,
+		0x04010104,0x00010004,0x04010000,0x00000104,
+		0x04000000,0x00000004,0x04010100,0x00000100,
+		0x00010100,0x04010000,0x04010004,0x00010104,
+		0x04000104,0x00010100,0x00010000,0x04000104,
+		0x00000004,0x04010104,0x00000100,0x04000000,
+		0x04010100,0x04000000,0x00010004,0x00000104,
+		0x00010000,0x04010100,0x04000100,0x00000000,
+		0x00000100,0x00010004,0x04010104,0x04000100,
+		0x04000004,0x00000100,0x00000000,0x04010004,
+		0x04000104,0x00010000,0x04000000,0x04010104,
+		0x00000004,0x00010104,0x00010100,0x04000004,
+		0x04010000,0x04000104,0x00000104,0x04010000,
+		0x00010104,0x00000004,0x04010004,0x00010100,
+	},{
+		0x80401000,0x80001040,0x80001040,0x00000040,
+		0x00401040,0x80400040,0x80400000,0x80001000,
+		0x00000000,0x00401000,0x00401000,0x80401040,
+		0x80000040,0x00000000,0x00400040,0x80400000,
+		0x80000000,0x00001000,0x00400000,0x80401000,
+		0x00000040,0x00400000,0x80001000,0x00001040,
+		0x80400040,0x80000000,0x00001040,0x00400040,
+		0x00001000,0x00401040,0x80401040,0x80000040,
+		0x00400040,0x80400000,0x00401000,0x80401040,
+		0x80000040,0x00000000,0x00000000,0x00401000,
+		0x00001040,0x00400040,0x80400040,0x80000000,
+		0x80401000,0x80001040,0x80001040,0x00000040,
+		0x80401040,0x80000040,0x80000000,0x00001000,
+		0x80400000,0x80001000,0x00401040,0x80400040,
+		0x80001000,0x00001040,0x00400000,0x80401000,
+		0x00000040,0x00400000,0x00001000,0x00401040,
+	},{
+		0x00000080,0x01040080,0x01040000,0x21000080,
+		0x00040000,0x00000080,0x20000000,0x01040000,
+		0x20040080,0x00040000,0x01000080,0x20040080,
+		0x21000080,0x21040000,0x00040080,0x20000000,
+		0x01000000,0x20040000,0x20040000,0x00000000,
+		0x20000080,0x21040080,0x21040080,0x01000080,
+		0x21040000,0x20000080,0x00000000,0x21000000,
+		0x01040080,0x01000000,0x21000000,0x00040080,
+		0x00040000,0x21000080,0x00000080,0x01000000,
+		0x20000000,0x01040000,0x21000080,0x20040080,
+		0x01000080,0x20000000,0x21040000,0x01040080,
+		0x20040080,0x00000080,0x01000000,0x21040000,
+		0x21040080,0x00040080,0x21000000,0x21040080,
+		0x01040000,0x00000000,0x20040000,0x21000000,
+		0x00040080,0x01000080,0x20000080,0x00040000,
+		0x00000000,0x20040000,0x01040080,0x20000080,
+	},{
+		0x10000008,0x10200000,0x00002000,0x10202008,
+		0x10200000,0x00000008,0x10202008,0x00200000,
+		0x10002000,0x00202008,0x00200000,0x10000008,
+		0x00200008,0x10002000,0x10000000,0x00002008,
+		0x00000000,0x00200008,0x10002008,0x00002000,
+		0x00202000,0x10002008,0x00000008,0x10200008,
+		0x10200008,0x00000000,0x00202008,0x10202000,
+		0x00002008,0x00202000,0x10202000,0x10000000,
+		0x10002000,0x00000008,0x10200008,0x00202000,
+		0x10202008,0x00200000,0x00002008,0x10000008,
+		0x00200000,0x10002000,0x10000000,0x00002008,
+		0x10000008,0x10202008,0x00202000,0x10200000,
+		0x00202008,0x10202000,0x00000000,0x10200008,
+		0x00000008,0x00002000,0x10200000,0x00202008,
+		0x00002000,0x00200008,0x10002008,0x00000000,
+		0x10202000,0x10000000,0x00200008,0x10002008,
+	},{
+		0x00100000,0x02100001,0x02000401,0x00000000,
+		0x00000400,0x02000401,0x00100401,0x02100400,
+		0x02100401,0x00100000,0x00000000,0x02000001,
+		0x00000001,0x02000000,0x02100001,0x00000401,
+		0x02000400,0x00100401,0x00100001,0x02000400,
+		0x02000001,0x02100000,0x02100400,0x00100001,
+		0x02100000,0x00000400,0x00000401,0x02100401,
+		0x00100400,0x00000001,0x02000000,0x00100400,
+		0x02000000,0x00100400,0x00100000,0x02000401,
+		0x02000401,0x02100001,0x02100001,0x00000001,
+		0x00100001,0x02000000,0x02000400,0x00100000,
+		0x02100400,0x00000401,0x00100401,0x02100400,
+		0x00000401,0x02000001,0x02100401,0x02100000,
+		0x00100400,0x00000000,0x00000001,0x02100401,
+		0x00000000,0x00100401,0x02100000,0x00000400,
+		0x02000001,0x02000400,0x00000400,0x00100001,
+	},{
+		0x08000820,0x00000800,0x00020000,0x08020820,
+		0x08000000,0x08000820,0x00000020,0x08000000,
+		0x00020020,0x08020000,0x08020820,0x00020800,
+		0x08020800,0x00020820,0x00000800,0x00000020,
+		0x08020000,0x08000020,0x08000800,0x00000820,
+		0x00020800,0x00020020,0x08020020,0x08020800,
+		0x00000820,0x00000000,0x00000000,0x08020020,
+		0x08000020,0x08000800,0x00020820,0x00020000,
+		0x00020820,0x00020000,0x08020800,0x00000800,
+		0x00000020,0x08020020,0x00000800,0x00020820,
+		0x08000800,0x00000020,0x08000020,0x08020000,
+		0x08020020,0x08000000,0x00020000,0x08000820,
+		0x00000000,0x08020820,0x00020020,0x08000020,
+		0x08020000,0x08000800,0x08000820,0x00000000,
+		0x08020820,0x00020800,0x00020800,0x00000820,
+		0x00000820,0x00020020,0x08000000,0x08020800,
+	},
+};
+static const uint32_t ip_maskl[16][16] = {
+	{
+		0x00000000,0x00010000,0x00000000,0x00010000,
+		0x01000000,0x01010000,0x01000000,0x01010000,
+		0x00000000,0x00010000,0x00000000,0x00010000,
+		0x01000000,0x01010000,0x01000000,0x01010000,
+	},{
+		0x00000000,0x00000001,0x00000000,0x00000001,
+		0x00000100,0x00000101,0x00000100,0x00000101,
+		0x00000000,0x00000001,0x00000000,0x00000001,
+		0x00000100,0x00000101,0x00000100,0x00000101,
+	},{
+		0x00000000,0x00020000,0x00000000,0x00020000,
+		0x02000000,0x02020000,0x02000000,0x02020000,
+		0x00000000,0x00020000,0x00000000,0x00020000,
+		0x02000000,0x02020000,0x02000000,0x02020000,
+	},{
+		0x00000000,0x00000002,0x00000000,0x00000002,
+		0x00000200,0x00000202,0x00000200,0x00000202,
+		0x00000000,0x00000002,0x00000000,0x00000002,
+		0x00000200,0x00000202,0x00000200,0x00000202,
+	},{
+		0x00000000,0x00040000,0x00000000,0x00040000,
+		0x04000000,0x04040000,0x04000000,0x04040000,
+		0x00000000,0x00040000,0x00000000,0x00040000,
+		0x04000000,0x04040000,0x04000000,0x04040000,
+	},{
+		0x00000000,0x00000004,0x00000000,0x00000004,
+		0x00000400,0x00000404,0x00000400,0x00000404,
+		0x00000000,0x00000004,0x00000000,0x00000004,
+		0x00000400,0x00000404,0x00000400,0x00000404,
+	},{
+		0x00000000,0x00080000,0x00000000,0x00080000,
+		0x08000000,0x08080000,0x08000000,0x08080000,
+		0x00000000,0x00080000,0x00000000,0x00080000,
+		0x08000000,0x08080000,0x08000000,0x08080000,
+	},{
+		0x00000000,0x00000008,0x00000000,0x00000008,
+		0x00000800,0x00000808,0x00000800,0x00000808,
+		0x00000000,0x00000008,0x00000000,0x00000008,
+		0x00000800,0x00000808,0x00000800,0x00000808,
+	},{
+		0x00000000,0x00100000,0x00000000,0x00100000,
+		0x10000000,0x10100000,0x10000000,0x10100000,
+		0x00000000,0x00100000,0x00000000,0x00100000,
+		0x10000000,0x10100000,0x10000000,0x10100000,
+	},{
+		0x00000000,0x00000010,0x00000000,0x00000010,
+		0x00001000,0x00001010,0x00001000,0x00001010,
+		0x00000000,0x00000010,0x00000000,0x00000010,
+		0x00001000,0x00001010,0x00001000,0x00001010,
+	},{
+		0x00000000,0x00200000,0x00000000,0x00200000,
+		0x20000000,0x20200000,0x20000000,0x20200000,
+		0x00000000,0x00200000,0x00000000,0x00200000,
+		0x20000000,0x20200000,0x20000000,0x20200000,
+	},{
+		0x00000000,0x00000020,0x00000000,0x00000020,
+		0x00002000,0x00002020,0x00002000,0x00002020,
+		0x00000000,0x00000020,0x00000000,0x00000020,
+		0x00002000,0x00002020,0x00002000,0x00002020,
+	},{
+		0x00000000,0x00400000,0x00000000,0x00400000,
+		0x40000000,0x40400000,0x40000000,0x40400000,
+		0x00000000,0x00400000,0x00000000,0x00400000,
+		0x40000000,0x40400000,0x40000000,0x40400000,
+	},{
+		0x00000000,0x00000040,0x00000000,0x00000040,
+		0x00004000,0x00004040,0x00004000,0x00004040,
+		0x00000000,0x00000040,0x00000000,0x00000040,
+		0x00004000,0x00004040,0x00004000,0x00004040,
+	},{
+		0x00000000,0x00800000,0x00000000,0x00800000,
+		0x80000000,0x80800000,0x80000000,0x80800000,
+		0x00000000,0x00800000,0x00000000,0x00800000,
+		0x80000000,0x80800000,0x80000000,0x80800000,
+	},{
+		0x00000000,0x00000080,0x00000000,0x00000080,
+		0x00008000,0x00008080,0x00008000,0x00008080,
+		0x00000000,0x00000080,0x00000000,0x00000080,
+		0x00008000,0x00008080,0x00008000,0x00008080,
+	},
+};
+static const uint32_t ip_maskr[16][16] = {
+	{
+		0x00000000,0x00000000,0x00010000,0x00010000,
+		0x00000000,0x00000000,0x00010000,0x00010000,
+		0x01000000,0x01000000,0x01010000,0x01010000,
+		0x01000000,0x01000000,0x01010000,0x01010000,
+	},{
+		0x00000000,0x00000000,0x00000001,0x00000001,
+		0x00000000,0x00000000,0x00000001,0x00000001,
+		0x00000100,0x00000100,0x00000101,0x00000101,
+		0x00000100,0x00000100,0x00000101,0x00000101,
+	},{
+		0x00000000,0x00000000,0x00020000,0x00020000,
+		0x00000000,0x00000000,0x00020000,0x00020000,
+		0x02000000,0x02000000,0x02020000,0x02020000,
+		0x02000000,0x02000000,0x02020000,0x02020000,
+	},{
+		0x00000000,0x00000000,0x00000002,0x00000002,
+		0x00000000,0x00000000,0x00000002,0x00000002,
+		0x00000200,0x00000200,0x00000202,0x00000202,
+		0x00000200,0x00000200,0x00000202,0x00000202,
+	},{
+		0x00000000,0x00000000,0x00040000,0x00040000,
+		0x00000000,0x00000000,0x00040000,0x00040000,
+		0x04000000,0x04000000,0x04040000,0x04040000,
+		0x04000000,0x04000000,0x04040000,0x04040000,
+	},{
+		0x00000000,0x00000000,0x00000004,0x00000004,
+		0x00000000,0x00000000,0x00000004,0x00000004,
+		0x00000400,0x00000400,0x00000404,0x00000404,
+		0x00000400,0x00000400,0x00000404,0x00000404,
+	},{
+		0x00000000,0x00000000,0x00080000,0x00080000,
+		0x00000000,0x00000000,0x00080000,0x00080000,
+		0x08000000,0x08000000,0x08080000,0x08080000,
+		0x08000000,0x08000000,0x08080000,0x08080000,
+	},{
+		0x00000000,0x00000000,0x00000008,0x00000008,
+		0x00000000,0x00000000,0x00000008,0x00000008,
+		0x00000800,0x00000800,0x00000808,0x00000808,
+		0x00000800,0x00000800,0x00000808,0x00000808,
+	},{
+		0x00000000,0x00000000,0x00100000,0x00100000,
+		0x00000000,0x00000000,0x00100000,0x00100000,
+		0x10000000,0x10000000,0x10100000,0x10100000,
+		0x10000000,0x10000000,0x10100000,0x10100000,
+	},{
+		0x00000000,0x00000000,0x00000010,0x00000010,
+		0x00000000,0x00000000,0x00000010,0x00000010,
+		0x00001000,0x00001000,0x00001010,0x00001010,
+		0x00001000,0x00001000,0x00001010,0x00001010,
+	},{
+		0x00000000,0x00000000,0x00200000,0x00200000,
+		0x00000000,0x00000000,0x00200000,0x00200000,
+		0x20000000,0x20000000,0x20200000,0x20200000,
+		0x20000000,0x20000000,0x20200000,0x20200000,
+	},{
+		0x00000000,0x00000000,0x00000020,0x00000020,
+		0x00000000,0x00000000,0x00000020,0x00000020,
+		0x00002000,0x00002000,0x00002020,0x00002020,
+		0x00002000,0x00002000,0x00002020,0x00002020,
+	},{
+		0x00000000,0x00000000,0x00400000,0x00400000,
+		0x00000000,0x00000000,0x00400000,0x00400000,
+		0x40000000,0x40000000,0x40400000,0x40400000,
+		0x40000000,0x40000000,0x40400000,0x40400000,
+	},{
+		0x00000000,0x00000000,0x00000040,0x00000040,
+		0x00000000,0x00000000,0x00000040,0x00000040,
+		0x00004000,0x00004000,0x00004040,0x00004040,
+		0x00004000,0x00004000,0x00004040,0x00004040,
+	},{
+		0x00000000,0x00000000,0x00800000,0x00800000,
+		0x00000000,0x00000000,0x00800000,0x00800000,
+		0x80000000,0x80000000,0x80800000,0x80800000,
+		0x80000000,0x80000000,0x80800000,0x80800000,
+	},{
+		0x00000000,0x00000000,0x00000080,0x00000080,
+		0x00000000,0x00000000,0x00000080,0x00000080,
+		0x00008000,0x00008000,0x00008080,0x00008080,
+		0x00008000,0x00008000,0x00008080,0x00008080,
+	},
+};
+static const uint32_t fp_maskl[8][16] = {
+	{
+		0x00000000,0x40000000,0x00400000,0x40400000,
+		0x00004000,0x40004000,0x00404000,0x40404000,
+		0x00000040,0x40000040,0x00400040,0x40400040,
+		0x00004040,0x40004040,0x00404040,0x40404040,
+	},{
+		0x00000000,0x10000000,0x00100000,0x10100000,
+		0x00001000,0x10001000,0x00101000,0x10101000,
+		0x00000010,0x10000010,0x00100010,0x10100010,
+		0x00001010,0x10001010,0x00101010,0x10101010,
+	},{
+		0x00000000,0x04000000,0x00040000,0x04040000,
+		0x00000400,0x04000400,0x00040400,0x04040400,
+		0x00000004,0x04000004,0x00040004,0x04040004,
+		0x00000404,0x04000404,0x00040404,0x04040404,
+	},{
+		0x00000000,0x01000000,0x00010000,0x01010000,
+		0x00000100,0x01000100,0x00010100,0x01010100,
+		0x00000001,0x01000001,0x00010001,0x01010001,
+		0x00000101,0x01000101,0x00010101,0x01010101,
+	},{
+		0x00000000,0x80000000,0x00800000,0x80800000,
+		0x00008000,0x80008000,0x00808000,0x80808000,
+		0x00000080,0x80000080,0x00800080,0x80800080,
+		0x00008080,0x80008080,0x00808080,0x80808080,
+	},{
+		0x00000000,0x20000000,0x00200000,0x20200000,
+		0x00002000,0x20002000,0x00202000,0x20202000,
+		0x00000020,0x20000020,0x00200020,0x20200020,
+		0x00002020,0x20002020,0x00202020,0x20202020,
+	},{
+		0x00000000,0x08000000,0x00080000,0x08080000,
+		0x00000800,0x08000800,0x00080800,0x08080800,
+		0x00000008,0x08000008,0x00080008,0x08080008,
+		0x00000808,0x08000808,0x00080808,0x08080808,
+	},{
+		0x00000000,0x02000000,0x00020000,0x02020000,
+		0x00000200,0x02000200,0x00020200,0x02020200,
+		0x00000002,0x02000002,0x00020002,0x02020002,
+		0x00000202,0x02000202,0x00020202,0x02020202,
+	},
+};
+static const uint32_t fp_maskr[8][16] = {
+	{
+		0x00000000,0x40000000,0x00400000,0x40400000,
+		0x00004000,0x40004000,0x00404000,0x40404000,
+		0x00000040,0x40000040,0x00400040,0x40400040,
+		0x00004040,0x40004040,0x00404040,0x40404040,
+	},{
+		0x00000000,0x10000000,0x00100000,0x10100000,
+		0x00001000,0x10001000,0x00101000,0x10101000,
+		0x00000010,0x10000010,0x00100010,0x10100010,
+		0x00001010,0x10001010,0x00101010,0x10101010,
+	},{
+		0x00000000,0x04000000,0x00040000,0x04040000,
+		0x00000400,0x04000400,0x00040400,0x04040400,
+		0x00000004,0x04000004,0x00040004,0x04040004,
+		0x00000404,0x04000404,0x00040404,0x04040404,
+	},{
+		0x00000000,0x01000000,0x00010000,0x01010000,
+		0x00000100,0x01000100,0x00010100,0x01010100,
+		0x00000001,0x01000001,0x00010001,0x01010001,
+		0x00000101,0x01000101,0x00010101,0x01010101,
+	},{
+		0x00000000,0x80000000,0x00800000,0x80800000,
+		0x00008000,0x80008000,0x00808000,0x80808000,
+		0x00000080,0x80000080,0x00800080,0x80800080,
+		0x00008080,0x80008080,0x00808080,0x80808080,
+	},{
+		0x00000000,0x20000000,0x00200000,0x20200000,
+		0x00002000,0x20002000,0x00202000,0x20202000,
+		0x00000020,0x20000020,0x00200020,0x20200020,
+		0x00002020,0x20002020,0x00202020,0x20202020,
+	},{
+		0x00000000,0x08000000,0x00080000,0x08080000,
+		0x00000800,0x08000800,0x00080800,0x08080800,
+		0x00000008,0x08000008,0x00080008,0x08080008,
+		0x00000808,0x08000808,0x00080808,0x08080808,
+	},{
+		0x00000000,0x02000000,0x00020000,0x02020000,
+		0x00000200,0x02000200,0x00020200,0x02020200,
+		0x00000002,0x02000002,0x00020002,0x02020002,
+		0x00000202,0x02000202,0x00020202,0x02020202,
+	},
+};
+static const uint32_t key_perm_maskl[8][16] = {
+	{
+		0x00000000,0x00000000,0x00000010,0x00000010,
+		0x00001000,0x00001000,0x00001010,0x00001010,
+		0x00100000,0x00100000,0x00100010,0x00100010,
+		0x00101000,0x00101000,0x00101010,0x00101010,
+	},{
+		0x00000000,0x00000000,0x00000020,0x00000020,
+		0x00002000,0x00002000,0x00002020,0x00002020,
+		0x00200000,0x00200000,0x00200020,0x00200020,
+		0x00202000,0x00202000,0x00202020,0x00202020,
+	},{
+		0x00000000,0x00000000,0x00000040,0x00000040,
+		0x00004000,0x00004000,0x00004040,0x00004040,
+		0x00400000,0x00400000,0x00400040,0x00400040,
+		0x00404000,0x00404000,0x00404040,0x00404040,
+	},{
+		0x00000000,0x00000000,0x00000080,0x00000080,
+		0x00008000,0x00008000,0x00008080,0x00008080,
+		0x00800000,0x00800000,0x00800080,0x00800080,
+		0x00808000,0x00808000,0x00808080,0x00808080,
+	},{
+		0x00000000,0x00000001,0x00000100,0x00000101,
+		0x00010000,0x00010001,0x00010100,0x00010101,
+		0x01000000,0x01000001,0x01000100,0x01000101,
+		0x01010000,0x01010001,0x01010100,0x01010101,
+	},{
+		0x00000000,0x00000002,0x00000200,0x00000202,
+		0x00020000,0x00020002,0x00020200,0x00020202,
+		0x02000000,0x02000002,0x02000200,0x02000202,
+		0x02020000,0x02020002,0x02020200,0x02020202,
+	},{
+		0x00000000,0x00000004,0x00000400,0x00000404,
+		0x00040000,0x00040004,0x00040400,0x00040404,
+		0x04000000,0x04000004,0x04000400,0x04000404,
+		0x04040000,0x04040004,0x04040400,0x04040404,
+	},{
+		0x00000000,0x00000008,0x00000800,0x00000808,
+		0x00080000,0x00080008,0x00080800,0x00080808,
+		0x08000000,0x08000008,0x08000800,0x08000808,
+		0x08080000,0x08080008,0x08080800,0x08080808,
+	},
+};
+static const uint32_t key_perm_maskr[12][16] = {
+	{
+		0x00000000,0x00000001,0x00000000,0x00000001,
+		0x00000000,0x00000001,0x00000000,0x00000001,
+		0x00000000,0x00000001,0x00000000,0x00000001,
+		0x00000000,0x00000001,0x00000000,0x00000001,
+	},{
+		0x00000000,0x00000000,0x00100000,0x00100000,
+		0x00001000,0x00001000,0x00101000,0x00101000,
+		0x00000010,0x00000010,0x00100010,0x00100010,
+		0x00001010,0x00001010,0x00101010,0x00101010,
+	},{
+		0x00000000,0x00000002,0x00000000,0x00000002,
+		0x00000000,0x00000002,0x00000000,0x00000002,
+		0x00000000,0x00000002,0x00000000,0x00000002,
+		0x00000000,0x00000002,0x00000000,0x00000002,
+	},{
+		0x00000000,0x00000000,0x00200000,0x00200000,
+		0x00002000,0x00002000,0x00202000,0x00202000,
+		0x00000020,0x00000020,0x00200020,0x00200020,
+		0x00002020,0x00002020,0x00202020,0x00202020,
+	},{
+		0x00000000,0x00000004,0x00000000,0x00000004,
+		0x00000000,0x00000004,0x00000000,0x00000004,
+		0x00000000,0x00000004,0x00000000,0x00000004,
+		0x00000000,0x00000004,0x00000000,0x00000004,
+	},{
+		0x00000000,0x00000000,0x00400000,0x00400000,
+		0x00004000,0x00004000,0x00404000,0x00404000,
+		0x00000040,0x00000040,0x00400040,0x00400040,
+		0x00004040,0x00004040,0x00404040,0x00404040,
+	},{
+		0x00000000,0x00000008,0x00000000,0x00000008,
+		0x00000000,0x00000008,0x00000000,0x00000008,
+		0x00000000,0x00000008,0x00000000,0x00000008,
+		0x00000000,0x00000008,0x00000000,0x00000008,
+	},{
+		0x00000000,0x00000000,0x00800000,0x00800000,
+		0x00008000,0x00008000,0x00808000,0x00808000,
+		0x00000080,0x00000080,0x00800080,0x00800080,
+		0x00008080,0x00008080,0x00808080,0x00808080,
+	},{
+		0x00000000,0x00000000,0x01000000,0x01000000,
+		0x00010000,0x00010000,0x01010000,0x01010000,
+		0x00000100,0x00000100,0x01000100,0x01000100,
+		0x00010100,0x00010100,0x01010100,0x01010100,
+	},{
+		0x00000000,0x00000000,0x02000000,0x02000000,
+		0x00020000,0x00020000,0x02020000,0x02020000,
+		0x00000200,0x00000200,0x02000200,0x02000200,
+		0x00020200,0x00020200,0x02020200,0x02020200,
+	},{
+		0x00000000,0x00000000,0x04000000,0x04000000,
+		0x00040000,0x00040000,0x04040000,0x04040000,
+		0x00000400,0x00000400,0x04000400,0x04000400,
+		0x00040400,0x00040400,0x04040400,0x04040400,
+	},{
+		0x00000000,0x00000000,0x08000000,0x08000000,
+		0x00080000,0x00080000,0x08080000,0x08080000,
+		0x00000800,0x00000800,0x08000800,0x08000800,
+		0x00080800,0x00080800,0x08080800,0x08080800,
+	},
+};
+static const uint32_t comp_maskl0[4][8] = {
+	{
+		0x00000000,0x00020000,0x00000001,0x00020001,
+		0x00080000,0x000a0000,0x00080001,0x000a0001,
+	},{
+		0x00000000,0x00001000,0x00000000,0x00001000,
+		0x00000040,0x00001040,0x00000040,0x00001040,
+	},{
+		0x00000000,0x00400000,0x00000020,0x00400020,
+		0x00008000,0x00408000,0x00008020,0x00408020,
+	},{
+		0x00000000,0x00100000,0x00000800,0x00100800,
+		0x00000000,0x00100000,0x00000800,0x00100800,
+	},
+};
+static const uint32_t comp_maskr0[4][8] = {
+	{
+		0x00000000,0x00200000,0x00020000,0x00220000,
+		0x00000002,0x00200002,0x00020002,0x00220002,
+	},{
+		0x00000000,0x00000000,0x00100000,0x00100000,
+		0x00000004,0x00000004,0x00100004,0x00100004,
+	},{
+		0x00000000,0x00004000,0x00000800,0x00004800,
+		0x00000000,0x00004000,0x00000800,0x00004800,
+	},{
+		0x00000000,0x00400000,0x00008000,0x00408000,
+		0x00000008,0x00400008,0x00008008,0x00408008,
+	},
+};
+static const uint32_t comp_maskl1[4][16] = {
+	{
+		0x00000000,0x00000010,0x00004000,0x00004010,
+		0x00040000,0x00040010,0x00044000,0x00044010,
+		0x00000100,0x00000110,0x00004100,0x00004110,
+		0x00040100,0x00040110,0x00044100,0x00044110,
+	},{
+		0x00000000,0x00800000,0x00000002,0x00800002,
+		0x00000200,0x00800200,0x00000202,0x00800202,
+		0x00200000,0x00a00000,0x00200002,0x00a00002,
+		0x00200200,0x00a00200,0x00200202,0x00a00202,
+	},{
+		0x00000000,0x00002000,0x00000004,0x00002004,
+		0x00000400,0x00002400,0x00000404,0x00002404,
+		0x00000000,0x00002000,0x00000004,0x00002004,
+		0x00000400,0x00002400,0x00000404,0x00002404,
+	},{
+		0x00000000,0x00010000,0x00000008,0x00010008,
+		0x00000080,0x00010080,0x00000088,0x00010088,
+		0x00000000,0x00010000,0x00000008,0x00010008,
+		0x00000080,0x00010080,0x00000088,0x00010088,
+	},
+};
+static const uint32_t comp_maskr1[4][16] = {
+	{
+		0x00000000,0x00000000,0x00000080,0x00000080,
+		0x00002000,0x00002000,0x00002080,0x00002080,
+		0x00000001,0x00000001,0x00000081,0x00000081,
+		0x00002001,0x00002001,0x00002081,0x00002081,
+	},{
+		0x00000000,0x00000010,0x00800000,0x00800010,
+		0x00010000,0x00010010,0x00810000,0x00810010,
+		0x00000200,0x00000210,0x00800200,0x00800210,
+		0x00010200,0x00010210,0x00810200,0x00810210,
+	},{
+		0x00000000,0x00000400,0x00001000,0x00001400,
+		0x00080000,0x00080400,0x00081000,0x00081400,
+		0x00000020,0x00000420,0x00001020,0x00001420,
+		0x00080020,0x00080420,0x00081020,0x00081420,
+	},{
+		0x00000000,0x00000100,0x00040000,0x00040100,
+		0x00000000,0x00000100,0x00040000,0x00040100,
+		0x00000040,0x00000140,0x00040040,0x00040140,
+		0x00000040,0x00000140,0x00040040,0x00040140,
+	},
+};
+
+static const unsigned char ascii64[] =
+    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+/*   0000000000111111111122222222223333333333444444444455555555556666 */
+/*   0123456789012345678901234567890123456789012345678901234567890123 */
+
+/*
+ * We match the behavior of UFC-crypt on systems where "char" is signed by
+ * default (the majority), regardless of char's signedness on our system.
+ */
+static uint32_t ascii_to_bin(int ch)
+{
+	int sch = (ch < 0x80) ? ch : -(0x100 - ch);
+	int retval;
+
+	retval = sch - '.';
+	if (sch >= 'A') {
+		retval = sch - ('A' - 12);
+		if (sch >= 'a')
+			retval = sch - ('a' - 38);
+	}
+	retval &= 0x3f;
+
+	return retval;
+}
+
+/*
+ * When we choose to "support" invalid salts, nevertheless disallow those
+ * containing characters that would violate the passwd file format.
+ */
+static inline int ascii_is_unsafe(unsigned char ch)
+{
+	return !ch || ch == '\n' || ch == ':';
+}
+
+static uint32_t setup_salt(uint32_t salt)
+{
+	uint32_t obit, saltbit, saltbits;
+	unsigned int i;
+
+	saltbits = 0;
+	saltbit = 1;
+	obit = 0x800000;
+	for (i = 0; i < 24; i++) {
+		if (salt & saltbit)
+			saltbits |= obit;
+		saltbit <<= 1;
+		obit >>= 1;
+	}
+
+	return saltbits;
+}
+
+void __des_setkey(const unsigned char *key, struct expanded_key *ekey)
+{
+	uint32_t k0, k1, rawkey0, rawkey1;
+	unsigned int shifts, round, i, ibit;
+
+	rawkey0 =
+	    (uint32_t)key[3] |
+	    ((uint32_t)key[2] << 8) |
+	    ((uint32_t)key[1] << 16) |
+	    ((uint32_t)key[0] << 24);
+	rawkey1 =
+	    (uint32_t)key[7] |
+	    ((uint32_t)key[6] << 8) |
+	    ((uint32_t)key[5] << 16) |
+	    ((uint32_t)key[4] << 24);
+
+	/*
+	 * Do key permutation and split into two 28-bit subkeys.
+	 */
+	k0 = k1 = 0;
+	for (i = 0, ibit = 28; i < 4; i++, ibit -= 4) {
+		unsigned int j = i << 1;
+		k0 |= key_perm_maskl[i][(rawkey0 >> ibit) & 0xf] |
+		      key_perm_maskl[i + 4][(rawkey1 >> ibit) & 0xf];
+		k1 |= key_perm_maskr[j][(rawkey0 >> ibit) & 0xf];
+		ibit -= 4;
+		k1 |= key_perm_maskr[j + 1][(rawkey0 >> ibit) & 0xf] |
+		      key_perm_maskr[i + 8][(rawkey1 >> ibit) & 0xf];
+	}
+
+	/*
+	 * Rotate subkeys and do compression permutation.
+	 */
+	shifts = 0;
+	for (round = 0; round < 16; round++) {
+		uint32_t t0, t1;
+		uint32_t kl, kr;
+
+		shifts += key_shifts[round];
+
+		t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+		t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+		kl = kr = 0;
+		ibit = 25;
+		for (i = 0; i < 4; i++) {
+			kl |= comp_maskl0[i][(t0 >> ibit) & 7];
+			kr |= comp_maskr0[i][(t1 >> ibit) & 7];
+			ibit -= 4;
+			kl |= comp_maskl1[i][(t0 >> ibit) & 0xf];
+			kr |= comp_maskr1[i][(t1 >> ibit) & 0xf];
+			ibit -= 3;
+		}
+		ekey->l[round] = kl;
+		ekey->r[round] = kr;
+	}
+}
+
+/*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+void __do_des(uint32_t l_in, uint32_t r_in,
+    uint32_t *l_out, uint32_t *r_out,
+    uint32_t count, uint32_t saltbits, const struct expanded_key *ekey)
+{
+	uint32_t l, r;
+
+	/*
+	 * Do initial permutation (IP).
+	 */
+	l = r = 0;
+	if (l_in | r_in) {
+		unsigned int i, ibit;
+		for (i = 0, ibit = 28; i < 8; i++, ibit -= 4) {
+			l |= ip_maskl[i][(l_in >> ibit) & 0xf] |
+			     ip_maskl[i + 8][(r_in >> ibit) & 0xf];
+			r |= ip_maskr[i][(l_in >> ibit) & 0xf] |
+			     ip_maskr[i + 8][(r_in >> ibit) & 0xf];
+		}
+	}
+
+	while (count--) {
+		/*
+		 * Do each round.
+		 */
+		unsigned int round = 16;
+		const uint32_t *kl = ekey->l;
+		const uint32_t *kr = ekey->r;
+		uint32_t f;
+		while (round--) {
+			uint32_t r48l, r48r;
+			/*
+			 * Expand R to 48 bits (simulate the E-box).
+			 */
+			r48l	= ((r & 0x00000001) << 23)
+				| ((r & 0xf8000000) >> 9)
+				| ((r & 0x1f800000) >> 11)
+				| ((r & 0x01f80000) >> 13)
+				| ((r & 0x001f8000) >> 15);
+
+			r48r	= ((r & 0x0001f800) << 7)
+				| ((r & 0x00001f80) << 5)
+				| ((r & 0x000001f8) << 3)
+				| ((r & 0x0000001f) << 1)
+				| ((r & 0x80000000) >> 31);
+			/*
+			 * Do salting for crypt() and friends, and
+			 * XOR with the permuted key.
+			 */
+			f = (r48l ^ r48r) & saltbits;
+			r48l ^= f ^ *kl++;
+			r48r ^= f ^ *kr++;
+			/*
+			 * Do S-box lookups (which shrink it back to 32 bits)
+			 * and do the P-box permutation at the same time.
+			 */
+			f = psbox[0][r48l >> 18]
+			  | psbox[1][(r48l >> 12) & 0x3f]
+			  | psbox[2][(r48l >> 6) & 0x3f]
+			  | psbox[3][r48l & 0x3f]
+			  | psbox[4][r48r >> 18]
+			  | psbox[5][(r48r >> 12) & 0x3f]
+			  | psbox[6][(r48r >> 6) & 0x3f]
+			  | psbox[7][r48r & 0x3f];
+			/*
+			 * Now that we've permuted things, complete f().
+			 */
+			f ^= l;
+			l = r;
+			r = f;
+		}
+		r = l;
+		l = f;
+	}
+
+	/*
+	 * Do final permutation (inverse of IP).
+	 */
+	{
+		unsigned int i, ibit;
+		uint32_t lo, ro;
+		lo = ro = 0;
+		for (i = 0, ibit = 28; i < 4; i++, ibit -= 4) {
+			ro |= fp_maskr[i][(l >> ibit) & 0xf] |
+			      fp_maskr[i + 4][(r >> ibit) & 0xf];
+			ibit -= 4;
+			lo |= fp_maskl[i][(l >> ibit) & 0xf] |
+			      fp_maskl[i + 4][(r >> ibit) & 0xf];
+		}
+		*l_out = lo;
+		*r_out = ro;
+	}
+}
+
+static void des_cipher(const unsigned char *in, unsigned char *out,
+    uint32_t count, uint32_t saltbits, const struct expanded_key *ekey)
+{
+	uint32_t l_out, r_out, rawl, rawr;
+
+	rawl =
+	    (uint32_t)in[3] |
+	    ((uint32_t)in[2] << 8) |
+	    ((uint32_t)in[1] << 16) |
+	    ((uint32_t)in[0] << 24);
+	rawr =
+	    (uint32_t)in[7] |
+	    ((uint32_t)in[6] << 8) |
+	    ((uint32_t)in[5] << 16) |
+	    ((uint32_t)in[4] << 24);
+
+	__do_des(rawl, rawr, &l_out, &r_out, count, saltbits, ekey);
+
+	out[0] = l_out >> 24;
+	out[1] = l_out >> 16;
+	out[2] = l_out >> 8;
+	out[3] = l_out;
+	out[4] = r_out >> 24;
+	out[5] = r_out >> 16;
+	out[6] = r_out >> 8;
+	out[7] = r_out;
+}
+
+static char *_crypt_extended_r_uut(const char *_key, const char *_setting, char *output)
+{
+	const unsigned char *key = (const unsigned char *)_key;
+	const unsigned char *setting = (const unsigned char *)_setting;
+	struct expanded_key ekey;
+	unsigned char keybuf[8];
+	unsigned char *p, *q;
+	uint32_t count, salt, l, r0, r1;
+	unsigned int i;
+
+	/*
+	 * Copy the key, shifting each character left by one bit and padding
+	 * with zeroes.
+	 */
+	q = keybuf;
+	while (q <= &keybuf[sizeof(keybuf) - 1]) {
+		*q++ = *key << 1;
+		if (*key)
+			key++;
+	}
+	__des_setkey(keybuf, &ekey);
+
+	if (*setting == _PASSWORD_EFMT1) {
+		/*
+		 * "new"-style:
+		 *	setting - underscore, 4 chars of count, 4 chars of salt
+		 *	key - unlimited characters
+		 */
+		for (i = 1, count = 0; i < 5; i++) {
+			uint32_t value = ascii_to_bin(setting[i]);
+			if (ascii64[value] != setting[i])
+				return NULL;
+			count |= value << (i - 1) * 6;
+		}
+		if (!count)
+			return NULL;
+
+		for (i = 5, salt = 0; i < 9; i++) {
+			uint32_t value = ascii_to_bin(setting[i]);
+			if (ascii64[value] != setting[i])
+				return NULL;
+			salt |= value << (i - 5) * 6;
+		}
+
+		while (*key) {
+			/*
+			 * Encrypt the key with itself.
+			 */
+			des_cipher(keybuf, keybuf, 1, 0, &ekey);
+			/*
+			 * And XOR with the next 8 characters of the key.
+			 */
+			q = keybuf;
+			while (q <= &keybuf[sizeof(keybuf) - 1] && *key)
+				*q++ ^= *key++ << 1;
+			__des_setkey(keybuf, &ekey);
+		}
+
+		memcpy(output, setting, 9);
+		output[9] = '\0';
+		p = (unsigned char *)output + 9;
+	} else {
+		/*
+		 * "old"-style:
+		 *	setting - 2 chars of salt
+		 *	key - up to 8 characters
+		 */
+		count = 25;
+
+		if (ascii_is_unsafe(setting[0]) || ascii_is_unsafe(setting[1]))
+			return NULL;
+
+		salt = (ascii_to_bin(setting[1]) << 6)
+		     |  ascii_to_bin(setting[0]);
+
+		output[0] = setting[0];
+		output[1] = setting[1];
+		p = (unsigned char *)output + 2;
+	}
+
+	/*
+	 * Do it.
+	 */
+	__do_des(0, 0, &r0, &r1, count, setup_salt(salt), &ekey);
+
+	/*
+	 * Now encode the result...
+	 */
+	l = (r0 >> 8);
+	*p++ = ascii64[(l >> 18) & 0x3f];
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+
+	l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+	*p++ = ascii64[(l >> 18) & 0x3f];
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+
+	l = r1 << 2;
+	*p++ = ascii64[(l >> 12) & 0x3f];
+	*p++ = ascii64[(l >> 6) & 0x3f];
+	*p++ = ascii64[l & 0x3f];
+	*p = 0;
+
+	return output;
+}
+
+char *__crypt_des(const char *key, const char *setting, char *output)
+{
+	const char *test_key = "\x80\xff\x80\x01 "
+	    "\x7f\x81\x80\x80\x0d\x0a\xff\x7f \x81 test";
+	const char *test_setting = "_0.../9Zz";
+	const char *test_hash = "_0.../9ZzX7iSJNd21sU";
+	char test_buf[21];
+	char *retval;
+	const char *p;
+
+	if (*setting != _PASSWORD_EFMT1) {
+		test_setting = "\x80x";
+		test_hash = "\x80x22/wK52ZKGA";
+	}
+
+	/*
+	 * Hash the supplied password.
+	 */
+	retval = _crypt_extended_r_uut(key, setting, output);
+
+	/*
+	 * Perform a quick self-test.  It is important that we make both calls
+	 * to _crypt_extended_r_uut() 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.
+	 */
+	p = _crypt_extended_r_uut(test_key, test_setting, test_buf);
+	if (p && !strcmp(p, test_hash) && retval)
+		return retval;
+
+	return (setting[0]=='*') ? "x" : "*";
+}
diff --git a/crypt_md5.c b/crypt_md5.c
new file mode 100644
index 0000000..6e75b36
--- /dev/null
+++ b/crypt_md5.c
@@ -0,0 +1,285 @@
+/*
+ * md5 crypt implementation
+ *
+ * original md5 crypt design is from Poul-Henning Kamp
+ * this implementation was created based on the code in freebsd
+ * at least 32bit int is assumed, key is limited and $1$ prefix is mandatory,
+ * on error "*" is returned
+ */
+#include <string.h>
+#include <stdint.h>
+
+/* public domain md5 implementation based on rfc1321 and libtomcrypt */
+
+struct md5 {
+	uint64_t len;    /* processed message length */
+	uint32_t h[4];   /* hash state */
+	uint8_t buf[64]; /* message block buffer */
+};
+
+static uint32_t rol(uint32_t n, int k) { return (n << k) | (n >> (32-k)); }
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define G(x,y,z) (y ^ (z & (y ^ x)))
+#define H(x,y,z) (x ^ y ^ z)
+#define I(x,y,z) (y ^ (x | ~z))
+#define FF(a,b,c,d,w,s,t) a += F(b,c,d) + w + t; a = rol(a,s) + b
+#define GG(a,b,c,d,w,s,t) a += G(b,c,d) + w + t; a = rol(a,s) + b
+#define HH(a,b,c,d,w,s,t) a += H(b,c,d) + w + t; a = rol(a,s) + b
+#define II(a,b,c,d,w,s,t) a += I(b,c,d) + w + t; a = rol(a,s) + b
+
+static const uint32_t tab[64] = {
+0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static void processblock(struct md5 *s, const uint8_t *buf)
+{
+	uint32_t i, W[16], a, b, c, d;
+
+	for (i = 0; i < 16; i++) {
+		W[i] = buf[4*i];
+		W[i] |= (uint32_t)buf[4*i+1]<<8;
+		W[i] |= (uint32_t)buf[4*i+2]<<16;
+		W[i] |= (uint32_t)buf[4*i+3]<<24;
+	}
+
+	a = s->h[0];
+	b = s->h[1];
+	c = s->h[2];
+	d = s->h[3];
+
+	i = 0;
+	while (i < 16) {
+		FF(a,b,c,d, W[i],  7, tab[i]); i++;
+		FF(d,a,b,c, W[i], 12, tab[i]); i++;
+		FF(c,d,a,b, W[i], 17, tab[i]); i++;
+		FF(b,c,d,a, W[i], 22, tab[i]); i++;
+	}
+	while (i < 32) {
+		GG(a,b,c,d, W[(5*i+1)%16],  5, tab[i]); i++;
+		GG(d,a,b,c, W[(5*i+1)%16],  9, tab[i]); i++;
+		GG(c,d,a,b, W[(5*i+1)%16], 14, tab[i]); i++;
+		GG(b,c,d,a, W[(5*i+1)%16], 20, tab[i]); i++;
+	}
+	while (i < 48) {
+		HH(a,b,c,d, W[(3*i+5)%16],  4, tab[i]); i++;
+		HH(d,a,b,c, W[(3*i+5)%16], 11, tab[i]); i++;
+		HH(c,d,a,b, W[(3*i+5)%16], 16, tab[i]); i++;
+		HH(b,c,d,a, W[(3*i+5)%16], 23, tab[i]); i++;
+	}
+	while (i < 64) {
+		II(a,b,c,d, W[7*i%16],  6, tab[i]); i++;
+		II(d,a,b,c, W[7*i%16], 10, tab[i]); i++;
+		II(c,d,a,b, W[7*i%16], 15, tab[i]); i++;
+		II(b,c,d,a, W[7*i%16], 21, tab[i]); i++;
+	}
+
+	s->h[0] += a;
+	s->h[1] += b;
+	s->h[2] += c;
+	s->h[3] += d;
+}
+
+static void pad(struct md5 *s)
+{
+	unsigned r = s->len % 64;
+
+	s->buf[r++] = 0x80;
+	if (r > 56) {
+		memset(s->buf + r, 0, 64 - r);
+		r = 0;
+		processblock(s, s->buf);
+	}
+	memset(s->buf + r, 0, 56 - r);
+	s->len *= 8;
+	s->buf[56] = s->len;
+	s->buf[57] = s->len >> 8;
+	s->buf[58] = s->len >> 16;
+	s->buf[59] = s->len >> 24;
+	s->buf[60] = s->len >> 32;
+	s->buf[61] = s->len >> 40;
+	s->buf[62] = s->len >> 48;
+	s->buf[63] = s->len >> 56;
+	processblock(s, s->buf);
+}
+
+static void md5_init(struct md5 *s)
+{
+	s->len = 0;
+	s->h[0] = 0x67452301;
+	s->h[1] = 0xefcdab89;
+	s->h[2] = 0x98badcfe;
+	s->h[3] = 0x10325476;
+}
+
+static void md5_sum(struct md5 *s, uint8_t *md)
+{
+	int i;
+
+	pad(s);
+	for (i = 0; i < 4; i++) {
+		md[4*i] = s->h[i];
+		md[4*i+1] = s->h[i] >> 8;
+		md[4*i+2] = s->h[i] >> 16;
+		md[4*i+3] = s->h[i] >> 24;
+	}
+}
+
+static void md5_update(struct md5 *s, const void *m, unsigned long len)
+{
+	const uint8_t *p = m;
+	unsigned r = s->len % 64;
+
+	s->len += len;
+	if (r) {
+		if (len < 64 - r) {
+			memcpy(s->buf + r, p, len);
+			return;
+		}
+		memcpy(s->buf + r, p, 64 - r);
+		len -= 64 - r;
+		p += 64 - r;
+		processblock(s, s->buf);
+	}
+	for (; len >= 64; len -= 64, p += 64)
+		processblock(s, p);
+	memcpy(s->buf, p, len);
+}
+
+/*-
+ * Copyright (c) 2003 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* key limit is not part of the original design, added for DoS protection */
+#define KEY_MAX 30000
+#define SALT_MAX 8
+
+static const unsigned char b64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *to64(char *s, unsigned int u, int n)
+{
+	while (--n >= 0) {
+		*s++ = b64[u % 64];
+		u /= 64;
+	}
+	return s;
+}
+
+static char *md5crypt(const char *key, const char *setting, char *output)
+{
+	struct md5 ctx;
+	unsigned char md[16];
+	unsigned int i, klen, slen;
+	const char *salt;
+	char *p;
+
+	/* reject large keys */
+	klen = strnlen(key, KEY_MAX+1);
+	if (klen > KEY_MAX)
+		return 0;
+
+	/* setting: $1$salt$ (closing $ is optional) */
+	if (strncmp(setting, "$1$", 3) != 0)
+		return 0;
+	salt = setting + 3;
+	for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++);
+	slen = i;
+
+	/* md5(key salt key) */
+	md5_init(&ctx);
+	md5_update(&ctx, key, klen);
+	md5_update(&ctx, salt, slen);
+	md5_update(&ctx, key, klen);
+	md5_sum(&ctx, md);
+
+	/* md5(key $1$ salt repeated-md weird-key[0]-0) */
+	md5_init(&ctx);
+	md5_update(&ctx, key, klen);
+	md5_update(&ctx, setting, 3 + slen);
+	for (i = klen; i > sizeof md; i -= sizeof md)
+		md5_update(&ctx, md, sizeof md);
+	md5_update(&ctx, md, i);
+	md[0] = 0;
+	for (i = klen; i; i >>= 1)
+		if (i & 1)
+			md5_update(&ctx, md, 1);
+		else
+			md5_update(&ctx, key, 1);
+	md5_sum(&ctx, md);
+
+	/* md = f(md, key, salt) iteration */
+	for (i = 0; i < 1000; i++) {
+		md5_init(&ctx);
+		if (i % 2)
+			md5_update(&ctx, key, klen);
+		else
+			md5_update(&ctx, md, sizeof md);
+		if (i % 3)
+			md5_update(&ctx, salt, slen);
+		if (i % 7)
+			md5_update(&ctx, key, klen);
+		if (i % 2)
+			md5_update(&ctx, md, sizeof md);
+		else
+			md5_update(&ctx, key, klen);
+		md5_sum(&ctx, md);
+	}
+
+	/* output is $1$salt$hash */
+	memcpy(output, setting, 3 + slen);
+	p = output + 3 + slen;
+	*p++ = '$';
+	static const unsigned char perm[][3] = {
+		0,6,12,1,7,13,2,8,14,3,9,15,4,10,5 };
+	for (i=0; i<5; i++) p = to64(p,
+		(md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4);
+	p = to64(p, md[11], 2);
+	*p = 0;
+
+	return output;
+}
+
+char *__crypt_md5(const char *key, const char *setting, char *output)
+{
+	static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
+	static const char testsetting[] = "$1$abcd0123$";
+	static const char testhash[] = "$1$abcd0123$9Qcg8DyviekV3tDGMZynJ1";
+	char testbuf[64];
+	char *p, *q;
+
+	p = md5crypt(key, setting, output);
+	/* self test and stack cleanup */
+	q = md5crypt(testkey, testsetting, testbuf);
+	if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
+		return "*";
+	return p;
+}
diff --git a/crypt_r.c b/crypt_r.c
new file mode 100644
index 0000000..75ba60b
--- /dev/null
+++ b/crypt_r.c
@@ -0,0 +1,29 @@
+#include <crypt.h>
+
+struct crypt_data;
+
+char *__crypt_des(const char *, const char *, char *);
+char *__crypt_md5(const char *, const char *, char *);
+char *__crypt_blowfish(const char *, const char *, char *);
+char *__crypt_sha256(const char *, const char *, char *);
+char *__crypt_sha512(const char *, const char *, char *);
+
+char *__crypt_r(const char *key, const char *salt, struct crypt_data *data)
+{
+	/* Per the crypt_r API, the caller has provided a pointer to
+	 * struct crypt_data; however, this implementation does not
+	 * use the structure to store any internal state, and treats
+	 * it purely as a char buffer for storing the result. */
+	char *output = (char *)data;
+	if (salt[0] == '$' && salt[1] && salt[2]) {
+		if (salt[1] == '1' && salt[2] == '$')
+			return __crypt_md5(key, salt, output);
+		if (salt[1] == '2' && salt[3] == '$')
+			return __crypt_blowfish(key, salt, output);
+		if (salt[1] == '5' && salt[2] == '$')
+			return __crypt_sha256(key, salt, output);
+		if (salt[1] == '6' && salt[2] == '$')
+			return __crypt_sha512(key, salt, output);
+	}
+	return __crypt_des(key, salt, output);
+}
diff --git a/crypt_sha256.c b/crypt_sha256.c
new file mode 100644
index 0000000..e885dc6
--- /dev/null
+++ b/crypt_sha256.c
@@ -0,0 +1,322 @@
+/*
+ * public domain sha256 crypt implementation
+ *
+ * original sha crypt design: http://people.redhat.com/drepper/SHA-crypt.txt
+ * in this implementation at least 32bit int is assumed,
+ * key length is limited, the $5$ prefix is mandatory, '\n' and ':' is rejected
+ * in the salt and rounds= setting must contain a valid iteration count,
+ * on error "*" is returned.
+ */
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+/* public domain sha256 implementation based on fips180-3 */
+
+struct sha256 {
+	uint64_t len;    /* processed message length */
+	uint32_t h[8];   /* hash state */
+	uint8_t buf[64]; /* message block buffer */
+};
+
+static uint32_t ror(uint32_t n, int k) { return (n >> k) | (n << (32-k)); }
+#define Ch(x,y,z)  (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
+#define S0(x)      (ror(x,2) ^ ror(x,13) ^ ror(x,22))
+#define S1(x)      (ror(x,6) ^ ror(x,11) ^ ror(x,25))
+#define R0(x)      (ror(x,7) ^ ror(x,18) ^ (x>>3))
+#define R1(x)      (ror(x,17) ^ ror(x,19) ^ (x>>10))
+
+static const uint32_t K[64] = {
+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+static void processblock(struct sha256 *s, const uint8_t *buf)
+{
+	uint32_t W[64], t1, t2, a, b, c, d, e, f, g, h;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		W[i] = (uint32_t)buf[4*i]<<24;
+		W[i] |= (uint32_t)buf[4*i+1]<<16;
+		W[i] |= (uint32_t)buf[4*i+2]<<8;
+		W[i] |= buf[4*i+3];
+	}
+	for (; i < 64; i++)
+		W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
+	a = s->h[0];
+	b = s->h[1];
+	c = s->h[2];
+	d = s->h[3];
+	e = s->h[4];
+	f = s->h[5];
+	g = s->h[6];
+	h = s->h[7];
+	for (i = 0; i < 64; i++) {
+		t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
+		t2 = S0(a) + Maj(a,b,c);
+		h = g;
+		g = f;
+		f = e;
+		e = d + t1;
+		d = c;
+		c = b;
+		b = a;
+		a = t1 + t2;
+	}
+	s->h[0] += a;
+	s->h[1] += b;
+	s->h[2] += c;
+	s->h[3] += d;
+	s->h[4] += e;
+	s->h[5] += f;
+	s->h[6] += g;
+	s->h[7] += h;
+}
+
+static void pad(struct sha256 *s)
+{
+	unsigned r = s->len % 64;
+
+	s->buf[r++] = 0x80;
+	if (r > 56) {
+		memset(s->buf + r, 0, 64 - r);
+		r = 0;
+		processblock(s, s->buf);
+	}
+	memset(s->buf + r, 0, 56 - r);
+	s->len *= 8;
+	s->buf[56] = s->len >> 56;
+	s->buf[57] = s->len >> 48;
+	s->buf[58] = s->len >> 40;
+	s->buf[59] = s->len >> 32;
+	s->buf[60] = s->len >> 24;
+	s->buf[61] = s->len >> 16;
+	s->buf[62] = s->len >> 8;
+	s->buf[63] = s->len;
+	processblock(s, s->buf);
+}
+
+static void sha256_init(struct sha256 *s)
+{
+	s->len = 0;
+	s->h[0] = 0x6a09e667;
+	s->h[1] = 0xbb67ae85;
+	s->h[2] = 0x3c6ef372;
+	s->h[3] = 0xa54ff53a;
+	s->h[4] = 0x510e527f;
+	s->h[5] = 0x9b05688c;
+	s->h[6] = 0x1f83d9ab;
+	s->h[7] = 0x5be0cd19;
+}
+
+static void sha256_sum(struct sha256 *s, uint8_t *md)
+{
+	int i;
+
+	pad(s);
+	for (i = 0; i < 8; i++) {
+		md[4*i] = s->h[i] >> 24;
+		md[4*i+1] = s->h[i] >> 16;
+		md[4*i+2] = s->h[i] >> 8;
+		md[4*i+3] = s->h[i];
+	}
+}
+
+static void sha256_update(struct sha256 *s, const void *m, unsigned long len)
+{
+	const uint8_t *p = m;
+	unsigned r = s->len % 64;
+
+	s->len += len;
+	if (r) {
+		if (len < 64 - r) {
+			memcpy(s->buf + r, p, len);
+			return;
+		}
+		memcpy(s->buf + r, p, 64 - r);
+		len -= 64 - r;
+		p += 64 - r;
+		processblock(s, s->buf);
+	}
+	for (; len >= 64; len -= 64, p += 64)
+		processblock(s, p);
+	memcpy(s->buf, p, len);
+}
+
+static const unsigned char b64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *to64(char *s, unsigned int u, int n)
+{
+	while (--n >= 0) {
+		*s++ = b64[u % 64];
+		u /= 64;
+	}
+	return s;
+}
+
+/* key limit is not part of the original design, added for DoS protection.
+ * rounds limit has been lowered (versus the reference/spec), also for DoS
+ * protection. runtime is O(klen^2 + klen*rounds) */
+#define KEY_MAX 256
+#define SALT_MAX 16
+#define ROUNDS_DEFAULT 5000
+#define ROUNDS_MIN 1000
+#define ROUNDS_MAX 9999999
+
+/* hash n bytes of the repeated md message digest */
+static void hashmd(struct sha256 *s, unsigned int n, const void *md)
+{
+	unsigned int i;
+
+	for (i = n; i > 32; i -= 32)
+		sha256_update(s, md, 32);
+	sha256_update(s, md, i);
+}
+
+static char *sha256crypt(const char *key, const char *setting, char *output)
+{
+	struct sha256 ctx;
+	unsigned char md[32], kmd[32], smd[32];
+	unsigned int i, r, klen, slen;
+	char rounds[20] = "";
+	const char *salt;
+	char *p;
+
+	/* reject large keys */
+	klen = strnlen(key, KEY_MAX+1);
+	if (klen > KEY_MAX)
+		return 0;
+
+	/* setting: $5$rounds=n$salt$ (rounds=n$ and closing $ are optional) */
+	if (strncmp(setting, "$5$", 3) != 0)
+		return 0;
+	salt = setting + 3;
+
+	r = ROUNDS_DEFAULT;
+	if (strncmp(salt, "rounds=", sizeof "rounds=" - 1) == 0) {
+		unsigned long u;
+		char *end;
+
+		/*
+		 * this is a deviation from the reference:
+		 * bad rounds setting is rejected if it is
+		 * - empty
+		 * - unterminated (missing '$')
+		 * - begins with anything but a decimal digit
+		 * the reference implementation treats these bad
+		 * rounds as part of the salt or parse them with
+		 * strtoul semantics which may cause problems
+		 * including non-portable hashes that depend on
+		 * the host's value of ULONG_MAX.
+		 */
+		salt += sizeof "rounds=" - 1;
+		if (!isdigit(*salt))
+			return 0;
+		u = strtoul(salt, &end, 10);
+		if (*end != '$')
+			return 0;
+		salt = end+1;
+		if (u < ROUNDS_MIN)
+			r = ROUNDS_MIN;
+		else if (u > ROUNDS_MAX)
+			return 0;
+		else
+			r = u;
+		/* needed when rounds is zero prefixed or out of bounds */
+		sprintf(rounds, "rounds=%u$", r);
+	}
+
+	for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++)
+		/* reject characters that interfere with /etc/shadow parsing */
+		if (salt[i] == '\n' || salt[i] == ':')
+			return 0;
+	slen = i;
+
+	/* B = sha(key salt key) */
+	sha256_init(&ctx);
+	sha256_update(&ctx, key, klen);
+	sha256_update(&ctx, salt, slen);
+	sha256_update(&ctx, key, klen);
+	sha256_sum(&ctx, md);
+
+	/* A = sha(key salt repeat-B alternate-B-key) */
+	sha256_init(&ctx);
+	sha256_update(&ctx, key, klen);
+	sha256_update(&ctx, salt, slen);
+	hashmd(&ctx, klen, md);
+	for (i = klen; i > 0; i >>= 1)
+		if (i & 1)
+			sha256_update(&ctx, md, sizeof md);
+		else
+			sha256_update(&ctx, key, klen);
+	sha256_sum(&ctx, md);
+
+	/* DP = sha(repeat-key), this step takes O(klen^2) time */
+	sha256_init(&ctx);
+	for (i = 0; i < klen; i++)
+		sha256_update(&ctx, key, klen);
+	sha256_sum(&ctx, kmd);
+
+	/* DS = sha(repeat-salt) */
+	sha256_init(&ctx);
+	for (i = 0; i < 16 + md[0]; i++)
+		sha256_update(&ctx, salt, slen);
+	sha256_sum(&ctx, smd);
+
+	/* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */
+	for (i = 0; i < r; i++) {
+		sha256_init(&ctx);
+		if (i % 2)
+			hashmd(&ctx, klen, kmd);
+		else
+			sha256_update(&ctx, md, sizeof md);
+		if (i % 3)
+			sha256_update(&ctx, smd, slen);
+		if (i % 7)
+			hashmd(&ctx, klen, kmd);
+		if (i % 2)
+			sha256_update(&ctx, md, sizeof md);
+		else
+			hashmd(&ctx, klen, kmd);
+		sha256_sum(&ctx, md);
+	}
+
+	/* output is $5$rounds=n$salt$hash */
+	p = output;
+	p += sprintf(p, "$5$%s%.*s$", rounds, slen, salt);
+	static const unsigned char perm[][3] = {
+		0,10,20,21,1,11,12,22,2,3,13,23,24,4,14,
+		15,25,5,6,16,26,27,7,17,18,28,8,9,19,29 };
+	for (i=0; i<10; i++) p = to64(p,
+		(md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4);
+	p = to64(p, (md[31]<<8)|md[30], 3);
+	*p = 0;
+	return output;
+}
+
+char *__crypt_sha256(const char *key, const char *setting, char *output)
+{
+	static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
+	static const char testsetting[] = "$5$rounds=1234$abc0123456789$";
+	static const char testhash[] = "$5$rounds=1234$abc0123456789$3VfDjPt05VHFn47C/ojFZ6KRPYrOjj1lLbH.dkF3bZ6";
+	char testbuf[128];
+	char *p, *q;
+
+	p = sha256crypt(key, setting, output);
+	/* self test and stack cleanup */
+	q = sha256crypt(testkey, testsetting, testbuf);
+	if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
+		return "*";
+	return p;
+}
diff --git a/crypt_sha512.c b/crypt_sha512.c
new file mode 100644
index 0000000..39970ca
--- /dev/null
+++ b/crypt_sha512.c
@@ -0,0 +1,371 @@
+/*
+ * public domain sha512 crypt implementation
+ *
+ * original sha crypt design: http://people.redhat.com/drepper/SHA-crypt.txt
+ * in this implementation at least 32bit int is assumed,
+ * key length is limited, the $6$ prefix is mandatory, '\n' and ':' is rejected
+ * in the salt and rounds= setting must contain a valid iteration count,
+ * on error "*" is returned.
+ */
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+/* public domain sha512 implementation based on fips180-3 */
+/* >=2^64 bits messages are not supported (about 2000 peta bytes) */
+
+struct sha512 {
+	uint64_t len;     /* processed message length */
+	uint64_t h[8];    /* hash state */
+	uint8_t buf[128]; /* message block buffer */
+};
+
+static uint64_t ror(uint64_t n, int k) { return (n >> k) | (n << (64-k)); }
+#define Ch(x,y,z)  (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) ((x & y) | (z & (x | y)))
+#define S0(x)      (ror(x,28) ^ ror(x,34) ^ ror(x,39))
+#define S1(x)      (ror(x,14) ^ ror(x,18) ^ ror(x,41))
+#define R0(x)      (ror(x,1) ^ ror(x,8) ^ (x>>7))
+#define R1(x)      (ror(x,19) ^ ror(x,61) ^ (x>>6))
+
+static const uint64_t K[80] = {
+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+static void processblock(struct sha512 *s, const uint8_t *buf)
+{
+	uint64_t W[80], t1, t2, a, b, c, d, e, f, g, h;
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		W[i] = (uint64_t)buf[8*i]<<56;
+		W[i] |= (uint64_t)buf[8*i+1]<<48;
+		W[i] |= (uint64_t)buf[8*i+2]<<40;
+		W[i] |= (uint64_t)buf[8*i+3]<<32;
+		W[i] |= (uint64_t)buf[8*i+4]<<24;
+		W[i] |= (uint64_t)buf[8*i+5]<<16;
+		W[i] |= (uint64_t)buf[8*i+6]<<8;
+		W[i] |= buf[8*i+7];
+	}
+	for (; i < 80; i++)
+		W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
+	a = s->h[0];
+	b = s->h[1];
+	c = s->h[2];
+	d = s->h[3];
+	e = s->h[4];
+	f = s->h[5];
+	g = s->h[6];
+	h = s->h[7];
+	for (i = 0; i < 80; i++) {
+		t1 = h + S1(e) + Ch(e,f,g) + K[i] + W[i];
+		t2 = S0(a) + Maj(a,b,c);
+		h = g;
+		g = f;
+		f = e;
+		e = d + t1;
+		d = c;
+		c = b;
+		b = a;
+		a = t1 + t2;
+	}
+	s->h[0] += a;
+	s->h[1] += b;
+	s->h[2] += c;
+	s->h[3] += d;
+	s->h[4] += e;
+	s->h[5] += f;
+	s->h[6] += g;
+	s->h[7] += h;
+}
+
+static void pad(struct sha512 *s)
+{
+	unsigned r = s->len % 128;
+
+	s->buf[r++] = 0x80;
+	if (r > 112) {
+		memset(s->buf + r, 0, 128 - r);
+		r = 0;
+		processblock(s, s->buf);
+	}
+	memset(s->buf + r, 0, 120 - r);
+	s->len *= 8;
+	s->buf[120] = s->len >> 56;
+	s->buf[121] = s->len >> 48;
+	s->buf[122] = s->len >> 40;
+	s->buf[123] = s->len >> 32;
+	s->buf[124] = s->len >> 24;
+	s->buf[125] = s->len >> 16;
+	s->buf[126] = s->len >> 8;
+	s->buf[127] = s->len;
+	processblock(s, s->buf);
+}
+
+static void sha512_init(struct sha512 *s)
+{
+	s->len = 0;
+	s->h[0] = 0x6a09e667f3bcc908ULL;
+	s->h[1] = 0xbb67ae8584caa73bULL;
+	s->h[2] = 0x3c6ef372fe94f82bULL;
+	s->h[3] = 0xa54ff53a5f1d36f1ULL;
+	s->h[4] = 0x510e527fade682d1ULL;
+	s->h[5] = 0x9b05688c2b3e6c1fULL;
+	s->h[6] = 0x1f83d9abfb41bd6bULL;
+	s->h[7] = 0x5be0cd19137e2179ULL;
+}
+
+static void sha512_sum(struct sha512 *s, uint8_t *md)
+{
+	int i;
+
+	pad(s);
+	for (i = 0; i < 8; i++) {
+		md[8*i] = s->h[i] >> 56;
+		md[8*i+1] = s->h[i] >> 48;
+		md[8*i+2] = s->h[i] >> 40;
+		md[8*i+3] = s->h[i] >> 32;
+		md[8*i+4] = s->h[i] >> 24;
+		md[8*i+5] = s->h[i] >> 16;
+		md[8*i+6] = s->h[i] >> 8;
+		md[8*i+7] = s->h[i];
+	}
+}
+
+static void sha512_update(struct sha512 *s, const void *m, unsigned long len)
+{
+	const uint8_t *p = m;
+	unsigned r = s->len % 128;
+
+	s->len += len;
+	if (r) {
+		if (len < 128 - r) {
+			memcpy(s->buf + r, p, len);
+			return;
+		}
+		memcpy(s->buf + r, p, 128 - r);
+		len -= 128 - r;
+		p += 128 - r;
+		processblock(s, s->buf);
+	}
+	for (; len >= 128; len -= 128, p += 128)
+		processblock(s, p);
+	memcpy(s->buf, p, len);
+}
+
+static const unsigned char b64[] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *to64(char *s, unsigned int u, int n)
+{
+	while (--n >= 0) {
+		*s++ = b64[u % 64];
+		u /= 64;
+	}
+	return s;
+}
+
+/* key limit is not part of the original design, added for DoS protection.
+ * rounds limit has been lowered (versus the reference/spec), also for DoS
+ * protection. runtime is O(klen^2 + klen*rounds) */
+#define KEY_MAX 256
+#define SALT_MAX 16
+#define ROUNDS_DEFAULT 5000
+#define ROUNDS_MIN 1000
+#define ROUNDS_MAX 9999999
+
+/* hash n bytes of the repeated md message digest */
+static void hashmd(struct sha512 *s, unsigned int n, const void *md)
+{
+	unsigned int i;
+
+	for (i = n; i > 64; i -= 64)
+		sha512_update(s, md, 64);
+	sha512_update(s, md, i);
+}
+
+static char *sha512crypt(const char *key, const char *setting, char *output)
+{
+	struct sha512 ctx;
+	unsigned char md[64], kmd[64], smd[64];
+	unsigned int i, r, klen, slen;
+	char rounds[20] = "";
+	const char *salt;
+	char *p;
+
+	/* reject large keys */
+	for (i = 0; i <= KEY_MAX && key[i]; i++);
+	if (i > KEY_MAX)
+		return 0;
+	klen = i;
+
+	/* setting: $6$rounds=n$salt$ (rounds=n$ and closing $ are optional) */
+	if (strncmp(setting, "$6$", 3) != 0)
+		return 0;
+	salt = setting + 3;
+
+	r = ROUNDS_DEFAULT;
+	if (strncmp(salt, "rounds=", sizeof "rounds=" - 1) == 0) {
+		unsigned long u;
+		char *end;
+
+		/*
+		 * this is a deviation from the reference:
+		 * bad rounds setting is rejected if it is
+		 * - empty
+		 * - unterminated (missing '$')
+		 * - begins with anything but a decimal digit
+		 * the reference implementation treats these bad
+		 * rounds as part of the salt or parse them with
+		 * strtoul semantics which may cause problems
+		 * including non-portable hashes that depend on
+		 * the host's value of ULONG_MAX.
+		 */
+		salt += sizeof "rounds=" - 1;
+		if (!isdigit(*salt))
+			return 0;
+		u = strtoul(salt, &end, 10);
+		if (*end != '$')
+			return 0;
+		salt = end+1;
+		if (u < ROUNDS_MIN)
+			r = ROUNDS_MIN;
+		else if (u > ROUNDS_MAX)
+			return 0;
+		else
+			r = u;
+		/* needed when rounds is zero prefixed or out of bounds */
+		sprintf(rounds, "rounds=%u$", r);
+	}
+
+	for (i = 0; i < SALT_MAX && salt[i] && salt[i] != '$'; i++)
+		/* reject characters that interfere with /etc/shadow parsing */
+		if (salt[i] == '\n' || salt[i] == ':')
+			return 0;
+	slen = i;
+
+	/* B = sha(key salt key) */
+	sha512_init(&ctx);
+	sha512_update(&ctx, key, klen);
+	sha512_update(&ctx, salt, slen);
+	sha512_update(&ctx, key, klen);
+	sha512_sum(&ctx, md);
+
+	/* A = sha(key salt repeat-B alternate-B-key) */
+	sha512_init(&ctx);
+	sha512_update(&ctx, key, klen);
+	sha512_update(&ctx, salt, slen);
+	hashmd(&ctx, klen, md);
+	for (i = klen; i > 0; i >>= 1)
+		if (i & 1)
+			sha512_update(&ctx, md, sizeof md);
+		else
+			sha512_update(&ctx, key, klen);
+	sha512_sum(&ctx, md);
+
+	/* DP = sha(repeat-key), this step takes O(klen^2) time */
+	sha512_init(&ctx);
+	for (i = 0; i < klen; i++)
+		sha512_update(&ctx, key, klen);
+	sha512_sum(&ctx, kmd);
+
+	/* DS = sha(repeat-salt) */
+	sha512_init(&ctx);
+	for (i = 0; i < 16 + md[0]; i++)
+		sha512_update(&ctx, salt, slen);
+	sha512_sum(&ctx, smd);
+
+	/* iterate A = f(A,DP,DS), this step takes O(rounds*klen) time */
+	for (i = 0; i < r; i++) {
+		sha512_init(&ctx);
+		if (i % 2)
+			hashmd(&ctx, klen, kmd);
+		else
+			sha512_update(&ctx, md, sizeof md);
+		if (i % 3)
+			sha512_update(&ctx, smd, slen);
+		if (i % 7)
+			hashmd(&ctx, klen, kmd);
+		if (i % 2)
+			sha512_update(&ctx, md, sizeof md);
+		else
+			hashmd(&ctx, klen, kmd);
+		sha512_sum(&ctx, md);
+	}
+
+	/* output is $6$rounds=n$salt$hash */
+	p = output;
+	p += sprintf(p, "$6$%s%.*s$", rounds, slen, salt);
+#if 1
+	static const unsigned char perm[][3] = {
+		0,21,42,22,43,1,44,2,23,3,24,45,25,46,4,
+		47,5,26,6,27,48,28,49,7,50,8,29,9,30,51,
+		31,52,10,53,11,32,12,33,54,34,55,13,56,14,35,
+		15,36,57,37,58,16,59,17,38,18,39,60,40,61,19,
+		62,20,41 };
+	for (i=0; i<21; i++) p = to64(p,
+		(md[perm[i][0]]<<16)|(md[perm[i][1]]<<8)|md[perm[i][2]], 4);
+#else
+	p = to64(p, (md[0]<<16)|(md[21]<<8)|md[42], 4);
+	p = to64(p, (md[22]<<16)|(md[43]<<8)|md[1], 4);
+	p = to64(p, (md[44]<<16)|(md[2]<<8)|md[23], 4);
+	p = to64(p, (md[3]<<16)|(md[24]<<8)|md[45], 4);
+	p = to64(p, (md[25]<<16)|(md[46]<<8)|md[4], 4);
+	p = to64(p, (md[47]<<16)|(md[5]<<8)|md[26], 4);
+	p = to64(p, (md[6]<<16)|(md[27]<<8)|md[48], 4);
+	p = to64(p, (md[28]<<16)|(md[49]<<8)|md[7], 4);
+	p = to64(p, (md[50]<<16)|(md[8]<<8)|md[29], 4);
+	p = to64(p, (md[9]<<16)|(md[30]<<8)|md[51], 4);
+	p = to64(p, (md[31]<<16)|(md[52]<<8)|md[10], 4);
+	p = to64(p, (md[53]<<16)|(md[11]<<8)|md[32], 4);
+	p = to64(p, (md[12]<<16)|(md[33]<<8)|md[54], 4);
+	p = to64(p, (md[34]<<16)|(md[55]<<8)|md[13], 4);
+	p = to64(p, (md[56]<<16)|(md[14]<<8)|md[35], 4);
+	p = to64(p, (md[15]<<16)|(md[36]<<8)|md[57], 4);
+	p = to64(p, (md[37]<<16)|(md[58]<<8)|md[16], 4);
+	p = to64(p, (md[59]<<16)|(md[17]<<8)|md[38], 4);
+	p = to64(p, (md[18]<<16)|(md[39]<<8)|md[60], 4);
+	p = to64(p, (md[40]<<16)|(md[61]<<8)|md[19], 4);
+	p = to64(p, (md[62]<<16)|(md[20]<<8)|md[41], 4);
+#endif
+	p = to64(p, md[63], 2);
+	*p = 0;
+	return output;
+}
+
+char *__crypt_sha512(const char *key, const char *setting, char *output)
+{
+	static const char testkey[] = "Xy01@#\x01\x02\x80\x7f\xff\r\n\x81\t !";
+	static const char testsetting[] = "$6$rounds=1234$abc0123456789$";
+	static const char testhash[] = "$6$rounds=1234$abc0123456789$BCpt8zLrc/RcyuXmCDOE1ALqMXB2MH6n1g891HhFj8.w7LxGv.FTkqq6Vxc/km3Y0jE0j24jY5PIv/oOu6reg1";
+	char testbuf[128];
+	char *p, *q;
+
+	p = sha512crypt(key, setting, output);
+	/* self test and stack cleanup */
+	q = sha512crypt(testkey, testsetting, testbuf);
+	if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash))
+		return "*";
+	return p;
+}
diff --git a/encrypt.c b/encrypt.c
index 35a3238..9332a6d 100644
--- a/encrypt.c
+++ b/encrypt.c
@@ -1,323 +1,60 @@
-/* encrypt.c - providing 56 bit DES encryption
-   Copyright (C) 1991 Jochen Obalek
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program 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 General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#include <time.h>
-#include <string.h>
+#include <stdint.h>
 #include <stdlib.h>
+#include <unistd.h>
 
-#define BS  64
-#define BS2 32
-#define KS  48
-#define KS2 24
-#define IS  56
-#define IS2 28
-
-static char schluessel[16][KS];
-
-
-static char PC1[] =
-{
-  56, 48, 40, 32, 24, 16,  8,  0,
-  57, 49, 41, 33, 25, 17,  9,  1,
-  58, 50, 42, 34, 26, 18, 10,  2,
-  59, 51, 43, 35,
-  62, 54, 46, 38, 30, 22, 14,  6,
-  61, 53, 45, 37, 29, 21, 13,  5,
-  60, 52, 44, 36, 28, 20, 12,  4,
-  27, 19, 11,  3
+struct expanded_key {
+        uint32_t l[16], r[16];
 };
 
+void __des_setkey(const unsigned char *key, struct expanded_key *ekey);
+void __do_des(uint32_t l_in, uint32_t r_in,
+    uint32_t *l_out, uint32_t *r_out,
+    uint32_t count, uint32_t saltbits, const struct expanded_key *ekey);
 
-static char PC2[] =
-{
-  13, 16, 10, 23,  0,  4,  2, 27,
-  14,  5, 20,  9, 22, 18, 11,  3,
-  25,  7, 15,  6, 26, 19, 12,  1,
-  40, 51, 30, 36, 46, 54, 29, 39,
-  50, 44, 32, 47, 43, 48, 38, 55,
-  33, 52, 45, 41, 49, 35, 28, 31
-};
 
+static struct expanded_key __encrypt_key;
 
-static char IP[] =
+void setkey(const char *key)
 {
-  57, 49, 41, 33, 25, 17,  9,  1,
-  59, 51, 43, 35, 27, 19, 11,  3,
-  61, 53, 45, 37, 29, 21, 13,  5,
-  63, 55, 47, 39, 31, 23, 15,  7,
-  56, 48, 40, 32, 24, 16,  8,  0,
-  58, 50, 42, 34, 26, 18, 10,  2,
-  60, 52, 44, 36, 28, 20, 12,  4,
-  62, 54, 46, 38, 30, 22, 14,  6
-};
-
-
-static char EP[] =
-{
-   7, 39, 15, 47, 23, 55, 31, 63,
-   6, 38, 14, 46, 22, 54, 30, 62,
-   5, 37, 13, 45, 21, 53, 29, 61,
-   4, 36, 12, 44, 20, 52, 28, 60,
-   3, 35, 11, 43, 19, 51, 27, 59,
-   2, 34, 10, 42, 18, 50, 26, 58,
-   1, 33,  9, 41, 17, 49, 25, 57,
-   0, 32,  8, 40, 16, 48, 24, 56
-};
-
-
-static char E0[] =
-{
-  31,  0,  1,  2,  3,  4,  3,  4,
-   5,  6,  7,  8,  7,  8,  9, 10,
-  11, 12, 11, 12, 13, 14, 15, 16,
-  15, 16, 17, 18, 19, 20, 19, 20,
-  21, 22, 23, 24, 23, 24, 25, 26,
-  27, 28, 27, 28, 29, 30, 31,  0
-};
-
-
-static char E[KS];
-
-
-static char PERM[] =
-{
-  15,  6, 19, 20, 28, 11, 27, 16,
-   0, 14, 22, 25,  4, 17, 30,  9,
-   1,  7, 23, 13, 31, 26,  2,  8,
-  18, 12, 29,  5, 21, 10,  3, 24
-};
-
-
-static char S_BOX[][64] =
-{
-  {
-    14,  0,  4, 15, 13,  7,  1,  4,  2, 14, 15,  2, 11, 13,  8,  1,
-     3, 10, 10,  6,  6, 12, 12, 11,  5,  9,  9,  5,  0,  3,  7,  8,
-     4, 15,  1, 12, 14,  8,  8,  2, 13,  4,  6,  9,  2,  1, 11,  7,
-    15,  5, 12, 11,  9,  3,  7, 14,  3, 10, 10,  0,  5,  6,  0, 13
-  },
-  {
-    15,  3,  1, 13,  8,  4, 14,  7,  6, 15, 11,  2,  3,  8,  4, 14,
-     9, 12,  7,  0,  2,  1, 13, 10, 12,  6,  0,  9,  5, 11, 10,  5,
-     0, 13, 14,  8,  7, 10, 11,  1, 10,  3,  4, 15, 13,  4,  1,  2,
-     5, 11,  8,  6, 12,  7,  6, 12,  9,  0,  3,  5,  2, 14, 15,  9
-  },
-  {
-    10, 13,  0,  7,  9,  0, 14,  9,  6,  3,  3,  4, 15,  6,  5, 10,
-     1,  2, 13,  8, 12,  5,  7, 14, 11, 12,  4, 11,  2, 15,  8,  1,
-    13,  1,  6, 10,  4, 13,  9,  0,  8,  6, 15,  9,  3,  8,  0,  7,
-    11,  4,  1, 15,  2, 14, 12,  3,  5, 11, 10,  5, 14,  2,  7, 12
-  },
-  {
-     7, 13, 13,  8, 14, 11,  3,  5,  0,  6,  6, 15,  9,  0, 10,  3,
-     1,  4,  2,  7,  8,  2,  5, 12, 11,  1, 12, 10,  4, 14, 15,  9,
-    10,  3,  6, 15,  9,  0,  0,  6, 12, 10, 11,  1,  7, 13, 13,  8,
-    15,  9,  1,  4,  3,  5, 14, 11,  5, 12,  2,  7,  8,  2,  4, 14
-  },
-  {
-     2, 14, 12, 11,  4,  2,  1, 12,  7,  4, 10,  7, 11, 13,  6,  1,
-     8,  5,  5,  0,  3, 15, 15, 10, 13,  3,  0,  9, 14,  8,  9,  6,
-     4, 11,  2,  8,  1, 12, 11,  7, 10,  1, 13, 14,  7,  2,  8, 13,
-    15,  6,  9, 15, 12,  0,  5,  9,  6, 10,  3,  4,  0,  5, 14,  3
-  },
-  {
-    12, 10,  1, 15, 10,  4, 15,  2,  9,  7,  2, 12,  6,  9,  8,  5,
-     0,  6, 13,  1,  3, 13,  4, 14, 14,  0,  7, 11,  5,  3, 11,  8,
-     9,  4, 14,  3, 15,  2,  5, 12,  2,  9,  8,  5, 12, 15,  3, 10,
-     7, 11,  0, 14,  4,  1, 10,  7,  1,  6, 13,  0, 11,  8,  6, 13
-  },
-  {
-     4, 13, 11,  0,  2, 11, 14,  7, 15,  4,  0,  9,  8,  1, 13, 10,
-     3, 14, 12,  3,  9,  5,  7, 12,  5,  2, 10, 15,  6,  8,  1,  6,
-     1,  6,  4, 11, 11, 13, 13,  8, 12,  1,  3,  4,  7, 10, 14,  7,
-    10,  9, 15,  5,  6,  0,  8, 15,  0, 14,  5,  2,  9,  3,  2, 12
-  },
-  {
-    13,  1,  2, 15,  8, 13,  4,  8,  6, 10, 15,  3, 11,  7,  1,  4,
-    10, 12,  9,  5,  3,  6, 14, 11,  5,  0,  0, 14, 12,  9,  7,  2,
-     7,  2, 11,  1,  4, 14,  1,  7,  9,  4, 12, 10, 14,  8,  2, 13,
-     0, 15,  6, 12, 10,  9, 13,  0, 15,  3,  3,  5,  5,  6,  8, 11
-  }
-};
+	unsigned char bkey[8];
+	int i, j;
 
-static void 
-perm (a, e, pc, n)
-     register char *a, *e;
-     register char *pc;
-     int n;
-{
-  for (; n--; pc++, a++)
-    *a = e[*(unsigned char *) pc];
-}
-
-static void 
-crypt_main (nachr_l, nachr_r, schl)
-     register char *nachr_l, *nachr_r;
-     register char *schl;
-{
-  char tmp[KS];
-  register int sbval;
-  register char *tp = tmp;
-  register char *e = E;
-  register int i, j;
-
-  for (i = 0; i < 8; i++)
-    {
-      for (j = 0, sbval = 0; j < 6; j++)
-	sbval = (sbval << 1) | (nachr_r[*(unsigned char *) e++] ^ *schl++);
-      sbval = S_BOX[i][sbval];
-      for (tp += 4, j = 4; j--; sbval >>= 1)
-	*--tp = sbval & 1;
-      tp += 4;
-    }
-
-  e = PERM;
-  for (i = 0; i < BS2; i++)
-    *nachr_l++ ^= tmp[*(unsigned char *) e++];
-}
-
-void 
-encrypt (char *nachr, int decr)
-{
-  char (*schl)[KS] = decr ? schluessel + 15 : schluessel;
-  char tmp[BS];
-  int i;
-
-  perm (tmp, nachr, IP, BS);
-
-  for (i = 8; i--;)
-    {
-      crypt_main (tmp, tmp + BS2, *schl);
-      if (decr)
-	schl--;
-      else
-	schl++;
-      crypt_main (tmp + BS2, tmp, *schl);
-      if (decr)
-	schl--;
-      else
-	schl++;
-    }
-
-  perm (nachr, tmp, EP, BS);
-}
-
-void 
-setkey (const char *schl)
-{
-  char tmp1[IS];
-  register unsigned int ls = 0x7efc;
-  register int i, j, k;
-  register int shval = 0;
-  register char *akt_schl;
-
-  memcpy (E, E0, KS);
-  perm (tmp1, schl, PC1, IS);
-
-  for (i = 0; i < 16; i++)
-    {
-      shval += 1 + (ls & 1);
-      akt_schl = schluessel[i];
-      for (j = 0; j < KS; j++)
-	{
-	  if ((k = PC2[j]) >= IS2)
-	    {
-	      if ((k += shval) >= IS)
-		k = (k - IS2) % IS2 + IS2;
-	    }
-	  else if ((k += shval) >= IS2)
-	    k %= IS2;
-	  *akt_schl++ = tmp1[k];
+	for (i = 0; i < 8; i++) {
+		bkey[i] = 0;
+		for (j = 7; j >= 0; j--, key++)
+			bkey[i] |= (uint32_t)(*key & 1) << j;
 	}
-      ls >>= 1;
-    }
+
+	__des_setkey(bkey, &__encrypt_key);
 }
 
-char *
-crypt (const char *wort, const char *salt)
+void encrypt(char *block, int edflag)
 {
-  static char retkey[14];
-  char key[BS + 2];
-  char *k;
-  int tmp, keybyte;
-  int i, j;
-
-  memset (key, 0, BS + 2);
-
-  for (k = key, i = 0; i < BS; i++)
-    {
-      if (!(keybyte = *wort++))
-	break;
-      k += 7;
-      for (j = 0; j < 7; j++, i++)
-	{
-	  *--k = keybyte & 1;
-	  keybyte >>= 1;
-	}
-      k += 8;
-    }
+	struct expanded_key decrypt_key, *key;
+	uint32_t b[2];
+	int i, j;
+	char *p;
 
-  setkey (key);
-  memset (key, 0, BS + 2);
-
-  for (k = E, i = 0; i < 2; i++)
-    {
-      retkey[i] = keybyte = *salt++;
-      if (keybyte > 'Z')
-	keybyte -= 'a' - 'Z' - 1;
-      if (keybyte > '9')
-	keybyte -= 'A' - '9' - 1;
-      keybyte -= '.';
-
-      for (j = 0; j < 6; j++, keybyte >>= 1, k++)
-	{
-	  if (!(keybyte & 1))
-	    continue;
-	  tmp = *k;
-	  *k = k[24];
-	  k[24] = tmp;
+	p = block;
+	for (i = 0; i < 2; i++) {
+		b[i] = 0;
+		for (j = 31; j >= 0; j--, p++)
+			b[i] |= (uint32_t)(*p & 1) << j;
 	}
-    }
 
-  for (i = 0; i < 25; i++)
-    encrypt (key, 0);
-
-  for (k = key, i = 0; i < 11; i++)
-    {
-      for (j = keybyte = 0; j < 6; j++)
-	{
-	  keybyte <<= 1;
-	  keybyte |= *k++;
+	key = &__encrypt_key;
+	if (edflag) {
+		key = &decrypt_key;
+		for (i = 0; i < 16; i++) {
+			decrypt_key.l[i] = __encrypt_key.l[15-i];
+			decrypt_key.r[i] = __encrypt_key.r[15-i];
+		}
 	}
 
-      keybyte += '.';
-      if (keybyte > '9')
-	keybyte += 'A' - '9' - 1;
-      if (keybyte > 'Z')
-	keybyte += 'a' - 'Z' - 1;
-      retkey[i + 2] = keybyte;
-    }
-
-  retkey[i + 2] = 0;
+	__do_des(b[0], b[1], b, b + 1, 1, 0, key);
 
-  if (!retkey[1])
-    retkey[1] = *retkey;
-
-  return retkey;
+	p = block;
+	for (i = 0; i < 2; i++)
+		for (j = 31; j >= 0; j--)
+			*p++ = b[i]>>j & 1;
 }
-
-
diff --git a/encrypt.h b/encrypt.h
deleted file mode 100644
index df053e7..0000000
--- a/encrypt.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* encrypt.h - API to 56 bit DES encryption via  calls
-               encrypt(3), setkey(3) and crypt(3)
-   Copyright (C) 1991 Jochen Obalek
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program 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 General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#ifndef _ENCRYPT_H_
-#define _ENCRYPT_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-void encrypt (char *block, int edflag);
-void setkey (const char *key);
-char *crypt (const char *key, const char *salt);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ENCRYPT_H_ */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.