From 14126498907f52ada5c2358144a4bb137660d0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Fri, 13 Jul 2018 12:02:19 +0200 Subject: [PATCH] Add patch to update to recent development branch Re-enable SUNMD5 support as it is BSD licensed now Build compatibility symbols for glibc only --- libxcrypt-4.0.1_to_develop.patch | 12687 +++++++++++++++++++++++++++++ libxcrypt-rh1592445.patch | 668 -- libxcrypt.spec | 30 +- 3 files changed, 12703 insertions(+), 682 deletions(-) create mode 100644 libxcrypt-4.0.1_to_develop.patch delete mode 100644 libxcrypt-rh1592445.patch diff --git a/libxcrypt-4.0.1_to_develop.patch b/libxcrypt-4.0.1_to_develop.patch new file mode 100644 index 0000000..b9b8c4a --- /dev/null +++ b/libxcrypt-4.0.1_to_develop.patch @@ -0,0 +1,12687 @@ +From 0bf9b35bb04b9f35a43e2ff6493d6a5ecc3c9db1 Mon Sep 17 00:00:00 2001 +From: Thorsten Kukuk +Date: Tue, 22 May 2018 11:42:07 +0200 +Subject: [PATCH 01/38] Fix spelling of SUSE + +--- + Makefile.am | 4 ++-- + README.md | 2 +- + libcrypt.map.in | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index a7e726f..90fe733 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -71,7 +71,7 @@ crypt.h: crypt-base.h gen-crypt-h.awk config.h + $(AM_V_at)mv -f crypt.h.T crypt.h + + # When we are being binary compatible, also install symbolic links to +-# mimic SuSE's libowcrypt; any program that uses -lowcrypt in its ++# mimic SUSE's libowcrypt; any program that uses -lowcrypt in its + # build, or already has a NEEDED entry for libowcrypt.so.1, will be + # redirected to libcrypt. The OW_CRYPT_1.0 symbol versions are already + # present in libcrypt.so.1. +@@ -80,7 +80,7 @@ crypt.h: crypt-base.h gen-crypt-h.awk config.h + # libraries involved, libcrypt.so.1 and libowcrypt.so.1. (We should + # be able to get away with this because in any circumstance where the + # soname of libcrypt isn't libcrypt.so.1, ENABLE_OBSOLETE_API should +-# be automatically turned off, and as best I can tell, SuSE only ever ++# be automatically turned off, and as best I can tell, SUSE only ever + # shipped libowcrypt.so.1.) + if ENABLE_OBSOLETE_API + if ENABLE_STATIC +diff --git a/README.md b/README.md +index 05319f3..869d46f 100644 +--- a/README.md ++++ b/README.md +@@ -75,7 +75,7 @@ libcrypt.so.1. We have taken pains to provide exactly the same + "symbol versions" as were used by glibc on various CPU architectures, + and to account for the variety of ways in which the Openwall + extensions were patched into glibc's libcrypt by some Linux +-distributions. (For instance, compatibility symlinks for SuSE's ++distributions. (For instance, compatibility symlinks for SUSE's + "libowcrypt" are provided.) + + However, the converse is not true: programs linked against libxcrypt +diff --git a/libcrypt.map.in b/libcrypt.map.in +index 2de7d1b..18aac79 100644 +--- a/libcrypt.map.in ++++ b/libcrypt.map.in +@@ -7,7 +7,7 @@ crypt XCRYPT_2.0 GLIBC_2.0 + crypt_r XCRYPT_2.0 GLIBC_2.0 + + # Actively supported Openwall extensions; never actually added to +-# upstream GNU libc, but present in at least Openwall, ALT, and SuSE ++# upstream GNU libc, but present in at least Openwall, ALT, and SUSE + # Linux distributions with one or more of these symbol versions + crypt_rn XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.1 + crypt_gensalt XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.1 OW_CRYPT_1.0 + +From 089d679b81a3c4e821f5f9cfaacb33e67370eeed Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 22 Jun 2018 00:07:54 +0000 +Subject: [PATCH 02/38] Lower the minimum required automake version + +The minimum required automake version was raised from 1.7 to 1.15 by +commit a6c11d6cd89ac391dfb81bc2b7eb2b9fb31d7da6. This new requirement +seems to be unnecessarily high, at least, the project builds using +automake 1.14 just fine. +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 90fe733..491dfae 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4,7 +4,7 @@ + # Author: Thorsten Kukuk + # + +-AUTOMAKE_OPTIONS = 1.15 gnits ++AUTOMAKE_OPTIONS = 1.14 gnits + ACLOCAL_AMFLAGS = -I m4 + + AM_CFLAGS = $(WARN_CFLAGS) + +From fab17cc338b3e18cb74ebed8da3a876e485e3c95 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 22 Jun 2018 00:07:54 +0000 +Subject: [PATCH 03/38] gen-vers.awk: fix typo in comment + +--- + gen-vers.awk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gen-vers.awk b/gen-vers.awk +index 602195a..4870d05 100644 +--- a/gen-vers.awk ++++ b/gen-vers.awk +@@ -15,7 +15,7 @@ + # the macros generated by this program. + # + # Note: if you change the format of .map.in files you probably need to +-# update gen-vers.awk too. ++# update gen-map.awk too. + # + # Note: we currently don't support compatibility symbols that need + # a different definition from the default version. + +From b1d83b002039a561233ce55986d9205e76138a14 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Wed, 27 Jun 2018 14:58:49 +0000 +Subject: [PATCH 04/38] Fix build with USE_SWAPCONTEXT turned off + +Due to regression introduced by commit v4.0.0~100, the project no longer +builds when USE_SWAPCONTEXT is not available or explicitly turned off. +This is not a very big deal as this build mode seems to be not very +popular, but fix it anyway. +--- + crypt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/crypt.c b/crypt.c +index d7f0ffc..2aa9491 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -288,7 +288,7 @@ do_crypt (const char *phrase, const char *setting, struct crypt_data *data) + swapcontext (&outer_ctx, &cint->inner_ctx); + } + #else +- cfn (phrase, setting, ++ h->crypt (phrase, setting, + (unsigned char *)data->output, sizeof data->output, + cint->alg_specific, sizeof cint->alg_specific); + #endif + +From 942d51bbe41f6f84138916c2b180b5b669d65b27 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 29 Jun 2018 11:07:48 +0000 +Subject: [PATCH 05/38] Include crypt-port.h in two remaining source files + +crypt-port.h must be the first header file included by each source file, +this guarantees that config.h is included before any system header. +--- + test-crypt-badsalt.c | 1 + + test-crypt-nonnull.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/test-crypt-badsalt.c b/test-crypt-badsalt.c +index 1e1e840..c46848d 100644 +--- a/test-crypt-badsalt.c ++++ b/test-crypt-badsalt.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include "crypt-port.h" + #include + #include + #include +diff --git a/test-crypt-nonnull.c b/test-crypt-nonnull.c +index 27313f0..5e4f118 100644 +--- a/test-crypt-nonnull.c ++++ b/test-crypt-nonnull.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include "crypt-port.h" + #include + #include + #include + +From e9b661ffd4d58788f61c46ad1e8e29380b43f464 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 29 Jun 2018 11:07:48 +0000 +Subject: [PATCH 06/38] Use ARRAY_SIZE instead of open-coding it in every use + case + +Introduce ARRAY_SIZE macro, use it in all cases like +sizeof (tests) / sizeof (tests[0]) + +The definition of ARRAY_SIZE is the simplest one, a guard that +its argument is an array can be added later if necessary. +--- + crypt-port.h | 3 +++ + test-alg-md4.c | 2 +- + test-alg-md5.c | 2 +- + test-alg-sha256.c | 2 +- + test-alg-sha512.c | 2 +- + test-byteorder.c | 8 ++++---- + test-crypt-badsalt.c | 2 +- + test-crypt-des.c | 2 +- + test-crypt-nonnull.c | 2 +- + test-crypt-nthash.c | 2 +- + test-crypt-pbkdf1-sha1.c | 2 +- + test-crypt-sha256.c | 2 +- + test-crypt-sha512.c | 2 +- + test-crypt-sunmd5.c | 2 +- + test-des-cases.h | 2 +- + test-gensalt.c | 2 +- + 16 files changed, 21 insertions(+), 18 deletions(-) + +diff --git a/crypt-port.h b/crypt-port.h +index 2b74ec9..99717f3 100644 +--- a/crypt-port.h ++++ b/crypt-port.h +@@ -87,6 +87,9 @@ typedef union + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) + ++/* ARRAY_SIZE is used in tests. */ ++#define ARRAY_SIZE(a_) (sizeof (a_) / sizeof ((a_)[0])) ++ + /* Provide a guaranteed way to erase sensitive memory at the best we + can, given the possibilities of the system. */ + #if defined HAVE_MEMSET_S +diff --git a/test-alg-md4.c b/test-alg-md4.c +index 3476c35..ab6ad87 100644 +--- a/test-alg-md4.c ++++ b/test-alg-md4.c +@@ -73,7 +73,7 @@ main (void) + int cnt; + int i; + +- for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt) ++ for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) + { + md4_init_ctx (&ctx); + md4_process_bytes ((const unsigned char*)tests[cnt].input, &ctx, strlen (tests[cnt].input)); +diff --git a/test-alg-md5.c b/test-alg-md5.c +index 8bde121..9908ab8 100644 +--- a/test-alg-md5.c ++++ b/test-alg-md5.c +@@ -80,7 +80,7 @@ main (void) + int cnt; + int i; + +- for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt) ++ for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) + { + md5_init_ctx (&ctx); + md5_process_bytes (tests[cnt].input, strlen (tests[cnt].input), &ctx); +diff --git a/test-alg-sha256.c b/test-alg-sha256.c +index 86b1e8c..45345e2 100644 +--- a/test-alg-sha256.c ++++ b/test-alg-sha256.c +@@ -88,7 +88,7 @@ main (void) + int cnt; + int i; + +- for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt) ++ for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) + { + sha256_init_ctx (&ctx); + sha256_process_bytes (tests[cnt].input, strlen (tests[cnt].input), +diff --git a/test-alg-sha512.c b/test-alg-sha512.c +index d6eae93..0e24ad5 100644 +--- a/test-alg-sha512.c ++++ b/test-alg-sha512.c +@@ -116,7 +116,7 @@ main (void) + int cnt; + int i; + +- for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt) ++ for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) + { + sha512_init_ctx (&ctx); + sha512_process_bytes (tests[cnt].input, strlen (tests[cnt].input), +diff --git a/test-byteorder.c b/test-byteorder.c +index 58bc9a7..7be0895 100644 +--- a/test-byteorder.c ++++ b/test-byteorder.c +@@ -46,7 +46,7 @@ test_le32 (void) + { 0x000000FF, "\xFF\x00\x00\x00" }, + { 0x01234567, "\x67\x45\x23\x01" }, + }; +- size_t n_cases = sizeof cases / sizeof cases[0]; ++ size_t n_cases = ARRAY_SIZE (cases); + size_t i; + uint32_t v; + unsigned char x[4]; +@@ -93,7 +93,7 @@ test_be32 (void) + { 0x000000FF, "\x00\x00\x00\xFF" }, + { 0x01234567, "\x01\x23\x45\x67" }, + }; +- size_t n_cases = sizeof cases / sizeof cases[0]; ++ size_t n_cases = ARRAY_SIZE (cases); + size_t i; + uint32_t v; + unsigned char x[4]; +@@ -144,7 +144,7 @@ test_le64 (void) + { 0xFF00000000000000ull, "\x00\x00\x00\x00\x00\x00\x00\xFF" }, + { 0x0123456789ABCDEFull, "\xEF\xCD\xAB\x89\x67\x45\x23\x01" }, + }; +- size_t n_cases = sizeof cases / sizeof cases[0]; ++ size_t n_cases = ARRAY_SIZE (cases); + size_t i; + uint64_t v; + unsigned char x[8]; +@@ -201,7 +201,7 @@ test_be64 (void) + { 0xFF00000000000000ull, "\xFF\x00\x00\x00\x00\x00\x00\x00" }, + { 0x0123456789ABCDEFull, "\x01\x23\x45\x67\x89\xAB\xCD\xEF" }, + }; +- size_t n_cases = sizeof cases / sizeof cases[0]; ++ size_t n_cases = ARRAY_SIZE (cases); + size_t i; + uint64_t v; + unsigned char x[8]; +diff --git a/test-crypt-badsalt.c b/test-crypt-badsalt.c +index c46848d..a5e0e01 100644 +--- a/test-crypt-badsalt.c ++++ b/test-crypt-badsalt.c +@@ -45,7 +45,7 @@ main (void) + int result = 0; + struct crypt_data cd; + struct crypt_data *cdptr = &cd; +- size_t n = sizeof (tests) / sizeof (*tests); ++ size_t n = ARRAY_SIZE (tests); + size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); + char *page, *retval; + const char *saltstr, *special = "%"; +diff --git a/test-crypt-des.c b/test-crypt-des.c +index d2266e4..dbe44e0 100644 +--- a/test-crypt-des.c ++++ b/test-crypt-des.c +@@ -65,7 +65,7 @@ static const struct + }, + }; + +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + int + main (void) +diff --git a/test-crypt-nonnull.c b/test-crypt-nonnull.c +index 5e4f118..e4738ff 100644 +--- a/test-crypt-nonnull.c ++++ b/test-crypt-nonnull.c +@@ -44,7 +44,7 @@ main (void) + int result = 0; + struct crypt_data cd; + struct crypt_data *cdptr = &cd; +- size_t n = sizeof (tests) / sizeof (*tests); ++ size_t n = ARRAY_SIZE (tests); + size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); + char *page; + const char *saltstr, *special = "%"; +diff --git a/test-crypt-nthash.c b/test-crypt-nthash.c +index dc1f320..6f897fe 100644 +--- a/test-crypt-nthash.c ++++ b/test-crypt-nthash.c +@@ -120,7 +120,7 @@ static const struct + } + }; + +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + int + main (void) +diff --git a/test-crypt-pbkdf1-sha1.c b/test-crypt-pbkdf1-sha1.c +index c86abd4..aadc0fe 100644 +--- a/test-crypt-pbkdf1-sha1.c ++++ b/test-crypt-pbkdf1-sha1.c +@@ -58,7 +58,7 @@ const char *tests[][2] = + }, + }; + +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + int + main (void) +diff --git a/test-crypt-sha256.c b/test-crypt-sha256.c +index c742aae..23da81c 100644 +--- a/test-crypt-sha256.c ++++ b/test-crypt-sha256.c +@@ -48,7 +48,7 @@ static const struct + }, + }; + +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + + +diff --git a/test-crypt-sha512.c b/test-crypt-sha512.c +index a18cea8..1aa0b71 100644 +--- a/test-crypt-sha512.c ++++ b/test-crypt-sha512.c +@@ -49,7 +49,7 @@ static const struct + "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." + }, + }; +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + + int +diff --git a/test-crypt-sunmd5.c b/test-crypt-sunmd5.c +index d4fc0dc..d67781b 100644 +--- a/test-crypt-sunmd5.c ++++ b/test-crypt-sunmd5.c +@@ -88,7 +88,7 @@ const char *tests[][3] = + }, + }; + +-#define ntests (sizeof (tests) / sizeof (tests[0])) ++#define ntests ARRAY_SIZE (tests) + + int + main (void) +diff --git a/test-des-cases.h b/test-des-cases.h +index 03ca837..8354df7 100644 +--- a/test-des-cases.h ++++ b/test-des-cases.h +@@ -191,6 +191,6 @@ static const struct des_testcase des_testcases[] = + { "\x01\x83\x10\xdc\x40\x9b\x26\xd6", "\x1d\x9d\x5c\x50\x18\xf7\x28\xc2", "\x5f\x4c\x03\x8e\xd1\x2b\x2e\x41" }, + { "\x1c\x58\x7f\x1c\x13\x92\x4f\xef", "\x30\x55\x32\x28\x6d\x6f\x29\x5a", "\x63\xfa\xc0\xd0\x34\xd9\xf7\x93" }, + }; +-static const size_t N_DES_TESTCASES = sizeof des_testcases / sizeof des_testcases[0]; ++static const size_t N_DES_TESTCASES = ARRAY_SIZE (des_testcases); + + #endif /* test-des-cases.h */ +diff --git a/test-gensalt.c b/test-gensalt.c +index dfe194c..4b3a0e1 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -51,7 +51,7 @@ main (void) + for (tcase = testcases; tcase->prefix; tcase++) + { + XCRYPT_SECURE_MEMSET (prev_output, CRYPT_GENSALT_OUTPUT_SIZE); +- for (ent = 0; ent < (sizeof entropy / sizeof entropy[0]); ent++) ++ for (ent = 0; ent < ARRAY_SIZE (entropy); ent++) + { + XCRYPT_SECURE_MEMSET (output, CRYPT_GENSALT_OUTPUT_SIZE); + char *salt = crypt_gensalt_rn (tcase->prefix, 0, + +From 10483284a8fbefde59e71700089a28e3f18cbe5b Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 22 Jun 2018 00:07:54 +0000 +Subject: [PATCH 07/38] Extend --enable-weak-hashes configure option + +Extend --enable-weak-hashes configure option to accept optional "glibc" +parameter. When specified, it enables only those of weak hashes that +are supported by historic versions of the GNU libc. + +Closes: https://github.com/besser82/libxcrypt/issues/7 +--- + Makefile.am | 20 ++++++++++++++------ + configure.ac | 29 ++++++++++++++++++++++------- + crypt-des.c | 9 ++++++++- + crypt-port.h | 4 ++++ + crypt-private.h | 20 ++++++++++++++------ + crypt.c | 15 +++++++++++++++ + test-crypt-des.c | 2 ++ + test-gensalt.c | 4 +++- + 8 files changed, 82 insertions(+), 21 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 491dfae..c219bac 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -114,9 +114,13 @@ check_PROGRAMS = \ + + if ENABLE_WEAK_HASHES + libcrypt_la_SOURCES += \ +- crypt-md5.c crypt-des.c crypt-nthash.c crypt-pbkdf1-sha1.c \ +- crypt-sunmd5.c \ +- alg-des.c alg-hmac-sha1.c alg-md4.c alg-md5.c alg-sha1.c ++ crypt-des.c crypt-md5.c alg-des.c alg-md5.c ++ ++if ENABLE_WEAK_NON_GLIBC_HASHES ++libcrypt_la_SOURCES += \ ++ crypt-nthash.c crypt-pbkdf1-sha1.c crypt-sunmd5.c \ ++ alg-hmac-sha1.c alg-md4.c alg-sha1.c ++endif + + nodist_libcrypt_la_SOURCES = \ + alg-des-tables.c +@@ -143,11 +147,15 @@ alg-des-tables.c: gen-des-tables + $(AM_V_at)mv -f alg-des-tables.c.T alg-des-tables.c + + check_PROGRAMS += \ +- test-alg-des test-alg-hmac-sha1 test-alg-md4 \ +- test-alg-md5 test-alg-sha1 \ +- test-crypt-badsalt test-crypt-des test-crypt-md5 \ ++ test-alg-des test-alg-md5 test-crypt-des test-crypt-md5 \ ++ test-crypt-badsalt ++ ++if ENABLE_WEAK_NON_GLIBC_HASHES ++check_PROGRAMS += \ ++ test-alg-hmac-sha1 test-alg-md4 test-alg-sha1 \ + test-crypt-nthash test-crypt-sunmd5 test-crypt-pbkdf1-sha1 + endif ++endif + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +diff --git a/configure.ac b/configure.ac +index 9bc41d1..9846e3f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -204,17 +204,28 @@ AC_ARG_ENABLE([obsolete-api], + + AC_ARG_ENABLE([weak-hashes], + AS_HELP_STRING( +- [--disable-weak-hashes], +- [do not include any support for weak hashes (DES, MD5). +- Implies --disable-obsolete-api, and breaks binary compatibility +- with glibc's libcrypt.] ++ [--enable-weak-hashes[=ARG]], ++ [When set to "yes", all of the hashing methods documented in crypt(5) ++ are supported for authenticating existing password hashes, including ++ several that are too weak to use for new passwords. ++ ++ When set to "glibc", only the weak hashes supported by historic ++ versions of GNU libc are supported: traditional DES and FreeBSD-style ++ MD5, but not bigcrypt-DES, BSDi extended DES, SHA1, SUNMD5, or NTHASH. ++ ++ When set to "no", only bcrypt, SHA512, and SHA256 are supported. ++ This mode implies --disable-obsolete-api and breaks binary ++ compatibility with glibc's libcrypt. ++ ++ [default=yes]] + ), + [case "${enableval}" in +- yes) enable_weak_hashes=1 ;; +- no) enable_weak_hashes=0 ;; ++ yes) enable_weak_hashes=1; enable_weak_non_glibc_hashes=1 ;; ++ glibc) enable_weak_hashes=1; enable_weak_non_glibc_hashes=0 ;; ++ no) enable_weak_hashes=0; enable_weak_non_glibc_hashes=0 ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-weak-hashes]) ;; + esac], +- [enable_weak_hashes=1] ++ [enable_weak_hashes=1; enable_weak_non_glibc_hashes=1] + ) + + # If weak hashes are disabled, then the obsolete APIs won't work anyway +@@ -293,6 +304,10 @@ AC_DEFINE_UNQUOTED([ENABLE_WEAK_HASHES], [$enable_weak_hashes], + If this is 0, ENABLE_OBSOLETE_API must also be 0.]) + AM_CONDITIONAL([ENABLE_WEAK_HASHES], [test $enable_weak_hashes = 1]) + ++AC_DEFINE_UNQUOTED([ENABLE_WEAK_NON_GLIBC_HASHES], [$enable_weak_non_glibc_hashes], ++ [Define as 1 if weak hashes not supported by glibc should be included, 0 otherwise.]) ++AM_CONDITIONAL([ENABLE_WEAK_NON_GLIBC_HASHES], [test $enable_weak_non_glibc_hashes = 1]) ++ + # The Makefile needs to know which versions of the library we are building. + AM_CONDITIONAL([ENABLE_STATIC], [test $enable_static = yes]) + AM_CONDITIONAL([ENABLE_SHARED], [test $enable_shared = yes]) +diff --git a/crypt-des.c b/crypt-des.c +index 467be8d..79b3144 100644 +--- a/crypt-des.c ++++ b/crypt-des.c +@@ -144,7 +144,10 @@ des_gen_hash (struct des_ctx *ctx, uint32_t count, uint8_t *output, + } + + /* The original UNIX DES-based password hash, no extensions. */ +-static void ++#if ENABLE_WEAK_NON_GLIBC_HASHES ++static ++#endif ++void + crypt_des_trd_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) +@@ -192,6 +195,7 @@ crypt_des_trd_rn (const char *phrase, const char *setting, + des_gen_hash (ctx, 25, cp, pkbuf); + } + ++#if ENABLE_WEAK_NON_GLIBC_HASHES + /* This algorithm is algorithm 0 (default) shipped with the C2 secure + implementation of Digital UNIX. + +@@ -342,6 +346,7 @@ crypt_des_xbsd_rn (const char *phrase, const char *setting, + des_set_salt (ctx, salt); + des_gen_hash (ctx, count, cp, pkbuf); + } ++#endif /* ENABLE_WEAK_NON_GLIBC_HASHES */ + + void + gensalt_des_trd_rn (unsigned long count, +@@ -365,6 +370,7 @@ gensalt_des_trd_rn (unsigned long count, + output[2] = '\0'; + } + ++#if ENABLE_WEAK_NON_GLIBC_HASHES + void + gensalt_des_xbsd_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, +@@ -406,3 +412,4 @@ gensalt_des_xbsd_rn (unsigned long count, + + output[9] = '\0'; + } ++#endif /* ENABLE_WEAK_NON_GLIBC_HASHES */ +diff --git a/crypt-port.h b/crypt-port.h +index 99717f3..8b21f56 100644 +--- a/crypt-port.h ++++ b/crypt-port.h +@@ -217,7 +217,11 @@ void _xcrypt_secure_memset (void *s, size_t len) + #if ENABLE_WEAK_HASHES + #define comp_maskl _crypt_comp_maskl + #define comp_maskr _crypt_comp_maskr ++#if ENABLE_WEAK_NON_GLIBC_HASHES + #define crypt_des_trd_or_big_rn _crypt_crypt_des_trd_or_big_rn ++#else ++#define crypt_des_trd_rn _crypt_crypt_des_trd_rn ++#endif + #define crypt_des_xbsd_rn _crypt_crypt_des_xbsd_rn + #define crypt_md5_rn _crypt_crypt_md5_rn + #define crypt_nthash_rn _crypt_crypt_nthash_rn +diff --git a/crypt-private.h b/crypt-private.h +index 80a916d..c5db3bd 100644 +--- a/crypt-private.h ++++ b/crypt-private.h +@@ -39,15 +39,16 @@ extern void gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount, + /* Individual hash functions */ + + #if ENABLE_WEAK_HASHES ++extern void crypt_md5_rn (const char *phrase, const char *setting, ++ uint8_t *output, size_t o_size, ++ void *scratch, size_t s_size); ++#if ENABLE_WEAK_NON_GLIBC_HASHES + extern void crypt_des_trd_or_big_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size); + extern void crypt_des_xbsd_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size); +-extern void crypt_md5_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); + extern void crypt_nthash_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size); +@@ -57,6 +58,11 @@ extern void crypt_sha1_rn (const char *phrase, const char *setting, + extern void crypt_sunmd5_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size); ++#else ++extern void crypt_des_trd_rn (const char *phrase, const char *setting, ++ uint8_t *output, size_t o_size, ++ void *scratch, size_t s_size); ++#endif + #endif + + extern void crypt_sha256_rn (const char *phrase, const char *setting, +@@ -73,12 +79,13 @@ extern void crypt_bcrypt_rn (const char *phrase, const char *setting, + extern void gensalt_des_trd_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size); +-extern void gensalt_des_xbsd_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); + extern void gensalt_md5_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size); ++#if ENABLE_WEAK_NON_GLIBC_HASHES ++extern void gensalt_des_xbsd_rn (unsigned long count, ++ const uint8_t *rbytes, size_t nrbytes, ++ uint8_t *output, size_t o_size); + extern void gensalt_nthash_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size); +@@ -89,6 +96,7 @@ extern void gensalt_sunmd5_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size); + #endif ++#endif + + extern void gensalt_sha256_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, +diff --git a/crypt.c b/crypt.c +index 2aa9491..38dfca9 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -87,9 +87,11 @@ static const struct hashfn tagged_hashes[] = + /* legacy hashes */ + #if ENABLE_WEAK_HASHES + { "$1$", crypt_md5_rn, gensalt_md5_rn }, ++#if ENABLE_WEAK_NON_GLIBC_HASHES + { "$3$", crypt_nthash_rn, gensalt_nthash_rn }, + { "$md5", crypt_sunmd5_rn, gensalt_sunmd5_rn }, + { "$sha1", crypt_sha1_rn, gensalt_sha1_rn }, ++#endif + #endif + { "$5$", crypt_sha256_rn, gensalt_sha256_rn }, + { "$6$", crypt_sha512_rn, gensalt_sha512_rn }, +@@ -97,6 +99,7 @@ static const struct hashfn tagged_hashes[] = + }; + + #if ENABLE_WEAK_HASHES ++#if ENABLE_WEAK_NON_GLIBC_HASHES + /* BSD-style extended DES */ + static const struct hashfn bsdi_extended_hash = + { +@@ -109,6 +112,16 @@ static const struct hashfn traditional_hash = + "", crypt_des_trd_or_big_rn, gensalt_des_trd_rn + }; + ++#else ++ ++/* Traditional DES */ ++static const struct hashfn traditional_hash = ++{ ++ "", crypt_des_trd_rn, gensalt_des_trd_rn ++}; ++ ++#endif ++ + static int + is_des_salt_char (char c) + { +@@ -131,8 +144,10 @@ get_hashfn (const char *setting) + return 0; + } + #if ENABLE_WEAK_HASHES ++#if ENABLE_WEAK_NON_GLIBC_HASHES + else if (setting[0] == '_') + return &bsdi_extended_hash; ++#endif + else if (setting[0] == '\0' || + (is_des_salt_char (setting[0]) && is_des_salt_char (setting[1]))) + return &traditional_hash; +diff --git a/test-crypt-des.c b/test-crypt-des.c +index dbe44e0..e541885 100644 +--- a/test-crypt-des.c ++++ b/test-crypt-des.c +@@ -20,6 +20,7 @@ static const struct + { "XX", "XXxzOu6maQKqQ", "*U*U*U*U" }, + { "SD", "SDbsugeBiC58A", "" }, + ++#if ENABLE_WEAK_NON_GLIBC_HASHES + /* BSDI-extended-DES, ditto */ + { "_J9..CCCC", "_J9..CCCCXBrJUJV154M", "U*U*U*U*" }, + { "_J9..CCCC", "_J9..CCCCXUhOBTXzaiE", "U*U***U" }, +@@ -63,6 +64,7 @@ static const struct + "6M..............", "6MvZdspyAL4QEId8ugLUEeDs", + "\xf3\xf4\xe5\xf0\xe8\xe1\xee\xe9\xe5" /* stephanie */ + }, ++#endif + }; + + #define ntests ARRAY_SIZE (tests) +diff --git a/test-gensalt.c b/test-gensalt.c +index 4b3a0e1..39a5435 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -24,11 +24,13 @@ static const struct testcase testcases[] = + { + #if ENABLE_WEAK_HASHES + { "", 2 }, // DES +- { "_", 9 }, // BSDi extended DES + { "$1$", 11 }, // MD5 ++#if ENABLE_WEAK_NON_GLIBC_HASHES ++ { "_", 9 }, // BSDi extended DES + { "$3$", 29 }, // NTHASH + { "$md5", 27 }, // SUNMD5 + { "$sha1", 34 }, // PBKDF with SHA1 ++#endif + #endif + { "$5$", 19 }, // SHA-2-256 + { "$6$", 19 }, // SHA-2-512 + +From 84134e4d8e773fa6e27df1de2088f001e8042ef2 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Tue, 26 Jun 2018 22:45:01 +0000 +Subject: [PATCH 08/38] crypt_gensalt_rn: fix the number of automatically + obtained random bytes + +Commit v4.0.0~94 extended crypt_gensalt_ra to obtained random bytes +automatically when rbytes argument is NULL. The number of random bytes +was fixed to 16, subsequent commit v4.0.0~6 changed this fixed number +to 18. However, the approach of using a fixed number for every +algorithm has two problems. Firstly, it is too wasteful for some +of currently implemented algorithms that use less than 18 bytes +of randomness. Secondly, other algorithms can use more than 18 random +bytes. Fix these issues by specifying the number of random bytes along +with functions in tagged_hashes table. +--- + crypt.c | 43 ++++++++++++++++++++++--------------------- + test-gensalt.c | 34 +++++++++++++++++++--------------- + 2 files changed, 41 insertions(+), 36 deletions(-) + +diff --git a/crypt.c b/crypt.c +index 38dfca9..26f3537 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -21,9 +21,9 @@ + + #include + #include ++#include + + #ifdef USE_SWAPCONTEXT +-#include + #include + #endif + +@@ -72,6 +72,9 @@ struct hashfn + const char *prefix; + crypt_fn crypt; + gensalt_fn gensalt; ++ /* The type of this field is unsigned char to ensure that it cannot ++ be set larger than the size of an internal buffer in crypt_gensalt_rn. */ ++ unsigned char nrbytes; + }; + + /* This table should always begin with the algorithm that should be used +@@ -79,23 +82,23 @@ struct hashfn + static const struct hashfn tagged_hashes[] = + { + /* bcrypt */ +- { "$2b$", crypt_bcrypt_rn, gensalt_bcrypt_b_rn }, +- { "$2a$", crypt_bcrypt_rn, gensalt_bcrypt_a_rn }, +- { "$2x$", crypt_bcrypt_rn, gensalt_bcrypt_x_rn }, +- { "$2y$", crypt_bcrypt_rn, gensalt_bcrypt_y_rn }, ++ { "$2b$", crypt_bcrypt_rn, gensalt_bcrypt_b_rn, 16 }, ++ { "$2a$", crypt_bcrypt_rn, gensalt_bcrypt_a_rn, 16 }, ++ { "$2x$", crypt_bcrypt_rn, gensalt_bcrypt_x_rn, 16 }, ++ { "$2y$", crypt_bcrypt_rn, gensalt_bcrypt_y_rn, 16 }, + + /* legacy hashes */ + #if ENABLE_WEAK_HASHES +- { "$1$", crypt_md5_rn, gensalt_md5_rn }, ++ { "$1$", crypt_md5_rn, gensalt_md5_rn, 9 }, + #if ENABLE_WEAK_NON_GLIBC_HASHES +- { "$3$", crypt_nthash_rn, gensalt_nthash_rn }, +- { "$md5", crypt_sunmd5_rn, gensalt_sunmd5_rn }, +- { "$sha1", crypt_sha1_rn, gensalt_sha1_rn }, ++ { "$3$", crypt_nthash_rn, gensalt_nthash_rn, 16 }, ++ { "$md5", crypt_sunmd5_rn, gensalt_sunmd5_rn, 8 }, ++ { "$sha1", crypt_sha1_rn, gensalt_sha1_rn, 48 }, + #endif + #endif +- { "$5$", crypt_sha256_rn, gensalt_sha256_rn }, +- { "$6$", crypt_sha512_rn, gensalt_sha512_rn }, +- { 0, 0, 0 } ++ { "$5$", crypt_sha256_rn, gensalt_sha256_rn, 15 }, ++ { "$6$", crypt_sha512_rn, gensalt_sha512_rn, 15 }, ++ { 0, 0, 0, 0 } + }; + + #if ENABLE_WEAK_HASHES +@@ -103,13 +106,13 @@ static const struct hashfn tagged_hashes[] = + /* BSD-style extended DES */ + static const struct hashfn bsdi_extended_hash = + { +- "_", crypt_des_xbsd_rn, gensalt_des_xbsd_rn ++ "_", crypt_des_xbsd_rn, gensalt_des_xbsd_rn, 3 + }; + + /* Traditional DES or bigcrypt-style extended DES */ + static const struct hashfn traditional_hash = + { +- "", crypt_des_trd_or_big_rn, gensalt_des_trd_rn ++ "", crypt_des_trd_or_big_rn, gensalt_des_trd_rn, 2 + }; + + #else +@@ -117,7 +120,7 @@ static const struct hashfn traditional_hash = + /* Traditional DES */ + static const struct hashfn traditional_hash = + { +- "", crypt_des_trd_rn, gensalt_des_trd_rn ++ "", crypt_des_trd_rn, gensalt_des_trd_rn, 2 + }; + + #endif +@@ -375,10 +378,6 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + const char *rbytes, int nrbytes, char *output, + int output_size) + { +- /* Always add two padding bytes to make sure the whole string +- will be random on Base64 encoding. */ +- char internal_rbytes[16 + 2]; +- + make_failure_token ("", output, output_size); + + /* Individual gensalt functions will check for adequate space for +@@ -404,15 +403,17 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + return 0; + } + ++ char internal_rbytes[UCHAR_MAX]; ++ + /* If rbytes is 0, read random bytes from the operating system if + possible. */ + if (!rbytes) + { +- if (!get_random_bytes(internal_rbytes, sizeof internal_rbytes)) ++ if (!get_random_bytes (internal_rbytes, h->nrbytes)) + return 0; + + rbytes = internal_rbytes; +- nrbytes = sizeof internal_rbytes; ++ nrbytes = h->nrbytes; + } + + /* Individual gensalt functions will check for sufficient random bits +diff --git a/test-gensalt.c b/test-gensalt.c +index 39a5435..f4d0629 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -18,27 +18,28 @@ struct testcase + { + const char *prefix; + unsigned int expected_len; ++ unsigned int expected_auto_len; + }; + + static const struct testcase testcases[] = + { + #if ENABLE_WEAK_HASHES +- { "", 2 }, // DES +- { "$1$", 11 }, // MD5 ++ { "", 2, 0 }, // DES ++ { "$1$", 11, 0 }, // MD5 + #if ENABLE_WEAK_NON_GLIBC_HASHES +- { "_", 9 }, // BSDi extended DES +- { "$3$", 29 }, // NTHASH +- { "$md5", 27 }, // SUNMD5 +- { "$sha1", 34 }, // PBKDF with SHA1 ++ { "_", 9, 0 }, // BSDi extended DES ++ { "$3$", 29, 0 }, // NTHASH ++ { "$md5", 27, 0 }, // SUNMD5 ++ { "$sha1", 34, 74 }, // PBKDF with SHA1 + #endif + #endif +- { "$5$", 19 }, // SHA-2-256 +- { "$6$", 19 }, // SHA-2-512 +- { "$2a$", 29 }, // bcrypt mode A +- { "$2b$", 29 }, // bcrypt mode B +- { "$2x$", 29 }, // bcrypt mode X +- { "$2y$", 29 }, // bcrypt mode Y +- { 0, 0 } ++ { "$5$", 19, 0 }, // SHA-2-256 ++ { "$6$", 19, 0 }, // SHA-2-512 ++ { "$2a$", 29, 0 }, // bcrypt mode A ++ { "$2b$", 29, 0 }, // bcrypt mode B ++ { "$2x$", 29, 0 }, // bcrypt mode X ++ { "$2y$", 29, 0 }, // bcrypt mode Y ++ { 0, 0, 0 } + }; + + int +@@ -74,11 +75,14 @@ main (void) + continue; + } + size_t slen = strlen (salt); +- if (slen != tcase->expected_len) ++ unsigned int expected_len = ++ (!entropy[ent] && tcase->expected_auto_len) ? ++ tcase->expected_auto_len : tcase->expected_len; ++ if (slen != expected_len) + { + fprintf (stderr, + "ERROR: %s/%u -> %s (expected len=%u got %zu)\n", +- tcase->prefix, ent, salt, tcase->expected_len, slen); ++ tcase->prefix, ent, salt, expected_len, slen); + status = 1; + } + else if (strncmp (salt, tcase->prefix, strlen (tcase->prefix))) + +From 2973606ece4ebc17ffea4882b090eec68555f0b0 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Wed, 27 Jun 2018 17:59:36 +0000 +Subject: [PATCH 09/38] crypt_gensalt_rn: fix the leak of obtained random bytes + +Erase the memory containing automatically obtained random bytes +to avoid leak of sensitive data after return from the function. +--- + crypt.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/crypt.c b/crypt.c +index 26f3537..12d50fd 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -404,6 +404,8 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + } + + char internal_rbytes[UCHAR_MAX]; ++ /* typeof (internal_nrbytes) == typeof (h->nrbytes). */ ++ unsigned char internal_nrbytes = 0; + + /* If rbytes is 0, read random bytes from the operating system if + possible. */ +@@ -413,7 +415,7 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + return 0; + + rbytes = internal_rbytes; +- nrbytes = h->nrbytes; ++ nrbytes = internal_nrbytes = h->nrbytes; + } + + /* Individual gensalt functions will check for sufficient random bits +@@ -429,6 +431,9 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + (const unsigned char *)rbytes, (size_t)nrbytes, + (unsigned char *)output, (size_t)output_size); + ++ if (internal_nrbytes) ++ XCRYPT_SECURE_MEMSET (internal_rbytes, internal_nrbytes); ++ + return output[0] == '*' ? 0 : output; + } + SYMVER_crypt_gensalt_rn; + +From 19ac122ea84b370e421a8cb5a174a64577f6fa4e Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 29 Jun 2018 02:59:42 +0000 +Subject: [PATCH 10/38] test-gensalt: extend checks of expected output + +In addition to checks for expected output length, +check expected output strings for deterministic methods. +--- + test-gensalt.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 83 insertions(+), 13 deletions(-) + +diff --git a/test-gensalt.c b/test-gensalt.c +index f4d0629..2705671 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -14,9 +14,72 @@ static const char *const entropy[] = + 0 + }; + ++#if ENABLE_WEAK_HASHES ++static const char *const des_expected_output[] = { "Mp", "Pp", "ZH", "Uh"}; ++static const char *const md5_expected_output[] = { ++ "$1$MJHnaAke", ++ "$1$PKXc3hCO", ++ "$1$ZAFlICwY", ++ "$1$UqGBkVu0" ++}; ++#if ENABLE_WEAK_NON_GLIBC_HASHES ++static const char *const bsdi_expected_output[] = { ++ "_J9..MJHn", ++ "_J9..PKXc", ++ "_J9..ZAFl", ++ "_J9..UqGB" ++}; ++static const char *const nthash_expected_output[] = { ++ "$3$__not_used__c809a450df09a3", ++ "$3$__not_used__30d0d6f834c0c3", ++ "$3$__not_used__0eeeebb83d6fe4", ++ "$3$__not_used__1c690d6a9ef88c" ++}; ++#define sunmd5_expected_output 0 /* output is not deterministic */ ++#define pbkdf_expected_output 0 /* output is not deterministic */ ++#endif ++#endif ++static const char *const sha256_expected_output[] = { ++ "$5$MJHnaAkegEVYHsFK", ++ "$5$PKXc3hCOSyMqdaEQ", ++ "$5$ZAFlICwYRETzIzIj", ++ "$5$UqGBkVu01rurVZqg" ++}; ++static const char *const sha512_expected_output[] = { ++ "$6$MJHnaAkegEVYHsFK", ++ "$6$PKXc3hCOSyMqdaEQ", ++ "$6$ZAFlICwYRETzIzIj", ++ "$6$UqGBkVu01rurVZqg" ++}; ++static const char *const bcrypt_a_expected_output[] = { ++ "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO", ++ "$2a$05$kxUgPcrmlm9XoOjvxCyfP.", ++ "$2a$05$HPNDjKMRFdR7zC87CMSmA.", ++ "$2a$05$mAyzaIeJu41dWUkxEbn8hO" ++}; ++static const char *const bcrypt_b_expected_output[] = { ++ "$2b$05$UBVLHeMpJ/QQCv3XqJx8zO", ++ "$2b$05$kxUgPcrmlm9XoOjvxCyfP.", ++ "$2b$05$HPNDjKMRFdR7zC87CMSmA.", ++ "$2b$05$mAyzaIeJu41dWUkxEbn8hO" ++}; ++static const char *const bcrypt_x_expected_output[] = { ++ "$2x$05$UBVLHeMpJ/QQCv3XqJx8zO", ++ "$2x$05$kxUgPcrmlm9XoOjvxCyfP.", ++ "$2x$05$HPNDjKMRFdR7zC87CMSmA.", ++ "$2x$05$mAyzaIeJu41dWUkxEbn8hO" ++}; ++static const char *const bcrypt_y_expected_output[] = { ++ "$2y$05$UBVLHeMpJ/QQCv3XqJx8zO", ++ "$2y$05$kxUgPcrmlm9XoOjvxCyfP.", ++ "$2y$05$HPNDjKMRFdR7zC87CMSmA.", ++ "$2y$05$mAyzaIeJu41dWUkxEbn8hO" ++}; ++ + struct testcase + { + const char *prefix; ++ const char *const *expected_output; + unsigned int expected_len; + unsigned int expected_auto_len; + }; +@@ -24,22 +87,22 @@ struct testcase + static const struct testcase testcases[] = + { + #if ENABLE_WEAK_HASHES +- { "", 2, 0 }, // DES +- { "$1$", 11, 0 }, // MD5 ++ { "", des_expected_output, 2, 0 }, // DES ++ { "$1$", md5_expected_output, 11, 0 }, // MD5 + #if ENABLE_WEAK_NON_GLIBC_HASHES +- { "_", 9, 0 }, // BSDi extended DES +- { "$3$", 29, 0 }, // NTHASH +- { "$md5", 27, 0 }, // SUNMD5 +- { "$sha1", 34, 74 }, // PBKDF with SHA1 ++ { "_", bsdi_expected_output, 9, 0 }, // BSDi extended DES ++ { "$3$", nthash_expected_output, 29, 0 }, // NTHASH ++ { "$md5", sunmd5_expected_output, 27, 0 }, // SUNMD5 ++ { "$sha1", pbkdf_expected_output, 34, 74 }, // PBKDF with SHA1 + #endif + #endif +- { "$5$", 19, 0 }, // SHA-2-256 +- { "$6$", 19, 0 }, // SHA-2-512 +- { "$2a$", 29, 0 }, // bcrypt mode A +- { "$2b$", 29, 0 }, // bcrypt mode B +- { "$2x$", 29, 0 }, // bcrypt mode X +- { "$2y$", 29, 0 }, // bcrypt mode Y +- { 0, 0, 0 } ++ { "$5$", sha256_expected_output, 19, 0 }, // SHA-2-256 ++ { "$6$", sha512_expected_output, 19, 0 }, // SHA-2-512 ++ { "$2a$", bcrypt_a_expected_output, 29, 0 }, // bcrypt mode A ++ { "$2b$", bcrypt_b_expected_output, 29, 0 }, // bcrypt mode B ++ { "$2x$", bcrypt_x_expected_output, 29, 0 }, // bcrypt mode X ++ { "$2y$", bcrypt_y_expected_output, 29, 0 }, // bcrypt mode Y ++ { 0, 0, 0, 0 } + }; + + int +@@ -97,6 +160,13 @@ main (void) + tcase->prefix, ent, salt); + status = 1; + } ++ else if (entropy[ent] && tcase->expected_output && ++ strcmp (salt, tcase->expected_output[ent])) ++ { ++ fprintf (stderr, "ERROR: %s/%u -> %s (expected %s)\n", ++ tcase->prefix, ent, salt, tcase->expected_output[ent]); ++ status = 1; ++ } + else + fprintf (stderr, " ok: %s/%u -> %s\n", + tcase->prefix, ent, salt); + +From 75dd1518c70d11093117e5c575cc2d7c121415f9 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Sat, 30 Jun 2018 12:26:41 +0000 +Subject: [PATCH 11/38] crypt_sha1_rn: fix memory leak + +Reported-by: Vitaly Chikunov +--- + crypt-pbkdf1-sha1.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index ac4f04a..e8427d5 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -218,6 +218,8 @@ crypt_sha1_rn (const char *phrase, const char *setting, + + /* Don't leave anything around in vm they could use. */ + XCRYPT_SECURE_MEMSET (scratch, s_size) ++ XCRYPT_SECURE_MEMSET (salt, sl) ++ free (salt); + } + + /* Modified excerpt from: + +From 86f386578f997a1039df42e26ff3f766ed09454b Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Sat, 30 Jun 2018 12:26:41 +0000 +Subject: [PATCH 12/38] gensalt_sha1_rn: fix read of random bytes out of bounds + +Reported-by: Vitaly Chikunov +--- + crypt-pbkdf1-sha1.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index e8427d5..b55d233 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -250,7 +250,8 @@ gensalt_sha1_rn (unsigned long count, + for (c = 0; (c * sizeof (unsigned long)) + sizeof (unsigned long) <= nrbytes && + (c * enclen) + enclen <= CRYPT_SHA1_SALT_LENGTH; ++c) + { +- memcpy (&encbuf, rbytes + (c * enclen), sizeof (unsigned long)); ++ memcpy (&encbuf, rbytes + (c * sizeof (unsigned long)), ++ sizeof (unsigned long)); + to64 (output + n + (c * enclen), encbuf, (int)enclen); + } + + +From fd45d0e95045b49a80a87bfa184fc9be90336779 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 29 Jun 2018 13:22:51 +0000 +Subject: [PATCH 13/38] .travis.yml: reduce flakyness + +Reduce false positives by wrapping network-related operations +into a loop. +--- + .travis.yml | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/.travis.yml b/.travis.yml +index c812e22..7e892b2 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -96,7 +96,7 @@ matrix: + - FCVER="latest" + + before_install: +- - docker pull fedora:$FCVER ++ - for i in `seq 0 99`; do docker pull fedora:$FCVER && i= && break || sleep 1; done; [ -z "$i" ] + - perl -pe 's/\$(\w+)/$ENV{$1}/g' .travis.env.in > travis.env + - docker run -t -d -P --env-file travis.env --name buildenv -v $HOME/.ccache:/root/.ccache -v $PWD:/opt/libxcrypt fedora:$FCVER /bin/sh -c "mkdir -p /opt/libxcrypt ; bash" + - docker exec -t buildenv /bin/sh -c "echo \"deltarpm=0\" >> /etc/dnf/dnf.conf" +@@ -104,12 +104,12 @@ before_install: + - docker exec -t buildenv /bin/sh -c "echo \"max_parallel_downloads=20\" >> /etc/dnf/dnf.conf" + - docker exec -t buildenv /bin/sh -c "echo \"\" >> /etc/dnf/dnf.conf" + - if [[ "$FCVER" == "rawhide" ]] ; then docker exec -t buildenv /bin/sh -c "cat /opt/libxcrypt/.travis.dnf.conf.rawhide_latest >> /etc/dnf/dnf.conf" ; fi +- - docker exec -t buildenv /bin/sh -c "dnf makecache" +- - docker exec -t buildenv /bin/sh -c "dnf -y upgrade" +- - docker exec -t buildenv /bin/sh -c "dnf -y groups install buildsys-build" +- - docker exec -t buildenv /bin/sh -c "dnf -y install libtool" +- - if [[ "$CC" == "clang" ]] ; then docker exec -t buildenv /bin/sh -c "dnf -y install clang" ; fi +- - if [[ "$CODECOV" == "1" ]] ; then docker exec -t buildenv /bin/sh -c "dnf -y install '/usr/bin/git' '/usr/bin/lcov' '/usr/bin/pip3'" ; fi ++ - docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf makecache && i= && break || sleep 1; done; [ -z "$i" ]' ++ - docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y upgrade && i= && break || sleep 1; done; [ -z "$i" ]' ++ - docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y groups install buildsys-build && i= && break || sleep 1; done; [ -z "$i" ]' ++ - docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y install libtool && i= && break || sleep 1; done; [ -z "$i" ]' ++ - if [[ "$CC" == "clang" ]] ; then docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y install clang && i= && break || sleep 1; done; [ -z "$i" ]' ; fi ++ - if [[ "$CODECOV" == "1" ]] ; then docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y install '/usr/bin/git' '/usr/bin/lcov' '/usr/bin/pip3' && i= && break || sleep 1; done; [ -z "$i" ]' ; fi + - if [[ "$CODECOV" == "1" ]] ; then docker exec -t buildenv /bin/sh -c "pip3 install codecov" ; fi + + before_script: + +From 1a51a81abc609c1a48edb2f4c0887e892e9e968f Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Wed, 4 Jul 2018 15:07:31 -0400 +Subject: [PATCH 14/38] Check in alg-des-tables.c, don't run gen-des-tables at + build time. + +This eliminates a whole bunch of dodgy logic from +Makefile.am (Automake doesn't fully comprehend the distinction between +CC and CC_FOR_BUILD) and will also make it easier to support enabling +and disabling of individual hashes without needing AM_CONDITIONALs for +each. +--- + .gitignore | 2 - + LICENSING | 6 +- + Makefile.am | 26 +- + alg-des-tables.c | 3844 ++++++++++++++++++++++++++++++++++++++++++++ + configure.ac | 1 - + gen-des-tables.c | 11 +- + m4/ax_prog_cc_for_build.m4 | 158 -- + 7 files changed, 3853 insertions(+), 195 deletions(-) + create mode 100644 alg-des-tables.c + delete mode 100644 m4/ax_prog_cc_for_build.m4 + +diff --git a/.gitignore b/.gitignore +index 3728add..5e998dd 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -42,8 +42,6 @@ + *.o + *.so + *.trs +-/gen-des-tables +-/alg-des-tables.c + /crypt.h + /crypt-symbol-vers.h + /libcrypt.map +diff --git a/LICENSING b/LICENSING +index ad5b4b5..b6f5168 100644 +--- a/LICENSING ++++ b/LICENSING +@@ -19,7 +19,8 @@ source tree. For specific licensing terms consult the files themselves. + test-crypt-badsalt, test-crypt-nonnull + + * Copyright David Burren et al.; 3-clause BSD: +- alg-des.h, alg-des.c, crypt-des.c, crypt-des-obsolete.c, gen-des-tables.c ++ alg-des.h, alg-des.c, alg-des-tables.c, ++ crypt-des.c, crypt-des-obsolete.c, gen-des-tables.c + + * Public domain, written by Solar Designer et al.: + alg-md4.h, alg-md4.c, crypt-bcrypt.c, crypt-gensalt.c, test-crypt-bcrypt.c +@@ -49,9 +50,6 @@ source tree. For specific licensing terms consult the files themselves. + GPL (v3 or later), with Autoconf exception: + m4/zw_automodern.m4, m4/zw_simple_warnings.m4 + +- * Copyright Paolo Bonzini; FSF all-permissive license for short files: +- m4/ax_prog_cc_for_build.m4 +- + * Copyright holders unknown, no statement of license (all of these + files are part of the testsuite and do not contribute to the + installed library or its headers): +diff --git a/Makefile.am b/Makefile.am +index c219bac..71fbd62 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -114,7 +114,7 @@ check_PROGRAMS = \ + + if ENABLE_WEAK_HASHES + libcrypt_la_SOURCES += \ +- crypt-des.c crypt-md5.c alg-des.c alg-md5.c ++ crypt-des.c crypt-md5.c alg-des.c alg-des-tables.c alg-md5.c + + if ENABLE_WEAK_NON_GLIBC_HASHES + libcrypt_la_SOURCES += \ +@@ -122,30 +122,6 @@ libcrypt_la_SOURCES += \ + alg-hmac-sha1.c alg-md4.c alg-sha1.c + endif + +-nodist_libcrypt_la_SOURCES = \ +- alg-des-tables.c +-CLEANFILES += alg-des-tables.c alg-des-tables.c.T +- +-noinst_PROGRAMS = gen-des-tables +- +-LINK_FOR_BUILD = $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) \ +- $(LDFLAGS_FOR_BUILD) $(TARGET_ARCH_FOR_BUILD) -o $@ +- +-gen-des-tables$(BUILD_EXEEXT): $(gen_des_tables_OBJECTS) +- @rm -f gen-des-tables$(BUILD_EXEEXT) +- $(AM_V_CCLD)$(LINK_FOR_BUILD) $(gen_des_tables_OBJECTS) $(gen_des_tables_LDADD) $(LIBS) +-# suppress the built-in rule for +-gen-des-tables$(EXEEXT): +- +-$(gen_des_tables_OBJECTS) : CC=$(CC_FOR_BUILD) +-$(gen_des_tables_OBJECTS) : CFLAGS=$(CFLAGS_FOR_BUILD) +-$(gen_des_tables_OBJECTS) : CPPFLAGS=$(CPPFLAGS_FOR_BUILD) +-$(gen_des_tables_OBJECTS) : AM_CFLAGS=$(WARN_CFLAGS_FOR_BUILD) +- +-alg-des-tables.c: gen-des-tables +- $(AM_V_GEN)./gen-des-tables$(BUILD_EXEEXT) > alg-des-tables.c.T +- $(AM_V_at)mv -f alg-des-tables.c.T alg-des-tables.c +- + check_PROGRAMS += \ + test-alg-des test-alg-md5 test-crypt-des test-crypt-md5 \ + test-crypt-badsalt +diff --git a/alg-des-tables.c b/alg-des-tables.c +new file mode 100644 +index 0000000..0bf9c88 +--- /dev/null ++++ b/alg-des-tables.c +@@ -0,0 +1,3844 @@ ++/* ++ * FreeSec: libcrypt for NetBSD ++ * ++ * Copyright (c) 1994 David Burren ++ * All rights reserved. ++ * ++ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet ++ * this file should now *only* export crypt(), in order to make ++ * binaries of libcrypt exportable from the USA ++ * ++ * Adapted for FreeBSD-4.0 by Mark R V Murray ++ * this file should now *only* export crypt_des(), in order to make ++ * a module that can be optionally included in libcrypt. ++ * ++ * 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. ++ * ++ * This is an original implementation of the DES and the crypt(3) interfaces ++ * by David Burren . ++ */ ++ ++/* ++ * The tables in this file were generated from a more compact ++ * representation of the DES S-boxes and P-boxes by the program ++ * gen-des-tables.c, which we no longer bother to run at build time. ++ */ ++ ++#include "crypt-port.h" ++#include "alg-des.h" ++ ++const uint8_t m_sbox[4][4096] = { ++ { ++ 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, 0xe6, 0xef, 0xeb, 0xe2, ++ 0xe3, 0xe8, 0xe4, 0xee, 0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, ++ 0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, 0xe0, 0xed, 0xee, 0xe8, ++ 0xe7, 0xea, 0xeb, 0xe1, 0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, ++ 0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, 0xe9, 0xe0, 0xe3, 0xe5, ++ 0xe2, 0xee, 0xef, 0xe9, 0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, ++ 0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, 0x09, 0x0c, 0x07, 0x00, ++ 0x02, 0x01, 0x0d, 0x0a, 0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, ++ 0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, 0x0a, 0x03, 0x04, 0x0f, ++ 0x0d, 0x04, 0x01, 0x02, 0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, ++ 0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, 0x4f, 0x43, 0x41, 0x4d, ++ 0x48, 0x44, 0x4e, 0x47, 0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, ++ 0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, 0x4c, 0x46, 0x40, 0x49, ++ 0x45, 0x4b, 0x4a, 0x45, 0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, ++ 0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, 0x45, 0x4b, 0x48, 0x46, ++ 0x4c, 0x47, 0x46, 0x4c, 0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, ++ 0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, 0xf6, 0xff, 0xfb, 0xf2, ++ 0xf3, 0xf8, 0xf4, 0xfe, 0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, ++ 0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, 0xf0, 0xfd, 0xfe, 0xf8, ++ 0xf7, 0xfa, 0xfb, 0xf1, 0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, ++ 0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, 0xf9, 0xf0, 0xf3, 0xf5, ++ 0xf2, 0xfe, 0xff, 0xf9, 0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, ++ 0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, 0xd9, 0xdc, 0xd7, 0xd0, ++ 0xd2, 0xd1, 0xdd, 0xda, 0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, ++ 0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, 0xda, 0xd3, 0xd4, 0xdf, ++ 0xdd, 0xd4, 0xd1, 0xd2, 0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, ++ 0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, 0x7f, 0x73, 0x71, 0x7d, ++ 0x78, 0x74, 0x7e, 0x77, 0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, ++ 0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, 0x7c, 0x76, 0x70, 0x79, ++ 0x75, 0x7b, 0x7a, 0x75, 0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, ++ 0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, 0x75, 0x7b, 0x78, 0x76, ++ 0x7c, 0x77, 0x76, 0x7c, 0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, ++ 0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, 0x16, 0x1f, 0x1b, 0x12, ++ 0x13, 0x18, 0x14, 0x1e, 0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, ++ 0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, 0x10, 0x1d, 0x1e, 0x18, ++ 0x17, 0x1a, 0x1b, 0x11, 0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, ++ 0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, 0x19, 0x10, 0x13, 0x15, ++ 0x12, 0x1e, 0x1f, 0x19, 0x4f, 0x43, 0x41, 0x4d, 0x48, 0x44, 0x4e, 0x47, ++ 0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, 0x49, 0x4c, 0x47, 0x40, ++ 0x42, 0x41, 0x4d, 0x4a, 0x4c, 0x46, 0x40, 0x49, 0x45, 0x4b, 0x4a, 0x45, ++ 0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, 0x4a, 0x43, 0x44, 0x4f, ++ 0x4d, 0x44, 0x41, 0x42, 0x45, 0x4b, 0x48, 0x46, 0x4c, 0x47, 0x46, 0x4c, ++ 0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, 0x2f, 0x23, 0x21, 0x2d, ++ 0x28, 0x24, 0x2e, 0x27, 0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, ++ 0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, 0x2c, 0x26, 0x20, 0x29, ++ 0x25, 0x2b, 0x2a, 0x25, 0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, ++ 0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, 0x25, 0x2b, 0x28, 0x26, ++ 0x2c, 0x27, 0x26, 0x2c, 0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, ++ 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, 0xe6, 0xef, 0xeb, 0xe2, ++ 0xe3, 0xe8, 0xe4, 0xee, 0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, ++ 0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, 0xe0, 0xed, 0xee, 0xe8, ++ 0xe7, 0xea, 0xeb, 0xe1, 0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, ++ 0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, 0xe9, 0xe0, 0xe3, 0xe5, ++ 0xe2, 0xee, 0xef, 0xe9, 0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, ++ 0xf6, 0xff, 0xfb, 0xf2, 0xf3, 0xf8, 0xf4, 0xfe, 0xf9, 0xfc, 0xf7, 0xf0, ++ 0xf2, 0xf1, 0xfd, 0xfa, 0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, ++ 0xf0, 0xfd, 0xfe, 0xf8, 0xf7, 0xfa, 0xfb, 0xf1, 0xfa, 0xf3, 0xf4, 0xff, ++ 0xfd, 0xf4, 0xf1, 0xf2, 0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, ++ 0xf9, 0xf0, 0xf3, 0xf5, 0xf2, 0xfe, 0xff, 0xf9, 0x2f, 0x23, 0x21, 0x2d, ++ 0x28, 0x24, 0x2e, 0x27, 0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, ++ 0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, 0x2c, 0x26, 0x20, 0x29, ++ 0x25, 0x2b, 0x2a, 0x25, 0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, ++ 0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, 0x25, 0x2b, 0x28, 0x26, ++ 0x2c, 0x27, 0x26, 0x2c, 0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, ++ 0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, 0xb6, 0xbf, 0xbb, 0xb2, ++ 0xb3, 0xb8, 0xb4, 0xbe, 0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, ++ 0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, 0xb0, 0xbd, 0xbe, 0xb8, ++ 0xb7, 0xba, 0xbb, 0xb1, 0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, ++ 0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, 0xb9, 0xb0, 0xb3, 0xb5, ++ 0xb2, 0xbe, 0xbf, 0xb9, 0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, ++ 0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, 0xd9, 0xdc, 0xd7, 0xd0, ++ 0xd2, 0xd1, 0xdd, 0xda, 0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, ++ 0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, 0xda, 0xd3, 0xd4, 0xdf, ++ 0xdd, 0xd4, 0xd1, 0xd2, 0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, ++ 0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, 0x8f, 0x83, 0x81, 0x8d, ++ 0x88, 0x84, 0x8e, 0x87, 0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, ++ 0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, 0x8c, 0x86, 0x80, 0x89, ++ 0x85, 0x8b, 0x8a, 0x85, 0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, ++ 0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, 0x85, 0x8b, 0x88, 0x86, ++ 0x8c, 0x87, 0x86, 0x8c, 0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, ++ 0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, 0x16, 0x1f, 0x1b, 0x12, ++ 0x13, 0x18, 0x14, 0x1e, 0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, ++ 0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, 0x10, 0x1d, 0x1e, 0x18, ++ 0x17, 0x1a, 0x1b, 0x11, 0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, ++ 0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, 0x19, 0x10, 0x13, 0x15, ++ 0x12, 0x1e, 0x1f, 0x19, 0x3f, 0x33, 0x31, 0x3d, 0x38, 0x34, 0x3e, 0x37, ++ 0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, 0x39, 0x3c, 0x37, 0x30, ++ 0x32, 0x31, 0x3d, 0x3a, 0x3c, 0x36, 0x30, 0x39, 0x35, 0x3b, 0x3a, 0x35, ++ 0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, 0x3a, 0x33, 0x34, 0x3f, ++ 0x3d, 0x34, 0x31, 0x32, 0x35, 0x3b, 0x38, 0x36, 0x3c, 0x37, 0x36, 0x3c, ++ 0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, 0xaf, 0xa3, 0xa1, 0xad, ++ 0xa8, 0xa4, 0xae, 0xa7, 0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, ++ 0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, 0xac, 0xa6, 0xa0, 0xa9, ++ 0xa5, 0xab, 0xaa, 0xa5, 0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, ++ 0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, 0xa5, 0xab, 0xa8, 0xa6, ++ 0xac, 0xa7, 0xa6, 0xac, 0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, ++ 0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, 0xa6, 0xaf, 0xab, 0xa2, ++ 0xa3, 0xa8, 0xa4, 0xae, 0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, ++ 0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, 0xa0, 0xad, 0xae, 0xa8, ++ 0xa7, 0xaa, 0xab, 0xa1, 0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, ++ 0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, 0xa9, 0xa0, 0xa3, 0xa5, ++ 0xa2, 0xae, 0xaf, 0xa9, 0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, ++ 0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, 0x69, 0x6c, 0x67, 0x60, ++ 0x62, 0x61, 0x6d, 0x6a, 0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, ++ 0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, 0x6a, 0x63, 0x64, 0x6f, ++ 0x6d, 0x64, 0x61, 0x62, 0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, ++ 0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, 0x6f, 0x63, 0x61, 0x6d, ++ 0x68, 0x64, 0x6e, 0x67, 0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, ++ 0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, 0x6c, 0x66, 0x60, 0x69, ++ 0x65, 0x6b, 0x6a, 0x65, 0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, ++ 0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, 0x65, 0x6b, 0x68, 0x66, ++ 0x6c, 0x67, 0x66, 0x6c, 0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, ++ 0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, 0xc6, 0xcf, 0xcb, 0xc2, ++ 0xc3, 0xc8, 0xc4, 0xce, 0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, ++ 0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, 0xc0, 0xcd, 0xce, 0xc8, ++ 0xc7, 0xca, 0xcb, 0xc1, 0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, ++ 0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, 0xc9, 0xc0, 0xc3, 0xc5, ++ 0xc2, 0xce, 0xcf, 0xc9, 0xcf, 0xc3, 0xc1, 0xcd, 0xc8, 0xc4, 0xce, 0xc7, ++ 0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, 0xc9, 0xcc, 0xc7, 0xc0, ++ 0xc2, 0xc1, 0xcd, 0xca, 0xcc, 0xc6, 0xc0, 0xc9, 0xc5, 0xcb, 0xca, 0xc5, ++ 0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, 0xca, 0xc3, 0xc4, 0xcf, ++ 0xcd, 0xc4, 0xc1, 0xc2, 0xc5, 0xcb, 0xc8, 0xc6, 0xcc, 0xc7, 0xc6, 0xcc, ++ 0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, 0xbf, 0xb3, 0xb1, 0xbd, ++ 0xb8, 0xb4, 0xbe, 0xb7, 0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, ++ 0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, 0xbc, 0xb6, 0xb0, 0xb9, ++ 0xb5, 0xbb, 0xba, 0xb5, 0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, ++ 0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, 0xb5, 0xbb, 0xb8, 0xb6, ++ 0xbc, 0xb7, 0xb6, 0xbc, 0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, ++ 0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, 0x56, 0x5f, 0x5b, 0x52, ++ 0x53, 0x58, 0x54, 0x5e, 0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, ++ 0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, 0x50, 0x5d, 0x5e, 0x58, ++ 0x57, 0x5a, 0x5b, 0x51, 0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, ++ 0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, 0x59, 0x50, 0x53, 0x55, ++ 0x52, 0x5e, 0x5f, 0x59, 0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, ++ 0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, 0x99, 0x9c, 0x97, 0x90, ++ 0x92, 0x91, 0x9d, 0x9a, 0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, ++ 0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, 0x9a, 0x93, 0x94, 0x9f, ++ 0x9d, 0x94, 0x91, 0x92, 0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, ++ 0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, 0x9f, 0x93, 0x91, 0x9d, ++ 0x98, 0x94, 0x9e, 0x97, 0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, ++ 0x99, 0x9c, 0x97, 0x90, 0x92, 0x91, 0x9d, 0x9a, 0x9c, 0x96, 0x90, 0x99, ++ 0x95, 0x9b, 0x9a, 0x95, 0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, ++ 0x9a, 0x93, 0x94, 0x9f, 0x9d, 0x94, 0x91, 0x92, 0x95, 0x9b, 0x98, 0x96, ++ 0x9c, 0x97, 0x96, 0x9c, 0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, ++ 0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, 0x56, 0x5f, 0x5b, 0x52, ++ 0x53, 0x58, 0x54, 0x5e, 0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, ++ 0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, 0x50, 0x5d, 0x5e, 0x58, ++ 0x57, 0x5a, 0x5b, 0x51, 0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, ++ 0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, 0x59, 0x50, 0x53, 0x55, ++ 0x52, 0x5e, 0x5f, 0x59, 0x0f, 0x03, 0x01, 0x0d, 0x08, 0x04, 0x0e, 0x07, ++ 0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, 0x09, 0x0c, 0x07, 0x00, ++ 0x02, 0x01, 0x0d, 0x0a, 0x0c, 0x06, 0x00, 0x09, 0x05, 0x0b, 0x0a, 0x05, ++ 0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, 0x0a, 0x03, 0x04, 0x0f, ++ 0x0d, 0x04, 0x01, 0x02, 0x05, 0x0b, 0x08, 0x06, 0x0c, 0x07, 0x06, 0x0c, ++ 0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, 0x3f, 0x33, 0x31, 0x3d, ++ 0x38, 0x34, 0x3e, 0x37, 0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, ++ 0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, 0x3c, 0x36, 0x30, 0x39, ++ 0x35, 0x3b, 0x3a, 0x35, 0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, ++ 0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, 0x35, 0x3b, 0x38, 0x36, ++ 0x3c, 0x37, 0x36, 0x3c, 0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, ++ 0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, 0x76, 0x7f, 0x7b, 0x72, ++ 0x73, 0x78, 0x74, 0x7e, 0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, ++ 0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, 0x70, 0x7d, 0x7e, 0x78, ++ 0x77, 0x7a, 0x7b, 0x71, 0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, ++ 0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, 0x79, 0x70, 0x73, 0x75, ++ 0x72, 0x7e, 0x7f, 0x79, 0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, ++ 0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, 0x89, 0x8c, 0x87, 0x80, ++ 0x82, 0x81, 0x8d, 0x8a, 0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, ++ 0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, 0x8a, 0x83, 0x84, 0x8f, ++ 0x8d, 0x84, 0x81, 0x82, 0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, ++ 0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, 0x4f, 0x43, 0x41, 0x4d, ++ 0x48, 0x44, 0x4e, 0x47, 0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, ++ 0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, 0x4c, 0x46, 0x40, 0x49, ++ 0x45, 0x4b, 0x4a, 0x45, 0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, ++ 0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, 0x45, 0x4b, 0x48, 0x46, ++ 0x4c, 0x47, 0x46, 0x4c, 0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, ++ 0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, 0xf6, 0xff, 0xfb, 0xf2, ++ 0xf3, 0xf8, 0xf4, 0xfe, 0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, ++ 0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, 0xf0, 0xfd, 0xfe, 0xf8, ++ 0xf7, 0xfa, 0xfb, 0xf1, 0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, ++ 0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, 0xf9, 0xf0, 0xf3, 0xf5, ++ 0xf2, 0xfe, 0xff, 0xf9, 0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, ++ 0x16, 0x1f, 0x1b, 0x12, 0x13, 0x18, 0x14, 0x1e, 0x19, 0x1c, 0x17, 0x10, ++ 0x12, 0x11, 0x1d, 0x1a, 0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, ++ 0x10, 0x1d, 0x1e, 0x18, 0x17, 0x1a, 0x1b, 0x11, 0x1a, 0x13, 0x14, 0x1f, ++ 0x1d, 0x14, 0x11, 0x12, 0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, ++ 0x19, 0x10, 0x13, 0x15, 0x12, 0x1e, 0x1f, 0x19, 0xcf, 0xc3, 0xc1, 0xcd, ++ 0xc8, 0xc4, 0xce, 0xc7, 0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, ++ 0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, 0xcc, 0xc6, 0xc0, 0xc9, ++ 0xc5, 0xcb, 0xca, 0xc5, 0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, ++ 0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, 0xc5, 0xcb, 0xc8, 0xc6, ++ 0xcc, 0xc7, 0xc6, 0xcc, 0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, ++ 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, 0xe6, 0xef, 0xeb, 0xe2, ++ 0xe3, 0xe8, 0xe4, 0xee, 0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, ++ 0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, 0xe0, 0xed, 0xee, 0xe8, ++ 0xe7, 0xea, 0xeb, 0xe1, 0xea, 0xe3, 0xe4, 0xef, 0xed, 0xe4, 0xe1, 0xe2, ++ 0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, 0xe9, 0xe0, 0xe3, 0xe5, ++ 0xe2, 0xee, 0xef, 0xe9, 0x8f, 0x83, 0x81, 0x8d, 0x88, 0x84, 0x8e, 0x87, ++ 0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, 0x89, 0x8c, 0x87, 0x80, ++ 0x82, 0x81, 0x8d, 0x8a, 0x8c, 0x86, 0x80, 0x89, 0x85, 0x8b, 0x8a, 0x85, ++ 0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, 0x8a, 0x83, 0x84, 0x8f, ++ 0x8d, 0x84, 0x81, 0x82, 0x85, 0x8b, 0x88, 0x86, 0x8c, 0x87, 0x86, 0x8c, ++ 0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, 0x8f, 0x83, 0x81, 0x8d, ++ 0x88, 0x84, 0x8e, 0x87, 0x86, 0x8f, 0x8b, 0x82, 0x83, 0x88, 0x84, 0x8e, ++ 0x89, 0x8c, 0x87, 0x80, 0x82, 0x81, 0x8d, 0x8a, 0x8c, 0x86, 0x80, 0x89, ++ 0x85, 0x8b, 0x8a, 0x85, 0x80, 0x8d, 0x8e, 0x88, 0x87, 0x8a, 0x8b, 0x81, ++ 0x8a, 0x83, 0x84, 0x8f, 0x8d, 0x84, 0x81, 0x82, 0x85, 0x8b, 0x88, 0x86, ++ 0x8c, 0x87, 0x86, 0x8c, 0x89, 0x80, 0x83, 0x85, 0x82, 0x8e, 0x8f, 0x89, ++ 0x2f, 0x23, 0x21, 0x2d, 0x28, 0x24, 0x2e, 0x27, 0x26, 0x2f, 0x2b, 0x22, ++ 0x23, 0x28, 0x24, 0x2e, 0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, ++ 0x2c, 0x26, 0x20, 0x29, 0x25, 0x2b, 0x2a, 0x25, 0x20, 0x2d, 0x2e, 0x28, ++ 0x27, 0x2a, 0x2b, 0x21, 0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, ++ 0x25, 0x2b, 0x28, 0x26, 0x2c, 0x27, 0x26, 0x2c, 0x29, 0x20, 0x23, 0x25, ++ 0x22, 0x2e, 0x2f, 0x29, 0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, ++ 0xd6, 0xdf, 0xdb, 0xd2, 0xd3, 0xd8, 0xd4, 0xde, 0xd9, 0xdc, 0xd7, 0xd0, ++ 0xd2, 0xd1, 0xdd, 0xda, 0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, ++ 0xd0, 0xdd, 0xde, 0xd8, 0xd7, 0xda, 0xdb, 0xd1, 0xda, 0xd3, 0xd4, 0xdf, ++ 0xdd, 0xd4, 0xd1, 0xd2, 0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, ++ 0xd9, 0xd0, 0xd3, 0xd5, 0xd2, 0xde, 0xdf, 0xd9, 0x4f, 0x43, 0x41, 0x4d, ++ 0x48, 0x44, 0x4e, 0x47, 0x46, 0x4f, 0x4b, 0x42, 0x43, 0x48, 0x44, 0x4e, ++ 0x49, 0x4c, 0x47, 0x40, 0x42, 0x41, 0x4d, 0x4a, 0x4c, 0x46, 0x40, 0x49, ++ 0x45, 0x4b, 0x4a, 0x45, 0x40, 0x4d, 0x4e, 0x48, 0x47, 0x4a, 0x4b, 0x41, ++ 0x4a, 0x43, 0x44, 0x4f, 0x4d, 0x44, 0x41, 0x42, 0x45, 0x4b, 0x48, 0x46, ++ 0x4c, 0x47, 0x46, 0x4c, 0x49, 0x40, 0x43, 0x45, 0x42, 0x4e, 0x4f, 0x49, ++ 0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, 0x66, 0x6f, 0x6b, 0x62, ++ 0x63, 0x68, 0x64, 0x6e, 0x69, 0x6c, 0x67, 0x60, 0x62, 0x61, 0x6d, 0x6a, ++ 0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, 0x60, 0x6d, 0x6e, 0x68, ++ 0x67, 0x6a, 0x6b, 0x61, 0x6a, 0x63, 0x64, 0x6f, 0x6d, 0x64, 0x61, 0x62, ++ 0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, 0x69, 0x60, 0x63, 0x65, ++ 0x62, 0x6e, 0x6f, 0x69, 0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, ++ 0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, 0x99, 0x9c, 0x97, 0x90, ++ 0x92, 0x91, 0x9d, 0x9a, 0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, ++ 0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, 0x9a, 0x93, 0x94, 0x9f, ++ 0x9d, 0x94, 0x91, 0x92, 0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, ++ 0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, 0x2f, 0x23, 0x21, 0x2d, ++ 0x28, 0x24, 0x2e, 0x27, 0x26, 0x2f, 0x2b, 0x22, 0x23, 0x28, 0x24, 0x2e, ++ 0x29, 0x2c, 0x27, 0x20, 0x22, 0x21, 0x2d, 0x2a, 0x2c, 0x26, 0x20, 0x29, ++ 0x25, 0x2b, 0x2a, 0x25, 0x20, 0x2d, 0x2e, 0x28, 0x27, 0x2a, 0x2b, 0x21, ++ 0x2a, 0x23, 0x24, 0x2f, 0x2d, 0x24, 0x21, 0x22, 0x25, 0x2b, 0x28, 0x26, ++ 0x2c, 0x27, 0x26, 0x2c, 0x29, 0x20, 0x23, 0x25, 0x22, 0x2e, 0x2f, 0x29, ++ 0x1f, 0x13, 0x11, 0x1d, 0x18, 0x14, 0x1e, 0x17, 0x16, 0x1f, 0x1b, 0x12, ++ 0x13, 0x18, 0x14, 0x1e, 0x19, 0x1c, 0x17, 0x10, 0x12, 0x11, 0x1d, 0x1a, ++ 0x1c, 0x16, 0x10, 0x19, 0x15, 0x1b, 0x1a, 0x15, 0x10, 0x1d, 0x1e, 0x18, ++ 0x17, 0x1a, 0x1b, 0x11, 0x1a, 0x13, 0x14, 0x1f, 0x1d, 0x14, 0x11, 0x12, ++ 0x15, 0x1b, 0x18, 0x16, 0x1c, 0x17, 0x16, 0x1c, 0x19, 0x10, 0x13, 0x15, ++ 0x12, 0x1e, 0x1f, 0x19, 0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, ++ 0xb6, 0xbf, 0xbb, 0xb2, 0xb3, 0xb8, 0xb4, 0xbe, 0xb9, 0xbc, 0xb7, 0xb0, ++ 0xb2, 0xb1, 0xbd, 0xba, 0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, ++ 0xb0, 0xbd, 0xbe, 0xb8, 0xb7, 0xba, 0xbb, 0xb1, 0xba, 0xb3, 0xb4, 0xbf, ++ 0xbd, 0xb4, 0xb1, 0xb2, 0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, ++ 0xb9, 0xb0, 0xb3, 0xb5, 0xb2, 0xbe, 0xbf, 0xb9, 0x7f, 0x73, 0x71, 0x7d, ++ 0x78, 0x74, 0x7e, 0x77, 0x76, 0x7f, 0x7b, 0x72, 0x73, 0x78, 0x74, 0x7e, ++ 0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, 0x7c, 0x76, 0x70, 0x79, ++ 0x75, 0x7b, 0x7a, 0x75, 0x70, 0x7d, 0x7e, 0x78, 0x77, 0x7a, 0x7b, 0x71, ++ 0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, 0x75, 0x7b, 0x78, 0x76, ++ 0x7c, 0x77, 0x76, 0x7c, 0x79, 0x70, 0x73, 0x75, 0x72, 0x7e, 0x7f, 0x79, ++ 0xff, 0xf3, 0xf1, 0xfd, 0xf8, 0xf4, 0xfe, 0xf7, 0xf6, 0xff, 0xfb, 0xf2, ++ 0xf3, 0xf8, 0xf4, 0xfe, 0xf9, 0xfc, 0xf7, 0xf0, 0xf2, 0xf1, 0xfd, 0xfa, ++ 0xfc, 0xf6, 0xf0, 0xf9, 0xf5, 0xfb, 0xfa, 0xf5, 0xf0, 0xfd, 0xfe, 0xf8, ++ 0xf7, 0xfa, 0xfb, 0xf1, 0xfa, 0xf3, 0xf4, 0xff, 0xfd, 0xf4, 0xf1, 0xf2, ++ 0xf5, 0xfb, 0xf8, 0xf6, 0xfc, 0xf7, 0xf6, 0xfc, 0xf9, 0xf0, 0xf3, 0xf5, ++ 0xf2, 0xfe, 0xff, 0xf9, 0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, ++ 0x56, 0x5f, 0x5b, 0x52, 0x53, 0x58, 0x54, 0x5e, 0x59, 0x5c, 0x57, 0x50, ++ 0x52, 0x51, 0x5d, 0x5a, 0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, ++ 0x50, 0x5d, 0x5e, 0x58, 0x57, 0x5a, 0x5b, 0x51, 0x5a, 0x53, 0x54, 0x5f, ++ 0x5d, 0x54, 0x51, 0x52, 0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, ++ 0x59, 0x50, 0x53, 0x55, 0x52, 0x5e, 0x5f, 0x59, 0xcf, 0xc3, 0xc1, 0xcd, ++ 0xc8, 0xc4, 0xce, 0xc7, 0xc6, 0xcf, 0xcb, 0xc2, 0xc3, 0xc8, 0xc4, 0xce, ++ 0xc9, 0xcc, 0xc7, 0xc0, 0xc2, 0xc1, 0xcd, 0xca, 0xcc, 0xc6, 0xc0, 0xc9, ++ 0xc5, 0xcb, 0xca, 0xc5, 0xc0, 0xcd, 0xce, 0xc8, 0xc7, 0xca, 0xcb, 0xc1, ++ 0xca, 0xc3, 0xc4, 0xcf, 0xcd, 0xc4, 0xc1, 0xc2, 0xc5, 0xcb, 0xc8, 0xc6, ++ 0xcc, 0xc7, 0xc6, 0xcc, 0xc9, 0xc0, 0xc3, 0xc5, 0xc2, 0xce, 0xcf, 0xc9, ++ 0xbf, 0xb3, 0xb1, 0xbd, 0xb8, 0xb4, 0xbe, 0xb7, 0xb6, 0xbf, 0xbb, 0xb2, ++ 0xb3, 0xb8, 0xb4, 0xbe, 0xb9, 0xbc, 0xb7, 0xb0, 0xb2, 0xb1, 0xbd, 0xba, ++ 0xbc, 0xb6, 0xb0, 0xb9, 0xb5, 0xbb, 0xba, 0xb5, 0xb0, 0xbd, 0xbe, 0xb8, ++ 0xb7, 0xba, 0xbb, 0xb1, 0xba, 0xb3, 0xb4, 0xbf, 0xbd, 0xb4, 0xb1, 0xb2, ++ 0xb5, 0xbb, 0xb8, 0xb6, 0xbc, 0xb7, 0xb6, 0xbc, 0xb9, 0xb0, 0xb3, 0xb5, ++ 0xb2, 0xbe, 0xbf, 0xb9, 0x9f, 0x93, 0x91, 0x9d, 0x98, 0x94, 0x9e, 0x97, ++ 0x96, 0x9f, 0x9b, 0x92, 0x93, 0x98, 0x94, 0x9e, 0x99, 0x9c, 0x97, 0x90, ++ 0x92, 0x91, 0x9d, 0x9a, 0x9c, 0x96, 0x90, 0x99, 0x95, 0x9b, 0x9a, 0x95, ++ 0x90, 0x9d, 0x9e, 0x98, 0x97, 0x9a, 0x9b, 0x91, 0x9a, 0x93, 0x94, 0x9f, ++ 0x9d, 0x94, 0x91, 0x92, 0x95, 0x9b, 0x98, 0x96, 0x9c, 0x97, 0x96, 0x9c, ++ 0x99, 0x90, 0x93, 0x95, 0x92, 0x9e, 0x9f, 0x99, 0x3f, 0x33, 0x31, 0x3d, ++ 0x38, 0x34, 0x3e, 0x37, 0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, ++ 0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, 0x3c, 0x36, 0x30, 0x39, ++ 0x35, 0x3b, 0x3a, 0x35, 0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, ++ 0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, 0x35, 0x3b, 0x38, 0x36, ++ 0x3c, 0x37, 0x36, 0x3c, 0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, ++ 0x7f, 0x73, 0x71, 0x7d, 0x78, 0x74, 0x7e, 0x77, 0x76, 0x7f, 0x7b, 0x72, ++ 0x73, 0x78, 0x74, 0x7e, 0x79, 0x7c, 0x77, 0x70, 0x72, 0x71, 0x7d, 0x7a, ++ 0x7c, 0x76, 0x70, 0x79, 0x75, 0x7b, 0x7a, 0x75, 0x70, 0x7d, 0x7e, 0x78, ++ 0x77, 0x7a, 0x7b, 0x71, 0x7a, 0x73, 0x74, 0x7f, 0x7d, 0x74, 0x71, 0x72, ++ 0x75, 0x7b, 0x78, 0x76, 0x7c, 0x77, 0x76, 0x7c, 0x79, 0x70, 0x73, 0x75, ++ 0x72, 0x7e, 0x7f, 0x79, 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, ++ 0xe6, 0xef, 0xeb, 0xe2, 0xe3, 0xe8, 0xe4, 0xee, 0xe9, 0xec, 0xe7, 0xe0, ++ 0xe2, 0xe1, 0xed, 0xea, 0xec, 0xe6, 0xe0, 0xe9, 0xe5, 0xeb, 0xea, 0xe5, ++ 0xe0, 0xed, 0xee, 0xe8, 0xe7, 0xea, 0xeb, 0xe1, 0xea, 0xe3, 0xe4, 0xef, ++ 0xed, 0xe4, 0xe1, 0xe2, 0xe5, 0xeb, 0xe8, 0xe6, 0xec, 0xe7, 0xe6, 0xec, ++ 0xe9, 0xe0, 0xe3, 0xe5, 0xe2, 0xee, 0xef, 0xe9, 0x3f, 0x33, 0x31, 0x3d, ++ 0x38, 0x34, 0x3e, 0x37, 0x36, 0x3f, 0x3b, 0x32, 0x33, 0x38, 0x34, 0x3e, ++ 0x39, 0x3c, 0x37, 0x30, 0x32, 0x31, 0x3d, 0x3a, 0x3c, 0x36, 0x30, 0x39, ++ 0x35, 0x3b, 0x3a, 0x35, 0x30, 0x3d, 0x3e, 0x38, 0x37, 0x3a, 0x3b, 0x31, ++ 0x3a, 0x33, 0x34, 0x3f, 0x3d, 0x34, 0x31, 0x32, 0x35, 0x3b, 0x38, 0x36, ++ 0x3c, 0x37, 0x36, 0x3c, 0x39, 0x30, 0x33, 0x35, 0x32, 0x3e, 0x3f, 0x39, ++ 0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, 0xa6, 0xaf, 0xab, 0xa2, ++ 0xa3, 0xa8, 0xa4, 0xae, 0xa9, 0xac, 0xa7, 0xa0, 0xa2, 0xa1, 0xad, 0xaa, ++ 0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, 0xa0, 0xad, 0xae, 0xa8, ++ 0xa7, 0xaa, 0xab, 0xa1, 0xaa, 0xa3, 0xa4, 0xaf, 0xad, 0xa4, 0xa1, 0xa2, ++ 0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, 0xa9, 0xa0, 0xa3, 0xa5, ++ 0xa2, 0xae, 0xaf, 0xa9, 0xaf, 0xa3, 0xa1, 0xad, 0xa8, 0xa4, 0xae, 0xa7, ++ 0xa6, 0xaf, 0xab, 0xa2, 0xa3, 0xa8, 0xa4, 0xae, 0xa9, 0xac, 0xa7, 0xa0, ++ 0xa2, 0xa1, 0xad, 0xaa, 0xac, 0xa6, 0xa0, 0xa9, 0xa5, 0xab, 0xaa, 0xa5, ++ 0xa0, 0xad, 0xae, 0xa8, 0xa7, 0xaa, 0xab, 0xa1, 0xaa, 0xa3, 0xa4, 0xaf, ++ 0xad, 0xa4, 0xa1, 0xa2, 0xa5, 0xab, 0xa8, 0xa6, 0xac, 0xa7, 0xa6, 0xac, ++ 0xa9, 0xa0, 0xa3, 0xa5, 0xa2, 0xae, 0xaf, 0xa9, 0x0f, 0x03, 0x01, 0x0d, ++ 0x08, 0x04, 0x0e, 0x07, 0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, ++ 0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, 0x0c, 0x06, 0x00, 0x09, ++ 0x05, 0x0b, 0x0a, 0x05, 0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, ++ 0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, 0x05, 0x0b, 0x08, 0x06, ++ 0x0c, 0x07, 0x06, 0x0c, 0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, ++ 0x5f, 0x53, 0x51, 0x5d, 0x58, 0x54, 0x5e, 0x57, 0x56, 0x5f, 0x5b, 0x52, ++ 0x53, 0x58, 0x54, 0x5e, 0x59, 0x5c, 0x57, 0x50, 0x52, 0x51, 0x5d, 0x5a, ++ 0x5c, 0x56, 0x50, 0x59, 0x55, 0x5b, 0x5a, 0x55, 0x50, 0x5d, 0x5e, 0x58, ++ 0x57, 0x5a, 0x5b, 0x51, 0x5a, 0x53, 0x54, 0x5f, 0x5d, 0x54, 0x51, 0x52, ++ 0x55, 0x5b, 0x58, 0x56, 0x5c, 0x57, 0x56, 0x5c, 0x59, 0x50, 0x53, 0x55, ++ 0x52, 0x5e, 0x5f, 0x59, 0x6f, 0x63, 0x61, 0x6d, 0x68, 0x64, 0x6e, 0x67, ++ 0x66, 0x6f, 0x6b, 0x62, 0x63, 0x68, 0x64, 0x6e, 0x69, 0x6c, 0x67, 0x60, ++ 0x62, 0x61, 0x6d, 0x6a, 0x6c, 0x66, 0x60, 0x69, 0x65, 0x6b, 0x6a, 0x65, ++ 0x60, 0x6d, 0x6e, 0x68, 0x67, 0x6a, 0x6b, 0x61, 0x6a, 0x63, 0x64, 0x6f, ++ 0x6d, 0x64, 0x61, 0x62, 0x65, 0x6b, 0x68, 0x66, 0x6c, 0x67, 0x66, 0x6c, ++ 0x69, 0x60, 0x63, 0x65, 0x62, 0x6e, 0x6f, 0x69, 0x0f, 0x03, 0x01, 0x0d, ++ 0x08, 0x04, 0x0e, 0x07, 0x06, 0x0f, 0x0b, 0x02, 0x03, 0x08, 0x04, 0x0e, ++ 0x09, 0x0c, 0x07, 0x00, 0x02, 0x01, 0x0d, 0x0a, 0x0c, 0x06, 0x00, 0x09, ++ 0x05, 0x0b, 0x0a, 0x05, 0x00, 0x0d, 0x0e, 0x08, 0x07, 0x0a, 0x0b, 0x01, ++ 0x0a, 0x03, 0x04, 0x0f, 0x0d, 0x04, 0x01, 0x02, 0x05, 0x0b, 0x08, 0x06, ++ 0x0c, 0x07, 0x06, 0x0c, 0x09, 0x00, 0x03, 0x05, 0x02, 0x0e, 0x0f, 0x09, ++ 0xdf, 0xd3, 0xd1, 0xdd, 0xd8, 0xd4, 0xde, 0xd7, 0xd6, 0xdf, 0xdb, 0xd2, ++ 0xd3, 0xd8, 0xd4, 0xde, 0xd9, 0xdc, 0xd7, 0xd0, 0xd2, 0xd1, 0xdd, 0xda, ++ 0xdc, 0xd6, 0xd0, 0xd9, 0xd5, 0xdb, 0xda, 0xd5, 0xd0, 0xdd, 0xde, 0xd8, ++ 0xd7, 0xda, 0xdb, 0xd1, 0xda, 0xd3, 0xd4, 0xdf, 0xdd, 0xd4, 0xd1, 0xd2, ++ 0xd5, 0xdb, 0xd8, 0xd6, 0xdc, 0xd7, 0xd6, 0xdc, 0xd9, 0xd0, 0xd3, 0xd5, ++ 0xd2, 0xde, 0xdf, 0xd9, ++ }, ++ { ++ 0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, 0xa0, 0xa6, 0xa6, 0xaf, ++ 0xa9, 0xa0, 0xaa, 0xa3, 0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, ++ 0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, 0xaa, 0xa3, 0xa6, 0xaf, ++ 0xa9, 0xa0, 0xa0, 0xa6, 0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, ++ 0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, 0xa5, 0xac, 0xa2, 0xa7, ++ 0xa8, 0xa2, 0xa4, 0xae, 0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, ++ 0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, 0xd1, 0xd4, 0xd2, 0xd7, ++ 0xd8, 0xd2, 0xd5, 0xdc, 0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, ++ 0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, 0xdc, 0xda, 0xdb, 0xd1, ++ 0xd7, 0xdd, 0xdd, 0xd8, 0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, ++ 0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, 0x07, 0x0d, 0x0d, 0x08, ++ 0x0e, 0x0b, 0x03, 0x05, 0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, ++ 0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, 0x0b, 0x01, 0x0c, 0x0a, ++ 0x04, 0x0e, 0x0f, 0x09, 0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, ++ 0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, 0x0f, 0x09, 0x01, 0x04, ++ 0x03, 0x05, 0x0e, 0x0b, 0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, ++ 0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, 0x70, 0x76, 0x76, 0x7f, ++ 0x79, 0x70, 0x7a, 0x73, 0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, ++ 0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, 0x7a, 0x73, 0x76, 0x7f, ++ 0x79, 0x70, 0x70, 0x76, 0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, ++ 0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, 0x75, 0x7c, 0x72, 0x77, ++ 0x78, 0x72, 0x74, 0x7e, 0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, ++ 0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, 0x91, 0x94, 0x92, 0x97, ++ 0x98, 0x92, 0x95, 0x9c, 0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, ++ 0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, 0x9c, 0x9a, 0x9b, 0x91, ++ 0x97, 0x9d, 0x9d, 0x98, 0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, ++ 0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, 0x07, 0x0d, 0x0d, 0x08, ++ 0x0e, 0x0b, 0x03, 0x05, 0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, ++ 0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, 0x0b, 0x01, 0x0c, 0x0a, ++ 0x04, 0x0e, 0x0f, 0x09, 0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, ++ 0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, 0x0f, 0x09, 0x01, 0x04, ++ 0x03, 0x05, 0x0e, 0x0b, 0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, ++ 0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, 0xe0, 0xe6, 0xe6, 0xef, ++ 0xe9, 0xe0, 0xea, 0xe3, 0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, ++ 0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, 0xea, 0xe3, 0xe6, 0xef, ++ 0xe9, 0xe0, 0xe0, 0xe6, 0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, ++ 0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, 0xe5, 0xec, 0xe2, 0xe7, ++ 0xe8, 0xe2, 0xe4, 0xee, 0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, ++ 0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, 0x91, 0x94, 0x92, 0x97, ++ 0x98, 0x92, 0x95, 0x9c, 0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, ++ 0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, 0x9c, 0x9a, 0x9b, 0x91, ++ 0x97, 0x9d, 0x9d, 0x98, 0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, ++ 0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, 0x67, 0x6d, 0x6d, 0x68, ++ 0x6e, 0x6b, 0x63, 0x65, 0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, ++ 0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, 0x6b, 0x61, 0x6c, 0x6a, ++ 0x64, 0x6e, 0x6f, 0x69, 0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, ++ 0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, 0x6f, 0x69, 0x61, 0x64, ++ 0x63, 0x65, 0x6e, 0x6b, 0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, ++ 0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, 0x30, 0x36, 0x36, 0x3f, ++ 0x39, 0x30, 0x3a, 0x33, 0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, ++ 0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, 0x3a, 0x33, 0x36, 0x3f, ++ 0x39, 0x30, 0x30, 0x36, 0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, ++ 0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, 0x35, 0x3c, 0x32, 0x37, ++ 0x38, 0x32, 0x34, 0x3e, 0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, ++ 0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, 0x31, 0x34, 0x32, 0x37, ++ 0x38, 0x32, 0x35, 0x3c, 0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, ++ 0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, 0x3c, 0x3a, 0x3b, 0x31, ++ 0x37, 0x3d, 0x3d, 0x38, 0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, ++ 0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, 0x47, 0x4d, 0x4d, 0x48, ++ 0x4e, 0x4b, 0x43, 0x45, 0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, ++ 0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, 0x4b, 0x41, 0x4c, 0x4a, ++ 0x44, 0x4e, 0x4f, 0x49, 0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, ++ 0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, 0x4f, 0x49, 0x41, 0x44, ++ 0x43, 0x45, 0x4e, 0x4b, 0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, ++ 0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, 0xf0, 0xf6, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xfa, 0xf3, 0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, ++ 0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, 0xfa, 0xf3, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xf0, 0xf6, 0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, ++ 0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, 0xf5, 0xfc, 0xf2, 0xf7, ++ 0xf8, 0xf2, 0xf4, 0xfe, 0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, ++ 0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, 0x61, 0x64, 0x62, 0x67, ++ 0x68, 0x62, 0x65, 0x6c, 0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, ++ 0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, 0x6c, 0x6a, 0x6b, 0x61, ++ 0x67, 0x6d, 0x6d, 0x68, 0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, ++ 0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, 0x57, 0x5d, 0x5d, 0x58, ++ 0x5e, 0x5b, 0x53, 0x55, 0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, ++ 0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, 0x5b, 0x51, 0x5c, 0x5a, ++ 0x54, 0x5e, 0x5f, 0x59, 0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, ++ 0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, 0x5f, 0x59, 0x51, 0x54, ++ 0x53, 0x55, 0x5e, 0x5b, 0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, ++ 0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, 0xa0, 0xa6, 0xa6, 0xaf, ++ 0xa9, 0xa0, 0xaa, 0xa3, 0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, ++ 0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, 0xaa, 0xa3, 0xa6, 0xaf, ++ 0xa9, 0xa0, 0xa0, 0xa6, 0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, ++ 0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, 0xa5, 0xac, 0xa2, 0xa7, ++ 0xa8, 0xa2, 0xa4, 0xae, 0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, ++ 0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, 0x11, 0x14, 0x12, 0x17, ++ 0x18, 0x12, 0x15, 0x1c, 0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, ++ 0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, 0x1c, 0x1a, 0x1b, 0x11, ++ 0x17, 0x1d, 0x1d, 0x18, 0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, ++ 0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, 0x27, 0x2d, 0x2d, 0x28, ++ 0x2e, 0x2b, 0x23, 0x25, 0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, ++ 0x21, 0x24, 0x22, 0x27, 0x28, 0x22, 0x25, 0x2c, 0x2b, 0x21, 0x2c, 0x2a, ++ 0x24, 0x2e, 0x2f, 0x29, 0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, ++ 0x2c, 0x2a, 0x2b, 0x21, 0x27, 0x2d, 0x2d, 0x28, 0x2f, 0x29, 0x21, 0x24, ++ 0x23, 0x25, 0x2e, 0x2b, 0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, ++ 0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, 0xd0, 0xd6, 0xd6, 0xdf, ++ 0xd9, 0xd0, 0xda, 0xd3, 0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, ++ 0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, 0xda, 0xd3, 0xd6, 0xdf, ++ 0xd9, 0xd0, 0xd0, 0xd6, 0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, ++ 0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, 0xd5, 0xdc, 0xd2, 0xd7, ++ 0xd8, 0xd2, 0xd4, 0xde, 0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, ++ 0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, 0x81, 0x84, 0x82, 0x87, ++ 0x88, 0x82, 0x85, 0x8c, 0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, ++ 0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, 0x8c, 0x8a, 0x8b, 0x81, ++ 0x87, 0x8d, 0x8d, 0x88, 0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, ++ 0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, 0xc7, 0xcd, 0xcd, 0xc8, ++ 0xce, 0xcb, 0xc3, 0xc5, 0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, ++ 0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, 0xcb, 0xc1, 0xcc, 0xca, ++ 0xc4, 0xce, 0xcf, 0xc9, 0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, ++ 0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, 0xcf, 0xc9, 0xc1, 0xc4, ++ 0xc3, 0xc5, 0xce, 0xcb, 0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, ++ 0x57, 0x5d, 0x5d, 0x58, 0x5e, 0x5b, 0x53, 0x55, 0x50, 0x56, 0x56, 0x5f, ++ 0x59, 0x50, 0x5a, 0x53, 0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, ++ 0x5b, 0x51, 0x5c, 0x5a, 0x54, 0x5e, 0x5f, 0x59, 0x5a, 0x53, 0x56, 0x5f, ++ 0x59, 0x50, 0x50, 0x56, 0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, ++ 0x5f, 0x59, 0x51, 0x54, 0x53, 0x55, 0x5e, 0x5b, 0x55, 0x5c, 0x52, 0x57, ++ 0x58, 0x52, 0x54, 0x5e, 0x77, 0x7d, 0x7d, 0x78, 0x7e, 0x7b, 0x73, 0x75, ++ 0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, 0x71, 0x74, 0x72, 0x77, ++ 0x78, 0x72, 0x75, 0x7c, 0x7b, 0x71, 0x7c, 0x7a, 0x74, 0x7e, 0x7f, 0x79, ++ 0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, 0x7c, 0x7a, 0x7b, 0x71, ++ 0x77, 0x7d, 0x7d, 0x78, 0x7f, 0x79, 0x71, 0x74, 0x73, 0x75, 0x7e, 0x7b, ++ 0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, 0xe7, 0xed, 0xed, 0xe8, ++ 0xee, 0xeb, 0xe3, 0xe5, 0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, ++ 0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, 0xeb, 0xe1, 0xec, 0xea, ++ 0xe4, 0xee, 0xef, 0xe9, 0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, ++ 0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, 0xef, 0xe9, 0xe1, 0xe4, ++ 0xe3, 0xe5, 0xee, 0xeb, 0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, ++ 0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, 0xb0, 0xb6, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xba, 0xb3, 0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, ++ 0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, 0xba, 0xb3, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xb0, 0xb6, 0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, ++ 0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, 0xb5, 0xbc, 0xb2, 0xb7, ++ 0xb8, 0xb2, 0xb4, 0xbe, 0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, ++ 0xc0, 0xc6, 0xc6, 0xcf, 0xc9, 0xc0, 0xca, 0xc3, 0xc1, 0xc4, 0xc2, 0xc7, ++ 0xc8, 0xc2, 0xc5, 0xcc, 0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, ++ 0xca, 0xc3, 0xc6, 0xcf, 0xc9, 0xc0, 0xc0, 0xc6, 0xcc, 0xca, 0xcb, 0xc1, ++ 0xc7, 0xcd, 0xcd, 0xc8, 0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, ++ 0xc5, 0xcc, 0xc2, 0xc7, 0xc8, 0xc2, 0xc4, 0xce, 0x47, 0x4d, 0x4d, 0x48, ++ 0x4e, 0x4b, 0x43, 0x45, 0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, ++ 0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, 0x4b, 0x41, 0x4c, 0x4a, ++ 0x44, 0x4e, 0x4f, 0x49, 0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, ++ 0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, 0x4f, 0x49, 0x41, 0x44, ++ 0x43, 0x45, 0x4e, 0x4b, 0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, ++ 0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, 0xb0, 0xb6, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xba, 0xb3, 0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, ++ 0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, 0xba, 0xb3, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xb0, 0xb6, 0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, ++ 0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, 0xb5, 0xbc, 0xb2, 0xb7, ++ 0xb8, 0xb2, 0xb4, 0xbe, 0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, ++ 0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, 0x21, 0x24, 0x22, 0x27, ++ 0x28, 0x22, 0x25, 0x2c, 0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, ++ 0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, 0x2c, 0x2a, 0x2b, 0x21, ++ 0x27, 0x2d, 0x2d, 0x28, 0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, ++ 0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, 0xf7, 0xfd, 0xfd, 0xf8, ++ 0xfe, 0xfb, 0xf3, 0xf5, 0xf0, 0xf6, 0xf6, 0xff, 0xf9, 0xf0, 0xfa, 0xf3, ++ 0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, 0xfb, 0xf1, 0xfc, 0xfa, ++ 0xf4, 0xfe, 0xff, 0xf9, 0xfa, 0xf3, 0xf6, 0xff, 0xf9, 0xf0, 0xf0, 0xf6, ++ 0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, 0xff, 0xf9, 0xf1, 0xf4, ++ 0xf3, 0xf5, 0xfe, 0xfb, 0xf5, 0xfc, 0xf2, 0xf7, 0xf8, 0xf2, 0xf4, 0xfe, ++ 0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, 0x80, 0x86, 0x86, 0x8f, ++ 0x89, 0x80, 0x8a, 0x83, 0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, ++ 0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, 0x8a, 0x83, 0x86, 0x8f, ++ 0x89, 0x80, 0x80, 0x86, 0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, ++ 0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, 0x85, 0x8c, 0x82, 0x87, ++ 0x88, 0x82, 0x84, 0x8e, 0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, ++ 0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, 0x11, 0x14, 0x12, 0x17, ++ 0x18, 0x12, 0x15, 0x1c, 0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, ++ 0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, 0x1c, 0x1a, 0x1b, 0x11, ++ 0x17, 0x1d, 0x1d, 0x18, 0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, ++ 0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, 0xd7, 0xdd, 0xdd, 0xd8, ++ 0xde, 0xdb, 0xd3, 0xd5, 0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, ++ 0xd1, 0xd4, 0xd2, 0xd7, 0xd8, 0xd2, 0xd5, 0xdc, 0xdb, 0xd1, 0xdc, 0xda, ++ 0xd4, 0xde, 0xdf, 0xd9, 0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, ++ 0xdc, 0xda, 0xdb, 0xd1, 0xd7, 0xdd, 0xdd, 0xd8, 0xdf, 0xd9, 0xd1, 0xd4, ++ 0xd3, 0xd5, 0xde, 0xdb, 0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, ++ 0x17, 0x1d, 0x1d, 0x18, 0x1e, 0x1b, 0x13, 0x15, 0x10, 0x16, 0x16, 0x1f, ++ 0x19, 0x10, 0x1a, 0x13, 0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, ++ 0x1b, 0x11, 0x1c, 0x1a, 0x14, 0x1e, 0x1f, 0x19, 0x1a, 0x13, 0x16, 0x1f, ++ 0x19, 0x10, 0x10, 0x16, 0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, ++ 0x1f, 0x19, 0x11, 0x14, 0x13, 0x15, 0x1e, 0x1b, 0x15, 0x1c, 0x12, 0x17, ++ 0x18, 0x12, 0x14, 0x1e, 0x67, 0x6d, 0x6d, 0x68, 0x6e, 0x6b, 0x63, 0x65, ++ 0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, 0x61, 0x64, 0x62, 0x67, ++ 0x68, 0x62, 0x65, 0x6c, 0x6b, 0x61, 0x6c, 0x6a, 0x64, 0x6e, 0x6f, 0x69, ++ 0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, 0x6c, 0x6a, 0x6b, 0x61, ++ 0x67, 0x6d, 0x6d, 0x68, 0x6f, 0x69, 0x61, 0x64, 0x63, 0x65, 0x6e, 0x6b, ++ 0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, 0xa7, 0xad, 0xad, 0xa8, ++ 0xae, 0xab, 0xa3, 0xa5, 0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, ++ 0xa1, 0xa4, 0xa2, 0xa7, 0xa8, 0xa2, 0xa5, 0xac, 0xab, 0xa1, 0xac, 0xaa, ++ 0xa4, 0xae, 0xaf, 0xa9, 0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, ++ 0xac, 0xaa, 0xab, 0xa1, 0xa7, 0xad, 0xad, 0xa8, 0xaf, 0xa9, 0xa1, 0xa4, ++ 0xa3, 0xa5, 0xae, 0xab, 0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, ++ 0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, 0x40, 0x46, 0x46, 0x4f, ++ 0x49, 0x40, 0x4a, 0x43, 0x41, 0x44, 0x42, 0x47, 0x48, 0x42, 0x45, 0x4c, ++ 0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, 0x4a, 0x43, 0x46, 0x4f, ++ 0x49, 0x40, 0x40, 0x46, 0x4c, 0x4a, 0x4b, 0x41, 0x47, 0x4d, 0x4d, 0x48, ++ 0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, 0x45, 0x4c, 0x42, 0x47, ++ 0x48, 0x42, 0x44, 0x4e, 0xd7, 0xdd, 0xdd, 0xd8, 0xde, 0xdb, 0xd3, 0xd5, ++ 0xd0, 0xd6, 0xd6, 0xdf, 0xd9, 0xd0, 0xda, 0xd3, 0xd1, 0xd4, 0xd2, 0xd7, ++ 0xd8, 0xd2, 0xd5, 0xdc, 0xdb, 0xd1, 0xdc, 0xda, 0xd4, 0xde, 0xdf, 0xd9, ++ 0xda, 0xd3, 0xd6, 0xdf, 0xd9, 0xd0, 0xd0, 0xd6, 0xdc, 0xda, 0xdb, 0xd1, ++ 0xd7, 0xdd, 0xdd, 0xd8, 0xdf, 0xd9, 0xd1, 0xd4, 0xd3, 0xd5, 0xde, 0xdb, ++ 0xd5, 0xdc, 0xd2, 0xd7, 0xd8, 0xd2, 0xd4, 0xde, 0x97, 0x9d, 0x9d, 0x98, ++ 0x9e, 0x9b, 0x93, 0x95, 0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, ++ 0x91, 0x94, 0x92, 0x97, 0x98, 0x92, 0x95, 0x9c, 0x9b, 0x91, 0x9c, 0x9a, ++ 0x94, 0x9e, 0x9f, 0x99, 0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, ++ 0x9c, 0x9a, 0x9b, 0x91, 0x97, 0x9d, 0x9d, 0x98, 0x9f, 0x99, 0x91, 0x94, ++ 0x93, 0x95, 0x9e, 0x9b, 0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, ++ 0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, 0x00, 0x06, 0x06, 0x0f, ++ 0x09, 0x00, 0x0a, 0x03, 0x01, 0x04, 0x02, 0x07, 0x08, 0x02, 0x05, 0x0c, ++ 0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, 0x0a, 0x03, 0x06, 0x0f, ++ 0x09, 0x00, 0x00, 0x06, 0x0c, 0x0a, 0x0b, 0x01, 0x07, 0x0d, 0x0d, 0x08, ++ 0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, 0x05, 0x0c, 0x02, 0x07, ++ 0x08, 0x02, 0x04, 0x0e, 0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, ++ 0x80, 0x86, 0x86, 0x8f, 0x89, 0x80, 0x8a, 0x83, 0x81, 0x84, 0x82, 0x87, ++ 0x88, 0x82, 0x85, 0x8c, 0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, ++ 0x8a, 0x83, 0x86, 0x8f, 0x89, 0x80, 0x80, 0x86, 0x8c, 0x8a, 0x8b, 0x81, ++ 0x87, 0x8d, 0x8d, 0x88, 0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, ++ 0x85, 0x8c, 0x82, 0x87, 0x88, 0x82, 0x84, 0x8e, 0x67, 0x6d, 0x6d, 0x68, ++ 0x6e, 0x6b, 0x63, 0x65, 0x60, 0x66, 0x66, 0x6f, 0x69, 0x60, 0x6a, 0x63, ++ 0x61, 0x64, 0x62, 0x67, 0x68, 0x62, 0x65, 0x6c, 0x6b, 0x61, 0x6c, 0x6a, ++ 0x64, 0x6e, 0x6f, 0x69, 0x6a, 0x63, 0x66, 0x6f, 0x69, 0x60, 0x60, 0x66, ++ 0x6c, 0x6a, 0x6b, 0x61, 0x67, 0x6d, 0x6d, 0x68, 0x6f, 0x69, 0x61, 0x64, ++ 0x63, 0x65, 0x6e, 0x6b, 0x65, 0x6c, 0x62, 0x67, 0x68, 0x62, 0x64, 0x6e, ++ 0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, 0xf0, 0xf6, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xfa, 0xf3, 0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, ++ 0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, 0xfa, 0xf3, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xf0, 0xf6, 0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, ++ 0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, 0xf5, 0xfc, 0xf2, 0xf7, ++ 0xf8, 0xf2, 0xf4, 0xfe, 0x97, 0x9d, 0x9d, 0x98, 0x9e, 0x9b, 0x93, 0x95, ++ 0x90, 0x96, 0x96, 0x9f, 0x99, 0x90, 0x9a, 0x93, 0x91, 0x94, 0x92, 0x97, ++ 0x98, 0x92, 0x95, 0x9c, 0x9b, 0x91, 0x9c, 0x9a, 0x94, 0x9e, 0x9f, 0x99, ++ 0x9a, 0x93, 0x96, 0x9f, 0x99, 0x90, 0x90, 0x96, 0x9c, 0x9a, 0x9b, 0x91, ++ 0x97, 0x9d, 0x9d, 0x98, 0x9f, 0x99, 0x91, 0x94, 0x93, 0x95, 0x9e, 0x9b, ++ 0x95, 0x9c, 0x92, 0x97, 0x98, 0x92, 0x94, 0x9e, 0x37, 0x3d, 0x3d, 0x38, ++ 0x3e, 0x3b, 0x33, 0x35, 0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, ++ 0x31, 0x34, 0x32, 0x37, 0x38, 0x32, 0x35, 0x3c, 0x3b, 0x31, 0x3c, 0x3a, ++ 0x34, 0x3e, 0x3f, 0x39, 0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, ++ 0x3c, 0x3a, 0x3b, 0x31, 0x37, 0x3d, 0x3d, 0x38, 0x3f, 0x39, 0x31, 0x34, ++ 0x33, 0x35, 0x3e, 0x3b, 0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, ++ 0x87, 0x8d, 0x8d, 0x88, 0x8e, 0x8b, 0x83, 0x85, 0x80, 0x86, 0x86, 0x8f, ++ 0x89, 0x80, 0x8a, 0x83, 0x81, 0x84, 0x82, 0x87, 0x88, 0x82, 0x85, 0x8c, ++ 0x8b, 0x81, 0x8c, 0x8a, 0x84, 0x8e, 0x8f, 0x89, 0x8a, 0x83, 0x86, 0x8f, ++ 0x89, 0x80, 0x80, 0x86, 0x8c, 0x8a, 0x8b, 0x81, 0x87, 0x8d, 0x8d, 0x88, ++ 0x8f, 0x89, 0x81, 0x84, 0x83, 0x85, 0x8e, 0x8b, 0x85, 0x8c, 0x82, 0x87, ++ 0x88, 0x82, 0x84, 0x8e, 0x07, 0x0d, 0x0d, 0x08, 0x0e, 0x0b, 0x03, 0x05, ++ 0x00, 0x06, 0x06, 0x0f, 0x09, 0x00, 0x0a, 0x03, 0x01, 0x04, 0x02, 0x07, ++ 0x08, 0x02, 0x05, 0x0c, 0x0b, 0x01, 0x0c, 0x0a, 0x04, 0x0e, 0x0f, 0x09, ++ 0x0a, 0x03, 0x06, 0x0f, 0x09, 0x00, 0x00, 0x06, 0x0c, 0x0a, 0x0b, 0x01, ++ 0x07, 0x0d, 0x0d, 0x08, 0x0f, 0x09, 0x01, 0x04, 0x03, 0x05, 0x0e, 0x0b, ++ 0x05, 0x0c, 0x02, 0x07, 0x08, 0x02, 0x04, 0x0e, 0x77, 0x7d, 0x7d, 0x78, ++ 0x7e, 0x7b, 0x73, 0x75, 0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, ++ 0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, 0x7b, 0x71, 0x7c, 0x7a, ++ 0x74, 0x7e, 0x7f, 0x79, 0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, ++ 0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, 0x7f, 0x79, 0x71, 0x74, ++ 0x73, 0x75, 0x7e, 0x7b, 0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, ++ 0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, 0xb0, 0xb6, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xba, 0xb3, 0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, ++ 0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, 0xba, 0xb3, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xb0, 0xb6, 0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, ++ 0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, 0xb5, 0xbc, 0xb2, 0xb7, ++ 0xb8, 0xb2, 0xb4, 0xbe, 0x47, 0x4d, 0x4d, 0x48, 0x4e, 0x4b, 0x43, 0x45, ++ 0x40, 0x46, 0x46, 0x4f, 0x49, 0x40, 0x4a, 0x43, 0x41, 0x44, 0x42, 0x47, ++ 0x48, 0x42, 0x45, 0x4c, 0x4b, 0x41, 0x4c, 0x4a, 0x44, 0x4e, 0x4f, 0x49, ++ 0x4a, 0x43, 0x46, 0x4f, 0x49, 0x40, 0x40, 0x46, 0x4c, 0x4a, 0x4b, 0x41, ++ 0x47, 0x4d, 0x4d, 0x48, 0x4f, 0x49, 0x41, 0x44, 0x43, 0x45, 0x4e, 0x4b, ++ 0x45, 0x4c, 0x42, 0x47, 0x48, 0x42, 0x44, 0x4e, 0x17, 0x1d, 0x1d, 0x18, ++ 0x1e, 0x1b, 0x13, 0x15, 0x10, 0x16, 0x16, 0x1f, 0x19, 0x10, 0x1a, 0x13, ++ 0x11, 0x14, 0x12, 0x17, 0x18, 0x12, 0x15, 0x1c, 0x1b, 0x11, 0x1c, 0x1a, ++ 0x14, 0x1e, 0x1f, 0x19, 0x1a, 0x13, 0x16, 0x1f, 0x19, 0x10, 0x10, 0x16, ++ 0x1c, 0x1a, 0x1b, 0x11, 0x17, 0x1d, 0x1d, 0x18, 0x1f, 0x19, 0x11, 0x14, ++ 0x13, 0x15, 0x1e, 0x1b, 0x15, 0x1c, 0x12, 0x17, 0x18, 0x12, 0x14, 0x1e, ++ 0xf7, 0xfd, 0xfd, 0xf8, 0xfe, 0xfb, 0xf3, 0xf5, 0xf0, 0xf6, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xfa, 0xf3, 0xf1, 0xf4, 0xf2, 0xf7, 0xf8, 0xf2, 0xf5, 0xfc, ++ 0xfb, 0xf1, 0xfc, 0xfa, 0xf4, 0xfe, 0xff, 0xf9, 0xfa, 0xf3, 0xf6, 0xff, ++ 0xf9, 0xf0, 0xf0, 0xf6, 0xfc, 0xfa, 0xfb, 0xf1, 0xf7, 0xfd, 0xfd, 0xf8, ++ 0xff, 0xf9, 0xf1, 0xf4, 0xf3, 0xf5, 0xfe, 0xfb, 0xf5, 0xfc, 0xf2, 0xf7, ++ 0xf8, 0xf2, 0xf4, 0xfe, 0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, ++ 0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, 0x21, 0x24, 0x22, 0x27, ++ 0x28, 0x22, 0x25, 0x2c, 0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, ++ 0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, 0x2c, 0x2a, 0x2b, 0x21, ++ 0x27, 0x2d, 0x2d, 0x28, 0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, ++ 0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, 0xe7, 0xed, 0xed, 0xe8, ++ 0xee, 0xeb, 0xe3, 0xe5, 0xe0, 0xe6, 0xe6, 0xef, 0xe9, 0xe0, 0xea, 0xe3, ++ 0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, 0xeb, 0xe1, 0xec, 0xea, ++ 0xe4, 0xee, 0xef, 0xe9, 0xea, 0xe3, 0xe6, 0xef, 0xe9, 0xe0, 0xe0, 0xe6, ++ 0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, 0xef, 0xe9, 0xe1, 0xe4, ++ 0xe3, 0xe5, 0xee, 0xeb, 0xe5, 0xec, 0xe2, 0xe7, 0xe8, 0xe2, 0xe4, 0xee, ++ 0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, 0xc0, 0xc6, 0xc6, 0xcf, ++ 0xc9, 0xc0, 0xca, 0xc3, 0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, ++ 0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, 0xca, 0xc3, 0xc6, 0xcf, ++ 0xc9, 0xc0, 0xc0, 0xc6, 0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, ++ 0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, 0xc5, 0xcc, 0xc2, 0xc7, ++ 0xc8, 0xc2, 0xc4, 0xce, 0x37, 0x3d, 0x3d, 0x38, 0x3e, 0x3b, 0x33, 0x35, ++ 0x30, 0x36, 0x36, 0x3f, 0x39, 0x30, 0x3a, 0x33, 0x31, 0x34, 0x32, 0x37, ++ 0x38, 0x32, 0x35, 0x3c, 0x3b, 0x31, 0x3c, 0x3a, 0x34, 0x3e, 0x3f, 0x39, ++ 0x3a, 0x33, 0x36, 0x3f, 0x39, 0x30, 0x30, 0x36, 0x3c, 0x3a, 0x3b, 0x31, ++ 0x37, 0x3d, 0x3d, 0x38, 0x3f, 0x39, 0x31, 0x34, 0x33, 0x35, 0x3e, 0x3b, ++ 0x35, 0x3c, 0x32, 0x37, 0x38, 0x32, 0x34, 0x3e, 0x57, 0x5d, 0x5d, 0x58, ++ 0x5e, 0x5b, 0x53, 0x55, 0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, ++ 0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, 0x5b, 0x51, 0x5c, 0x5a, ++ 0x54, 0x5e, 0x5f, 0x59, 0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, ++ 0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, 0x5f, 0x59, 0x51, 0x54, ++ 0x53, 0x55, 0x5e, 0x5b, 0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, ++ 0xb7, 0xbd, 0xbd, 0xb8, 0xbe, 0xbb, 0xb3, 0xb5, 0xb0, 0xb6, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xba, 0xb3, 0xb1, 0xb4, 0xb2, 0xb7, 0xb8, 0xb2, 0xb5, 0xbc, ++ 0xbb, 0xb1, 0xbc, 0xba, 0xb4, 0xbe, 0xbf, 0xb9, 0xba, 0xb3, 0xb6, 0xbf, ++ 0xb9, 0xb0, 0xb0, 0xb6, 0xbc, 0xba, 0xbb, 0xb1, 0xb7, 0xbd, 0xbd, 0xb8, ++ 0xbf, 0xb9, 0xb1, 0xb4, 0xb3, 0xb5, 0xbe, 0xbb, 0xb5, 0xbc, 0xb2, 0xb7, ++ 0xb8, 0xb2, 0xb4, 0xbe, 0xa7, 0xad, 0xad, 0xa8, 0xae, 0xab, 0xa3, 0xa5, ++ 0xa0, 0xa6, 0xa6, 0xaf, 0xa9, 0xa0, 0xaa, 0xa3, 0xa1, 0xa4, 0xa2, 0xa7, ++ 0xa8, 0xa2, 0xa5, 0xac, 0xab, 0xa1, 0xac, 0xaa, 0xa4, 0xae, 0xaf, 0xa9, ++ 0xaa, 0xa3, 0xa6, 0xaf, 0xa9, 0xa0, 0xa0, 0xa6, 0xac, 0xaa, 0xab, 0xa1, ++ 0xa7, 0xad, 0xad, 0xa8, 0xaf, 0xa9, 0xa1, 0xa4, 0xa3, 0xa5, 0xae, 0xab, ++ 0xa5, 0xac, 0xa2, 0xa7, 0xa8, 0xa2, 0xa4, 0xae, 0x57, 0x5d, 0x5d, 0x58, ++ 0x5e, 0x5b, 0x53, 0x55, 0x50, 0x56, 0x56, 0x5f, 0x59, 0x50, 0x5a, 0x53, ++ 0x51, 0x54, 0x52, 0x57, 0x58, 0x52, 0x55, 0x5c, 0x5b, 0x51, 0x5c, 0x5a, ++ 0x54, 0x5e, 0x5f, 0x59, 0x5a, 0x53, 0x56, 0x5f, 0x59, 0x50, 0x50, 0x56, ++ 0x5c, 0x5a, 0x5b, 0x51, 0x57, 0x5d, 0x5d, 0x58, 0x5f, 0x59, 0x51, 0x54, ++ 0x53, 0x55, 0x5e, 0x5b, 0x55, 0x5c, 0x52, 0x57, 0x58, 0x52, 0x54, 0x5e, ++ 0xe7, 0xed, 0xed, 0xe8, 0xee, 0xeb, 0xe3, 0xe5, 0xe0, 0xe6, 0xe6, 0xef, ++ 0xe9, 0xe0, 0xea, 0xe3, 0xe1, 0xe4, 0xe2, 0xe7, 0xe8, 0xe2, 0xe5, 0xec, ++ 0xeb, 0xe1, 0xec, 0xea, 0xe4, 0xee, 0xef, 0xe9, 0xea, 0xe3, 0xe6, 0xef, ++ 0xe9, 0xe0, 0xe0, 0xe6, 0xec, 0xea, 0xeb, 0xe1, 0xe7, 0xed, 0xed, 0xe8, ++ 0xef, 0xe9, 0xe1, 0xe4, 0xe3, 0xe5, 0xee, 0xeb, 0xe5, 0xec, 0xe2, 0xe7, ++ 0xe8, 0xe2, 0xe4, 0xee, 0x27, 0x2d, 0x2d, 0x28, 0x2e, 0x2b, 0x23, 0x25, ++ 0x20, 0x26, 0x26, 0x2f, 0x29, 0x20, 0x2a, 0x23, 0x21, 0x24, 0x22, 0x27, ++ 0x28, 0x22, 0x25, 0x2c, 0x2b, 0x21, 0x2c, 0x2a, 0x24, 0x2e, 0x2f, 0x29, ++ 0x2a, 0x23, 0x26, 0x2f, 0x29, 0x20, 0x20, 0x26, 0x2c, 0x2a, 0x2b, 0x21, ++ 0x27, 0x2d, 0x2d, 0x28, 0x2f, 0x29, 0x21, 0x24, 0x23, 0x25, 0x2e, 0x2b, ++ 0x25, 0x2c, 0x22, 0x27, 0x28, 0x22, 0x24, 0x2e, 0x77, 0x7d, 0x7d, 0x78, ++ 0x7e, 0x7b, 0x73, 0x75, 0x70, 0x76, 0x76, 0x7f, 0x79, 0x70, 0x7a, 0x73, ++ 0x71, 0x74, 0x72, 0x77, 0x78, 0x72, 0x75, 0x7c, 0x7b, 0x71, 0x7c, 0x7a, ++ 0x74, 0x7e, 0x7f, 0x79, 0x7a, 0x73, 0x76, 0x7f, 0x79, 0x70, 0x70, 0x76, ++ 0x7c, 0x7a, 0x7b, 0x71, 0x77, 0x7d, 0x7d, 0x78, 0x7f, 0x79, 0x71, 0x74, ++ 0x73, 0x75, 0x7e, 0x7b, 0x75, 0x7c, 0x72, 0x77, 0x78, 0x72, 0x74, 0x7e, ++ 0xc7, 0xcd, 0xcd, 0xc8, 0xce, 0xcb, 0xc3, 0xc5, 0xc0, 0xc6, 0xc6, 0xcf, ++ 0xc9, 0xc0, 0xca, 0xc3, 0xc1, 0xc4, 0xc2, 0xc7, 0xc8, 0xc2, 0xc5, 0xcc, ++ 0xcb, 0xc1, 0xcc, 0xca, 0xc4, 0xce, 0xcf, 0xc9, 0xca, 0xc3, 0xc6, 0xcf, ++ 0xc9, 0xc0, 0xc0, 0xc6, 0xcc, 0xca, 0xcb, 0xc1, 0xc7, 0xcd, 0xcd, 0xc8, ++ 0xcf, 0xc9, 0xc1, 0xc4, 0xc3, 0xc5, 0xce, 0xcb, 0xc5, 0xcc, 0xc2, 0xc7, ++ 0xc8, 0xc2, 0xc4, 0xce, ++ }, ++ { ++ 0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, 0x29, 0x27, 0x22, 0x2c, ++ 0x26, 0x29, 0x28, 0x25, 0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, ++ 0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, 0x29, 0x24, 0x2e, 0x23, ++ 0x2f, 0x22, 0x25, 0x2c, 0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, ++ 0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, 0x21, 0x26, 0x2d, 0x20, ++ 0x2b, 0x28, 0x26, 0x2d, 0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, ++ 0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, 0xe0, 0xe6, 0xed, 0xe1, ++ 0xe3, 0xed, 0xe4, 0xee, 0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, ++ 0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, 0xe2, 0xe9, 0xe8, 0xe5, ++ 0xec, 0xef, 0xe3, 0xea, 0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, ++ 0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, 0xcc, 0xca, 0xc1, 0xcf, ++ 0xca, 0xc4, 0xcf, 0xc2, 0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, ++ 0xc0, 0xc6, 0xcd, 0xc1, 0xc3, 0xcd, 0xc4, 0xce, 0xce, 0xc0, 0xc7, 0xcb, ++ 0xc5, 0xc3, 0xcb, 0xc8, 0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, ++ 0xc2, 0xc9, 0xc8, 0xc5, 0xcc, 0xcf, 0xc3, 0xca, 0xc7, 0xcb, 0xc0, 0xce, ++ 0xc4, 0xc1, 0xca, 0xc7, 0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, ++ 0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, 0xb9, 0xb7, 0xb2, 0xbc, ++ 0xb6, 0xb9, 0xb8, 0xb5, 0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, ++ 0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, 0xb9, 0xb4, 0xbe, 0xb3, ++ 0xbf, 0xb2, 0xb5, 0xbc, 0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, ++ 0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, 0xb1, 0xb6, 0xbd, 0xb0, ++ 0xbb, 0xb8, 0xb6, 0xbd, 0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, ++ 0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, 0x40, 0x46, 0x4d, 0x41, ++ 0x43, 0x4d, 0x44, 0x4e, 0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, ++ 0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, 0x42, 0x49, 0x48, 0x45, ++ 0x4c, 0x4f, 0x43, 0x4a, 0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, ++ 0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, 0x2c, 0x2a, 0x21, 0x2f, ++ 0x2a, 0x24, 0x2f, 0x22, 0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, ++ 0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, 0x2e, 0x20, 0x27, 0x2b, ++ 0x25, 0x23, 0x2b, 0x28, 0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, ++ 0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, 0x27, 0x2b, 0x20, 0x2e, ++ 0x24, 0x21, 0x2a, 0x27, 0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, ++ 0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, 0x19, 0x17, 0x12, 0x1c, ++ 0x16, 0x19, 0x18, 0x15, 0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, ++ 0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, 0x19, 0x14, 0x1e, 0x13, ++ 0x1f, 0x12, 0x15, 0x1c, 0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, ++ 0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, 0x11, 0x16, 0x1d, 0x10, ++ 0x1b, 0x18, 0x16, 0x1d, 0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, ++ 0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, 0xc0, 0xc6, 0xcd, 0xc1, ++ 0xc3, 0xcd, 0xc4, 0xce, 0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, ++ 0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, 0xc2, 0xc9, 0xc8, 0xc5, ++ 0xcc, 0xcf, 0xc3, 0xca, 0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, ++ 0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, 0x7c, 0x7a, 0x71, 0x7f, ++ 0x7a, 0x74, 0x7f, 0x72, 0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, ++ 0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, 0x7e, 0x70, 0x77, 0x7b, ++ 0x75, 0x73, 0x7b, 0x78, 0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, ++ 0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, 0x77, 0x7b, 0x70, 0x7e, ++ 0x74, 0x71, 0x7a, 0x77, 0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, ++ 0x4c, 0x4a, 0x41, 0x4f, 0x4a, 0x44, 0x4f, 0x42, 0x49, 0x47, 0x42, 0x4c, ++ 0x46, 0x49, 0x48, 0x45, 0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, ++ 0x4e, 0x40, 0x47, 0x4b, 0x45, 0x43, 0x4b, 0x48, 0x49, 0x44, 0x4e, 0x43, ++ 0x4f, 0x42, 0x45, 0x4c, 0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, ++ 0x47, 0x4b, 0x40, 0x4e, 0x44, 0x41, 0x4a, 0x47, 0x41, 0x46, 0x4d, 0x40, ++ 0x4b, 0x48, 0x46, 0x4d, 0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, ++ 0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, 0xa0, 0xa6, 0xad, 0xa1, ++ 0xa3, 0xad, 0xa4, 0xae, 0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, ++ 0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, 0xa2, 0xa9, 0xa8, 0xa5, ++ 0xac, 0xaf, 0xa3, 0xaa, 0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, ++ 0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, 0x7c, 0x7a, 0x71, 0x7f, ++ 0x7a, 0x74, 0x7f, 0x72, 0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, ++ 0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, 0x7e, 0x70, 0x77, 0x7b, ++ 0x75, 0x73, 0x7b, 0x78, 0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, ++ 0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, 0x77, 0x7b, 0x70, 0x7e, ++ 0x74, 0x71, 0x7a, 0x77, 0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, ++ 0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, 0xb9, 0xb7, 0xb2, 0xbc, ++ 0xb6, 0xb9, 0xb8, 0xb5, 0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, ++ 0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, 0xb9, 0xb4, 0xbe, 0xb3, ++ 0xbf, 0xb2, 0xb5, 0xbc, 0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, ++ 0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, 0xb1, 0xb6, 0xbd, 0xb0, ++ 0xbb, 0xb8, 0xb6, 0xbd, 0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, ++ 0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, 0xd0, 0xd6, 0xdd, 0xd1, ++ 0xd3, 0xdd, 0xd4, 0xde, 0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, ++ 0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, 0xd2, 0xd9, 0xd8, 0xd5, ++ 0xdc, 0xdf, 0xd3, 0xda, 0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, ++ 0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, 0x6c, 0x6a, 0x61, 0x6f, ++ 0x6a, 0x64, 0x6f, 0x62, 0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, ++ 0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, 0x6e, 0x60, 0x67, 0x6b, ++ 0x65, 0x63, 0x6b, 0x68, 0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, ++ 0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, 0x67, 0x6b, 0x60, 0x6e, ++ 0x64, 0x61, 0x6a, 0x67, 0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, ++ 0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, 0x19, 0x17, 0x12, 0x1c, ++ 0x16, 0x19, 0x18, 0x15, 0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, ++ 0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, 0x19, 0x14, 0x1e, 0x13, ++ 0x1f, 0x12, 0x15, 0x1c, 0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, ++ 0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, 0x11, 0x16, 0x1d, 0x10, ++ 0x1b, 0x18, 0x16, 0x1d, 0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, ++ 0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, 0x80, 0x86, 0x8d, 0x81, ++ 0x83, 0x8d, 0x84, 0x8e, 0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, ++ 0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, 0x82, 0x89, 0x88, 0x85, ++ 0x8c, 0x8f, 0x83, 0x8a, 0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, ++ 0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, 0x5c, 0x5a, 0x51, 0x5f, ++ 0x5a, 0x54, 0x5f, 0x52, 0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, ++ 0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, 0x5e, 0x50, 0x57, 0x5b, ++ 0x55, 0x53, 0x5b, 0x58, 0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, ++ 0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, 0x57, 0x5b, 0x50, 0x5e, ++ 0x54, 0x51, 0x5a, 0x57, 0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, ++ 0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, 0x59, 0x57, 0x52, 0x5c, ++ 0x56, 0x59, 0x58, 0x55, 0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, ++ 0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, 0x59, 0x54, 0x5e, 0x53, ++ 0x5f, 0x52, 0x55, 0x5c, 0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, ++ 0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, 0x51, 0x56, 0x5d, 0x50, ++ 0x5b, 0x58, 0x56, 0x5d, 0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, ++ 0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, 0x00, 0x06, 0x0d, 0x01, ++ 0x03, 0x0d, 0x04, 0x0e, 0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, ++ 0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, 0x02, 0x09, 0x08, 0x05, ++ 0x0c, 0x0f, 0x03, 0x0a, 0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, ++ 0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, 0x3c, 0x3a, 0x31, 0x3f, ++ 0x3a, 0x34, 0x3f, 0x32, 0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, ++ 0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, 0x3e, 0x30, 0x37, 0x3b, ++ 0x35, 0x33, 0x3b, 0x38, 0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, ++ 0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, 0x37, 0x3b, 0x30, 0x3e, ++ 0x34, 0x31, 0x3a, 0x37, 0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, ++ 0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, 0xf9, 0xf7, 0xf2, 0xfc, ++ 0xf6, 0xf9, 0xf8, 0xf5, 0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, ++ 0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, 0xf9, 0xf4, 0xfe, 0xf3, ++ 0xff, 0xf2, 0xf5, 0xfc, 0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, ++ 0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, 0xf1, 0xf6, 0xfd, 0xf0, ++ 0xfb, 0xf8, 0xf6, 0xfd, 0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, ++ 0xf9, 0xf7, 0xf2, 0xfc, 0xf6, 0xf9, 0xf8, 0xf5, 0xf0, 0xf6, 0xfd, 0xf1, ++ 0xf3, 0xfd, 0xf4, 0xfe, 0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, ++ 0xf9, 0xf4, 0xfe, 0xf3, 0xff, 0xf2, 0xf5, 0xfc, 0xf2, 0xf9, 0xf8, 0xf5, ++ 0xfc, 0xff, 0xf3, 0xfa, 0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, ++ 0xf1, 0xf6, 0xfd, 0xf0, 0xfb, 0xf8, 0xf6, 0xfd, 0xac, 0xaa, 0xa1, 0xaf, ++ 0xaa, 0xa4, 0xaf, 0xa2, 0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, ++ 0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, 0xae, 0xa0, 0xa7, 0xab, ++ 0xa5, 0xa3, 0xab, 0xa8, 0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, ++ 0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, 0xa7, 0xab, 0xa0, 0xae, ++ 0xa4, 0xa1, 0xaa, 0xa7, 0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, ++ 0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, 0xd9, 0xd7, 0xd2, 0xdc, ++ 0xd6, 0xd9, 0xd8, 0xd5, 0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, ++ 0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, 0xd9, 0xd4, 0xde, 0xd3, ++ 0xdf, 0xd2, 0xd5, 0xdc, 0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, ++ 0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, 0xd1, 0xd6, 0xdd, 0xd0, ++ 0xdb, 0xd8, 0xd6, 0xdd, 0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, ++ 0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, 0x30, 0x36, 0x3d, 0x31, ++ 0x33, 0x3d, 0x34, 0x3e, 0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, ++ 0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, 0x32, 0x39, 0x38, 0x35, ++ 0x3c, 0x3f, 0x33, 0x3a, 0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, ++ 0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, 0x0c, 0x0a, 0x01, 0x0f, ++ 0x0a, 0x04, 0x0f, 0x02, 0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, ++ 0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, 0x0e, 0x00, 0x07, 0x0b, ++ 0x05, 0x03, 0x0b, 0x08, 0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, ++ 0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, 0x07, 0x0b, 0x00, 0x0e, ++ 0x04, 0x01, 0x0a, 0x07, 0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, ++ 0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, 0x99, 0x97, 0x92, 0x9c, ++ 0x96, 0x99, 0x98, 0x95, 0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, ++ 0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, 0x99, 0x94, 0x9e, 0x93, ++ 0x9f, 0x92, 0x95, 0x9c, 0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, ++ 0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, 0x91, 0x96, 0x9d, 0x90, ++ 0x9b, 0x98, 0x96, 0x9d, 0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, ++ 0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, 0xe0, 0xe6, 0xed, 0xe1, ++ 0xe3, 0xed, 0xe4, 0xee, 0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, ++ 0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, 0xe2, 0xe9, 0xe8, 0xe5, ++ 0xec, 0xef, 0xe3, 0xea, 0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, ++ 0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, 0x8c, 0x8a, 0x81, 0x8f, ++ 0x8a, 0x84, 0x8f, 0x82, 0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, ++ 0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, 0x8e, 0x80, 0x87, 0x8b, ++ 0x85, 0x83, 0x8b, 0x88, 0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, ++ 0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, 0x87, 0x8b, 0x80, 0x8e, ++ 0x84, 0x81, 0x8a, 0x87, 0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, ++ 0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, 0x99, 0x97, 0x92, 0x9c, ++ 0x96, 0x99, 0x98, 0x95, 0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, ++ 0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, 0x99, 0x94, 0x9e, 0x93, ++ 0x9f, 0x92, 0x95, 0x9c, 0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, ++ 0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, 0x91, 0x96, 0x9d, 0x90, ++ 0x9b, 0x98, 0x96, 0x9d, 0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, ++ 0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, 0x60, 0x66, 0x6d, 0x61, ++ 0x63, 0x6d, 0x64, 0x6e, 0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, ++ 0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, 0x62, 0x69, 0x68, 0x65, ++ 0x6c, 0x6f, 0x63, 0x6a, 0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, ++ 0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, 0x4c, 0x4a, 0x41, 0x4f, ++ 0x4a, 0x44, 0x4f, 0x42, 0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, ++ 0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, 0x4e, 0x40, 0x47, 0x4b, ++ 0x45, 0x43, 0x4b, 0x48, 0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, ++ 0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, 0x47, 0x4b, 0x40, 0x4e, ++ 0x44, 0x41, 0x4a, 0x47, 0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, ++ 0xbc, 0xba, 0xb1, 0xbf, 0xba, 0xb4, 0xbf, 0xb2, 0xb9, 0xb7, 0xb2, 0xbc, ++ 0xb6, 0xb9, 0xb8, 0xb5, 0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, ++ 0xbe, 0xb0, 0xb7, 0xbb, 0xb5, 0xb3, 0xbb, 0xb8, 0xb9, 0xb4, 0xbe, 0xb3, ++ 0xbf, 0xb2, 0xb5, 0xbc, 0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, ++ 0xb7, 0xbb, 0xb0, 0xbe, 0xb4, 0xb1, 0xba, 0xb7, 0xb1, 0xb6, 0xbd, 0xb0, ++ 0xbb, 0xb8, 0xb6, 0xbd, 0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, ++ 0x29, 0x27, 0x22, 0x2c, 0x26, 0x29, 0x28, 0x25, 0x20, 0x26, 0x2d, 0x21, ++ 0x23, 0x2d, 0x24, 0x2e, 0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, ++ 0x29, 0x24, 0x2e, 0x23, 0x2f, 0x22, 0x25, 0x2c, 0x22, 0x29, 0x28, 0x25, ++ 0x2c, 0x2f, 0x23, 0x2a, 0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, ++ 0x21, 0x26, 0x2d, 0x20, 0x2b, 0x28, 0x26, 0x2d, 0x8c, 0x8a, 0x81, 0x8f, ++ 0x8a, 0x84, 0x8f, 0x82, 0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, ++ 0x80, 0x86, 0x8d, 0x81, 0x83, 0x8d, 0x84, 0x8e, 0x8e, 0x80, 0x87, 0x8b, ++ 0x85, 0x83, 0x8b, 0x88, 0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, ++ 0x82, 0x89, 0x88, 0x85, 0x8c, 0x8f, 0x83, 0x8a, 0x87, 0x8b, 0x80, 0x8e, ++ 0x84, 0x81, 0x8a, 0x87, 0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, ++ 0x1c, 0x1a, 0x11, 0x1f, 0x1a, 0x14, 0x1f, 0x12, 0x19, 0x17, 0x12, 0x1c, ++ 0x16, 0x19, 0x18, 0x15, 0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, ++ 0x1e, 0x10, 0x17, 0x1b, 0x15, 0x13, 0x1b, 0x18, 0x19, 0x14, 0x1e, 0x13, ++ 0x1f, 0x12, 0x15, 0x1c, 0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, ++ 0x17, 0x1b, 0x10, 0x1e, 0x14, 0x11, 0x1a, 0x17, 0x11, 0x16, 0x1d, 0x10, ++ 0x1b, 0x18, 0x16, 0x1d, 0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, ++ 0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, 0xc0, 0xc6, 0xcd, 0xc1, ++ 0xc3, 0xcd, 0xc4, 0xce, 0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, ++ 0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, 0xc2, 0xc9, 0xc8, 0xc5, ++ 0xcc, 0xcf, 0xc3, 0xca, 0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, ++ 0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, 0xbc, 0xba, 0xb1, 0xbf, ++ 0xba, 0xb4, 0xbf, 0xb2, 0xb9, 0xb7, 0xb2, 0xbc, 0xb6, 0xb9, 0xb8, 0xb5, ++ 0xb0, 0xb6, 0xbd, 0xb1, 0xb3, 0xbd, 0xb4, 0xbe, 0xbe, 0xb0, 0xb7, 0xbb, ++ 0xb5, 0xb3, 0xbb, 0xb8, 0xb9, 0xb4, 0xbe, 0xb3, 0xbf, 0xb2, 0xb5, 0xbc, ++ 0xb2, 0xb9, 0xb8, 0xb5, 0xbc, 0xbf, 0xb3, 0xba, 0xb7, 0xbb, 0xb0, 0xbe, ++ 0xb4, 0xb1, 0xba, 0xb7, 0xb1, 0xb6, 0xbd, 0xb0, 0xbb, 0xb8, 0xb6, 0xbd, ++ 0x7c, 0x7a, 0x71, 0x7f, 0x7a, 0x74, 0x7f, 0x72, 0x79, 0x77, 0x72, 0x7c, ++ 0x76, 0x79, 0x78, 0x75, 0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, ++ 0x7e, 0x70, 0x77, 0x7b, 0x75, 0x73, 0x7b, 0x78, 0x79, 0x74, 0x7e, 0x73, ++ 0x7f, 0x72, 0x75, 0x7c, 0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, ++ 0x77, 0x7b, 0x70, 0x7e, 0x74, 0x71, 0x7a, 0x77, 0x71, 0x76, 0x7d, 0x70, ++ 0x7b, 0x78, 0x76, 0x7d, 0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, ++ 0xa9, 0xa7, 0xa2, 0xac, 0xa6, 0xa9, 0xa8, 0xa5, 0xa0, 0xa6, 0xad, 0xa1, ++ 0xa3, 0xad, 0xa4, 0xae, 0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, ++ 0xa9, 0xa4, 0xae, 0xa3, 0xaf, 0xa2, 0xa5, 0xac, 0xa2, 0xa9, 0xa8, 0xa5, ++ 0xac, 0xaf, 0xa3, 0xaa, 0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, ++ 0xa1, 0xa6, 0xad, 0xa0, 0xab, 0xa8, 0xa6, 0xad, 0x1c, 0x1a, 0x11, 0x1f, ++ 0x1a, 0x14, 0x1f, 0x12, 0x19, 0x17, 0x12, 0x1c, 0x16, 0x19, 0x18, 0x15, ++ 0x10, 0x16, 0x1d, 0x11, 0x13, 0x1d, 0x14, 0x1e, 0x1e, 0x10, 0x17, 0x1b, ++ 0x15, 0x13, 0x1b, 0x18, 0x19, 0x14, 0x1e, 0x13, 0x1f, 0x12, 0x15, 0x1c, ++ 0x12, 0x19, 0x18, 0x15, 0x1c, 0x1f, 0x13, 0x1a, 0x17, 0x1b, 0x10, 0x1e, ++ 0x14, 0x11, 0x1a, 0x17, 0x11, 0x16, 0x1d, 0x10, 0x1b, 0x18, 0x16, 0x1d, ++ 0xdc, 0xda, 0xd1, 0xdf, 0xda, 0xd4, 0xdf, 0xd2, 0xd9, 0xd7, 0xd2, 0xdc, ++ 0xd6, 0xd9, 0xd8, 0xd5, 0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, ++ 0xde, 0xd0, 0xd7, 0xdb, 0xd5, 0xd3, 0xdb, 0xd8, 0xd9, 0xd4, 0xde, 0xd3, ++ 0xdf, 0xd2, 0xd5, 0xdc, 0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, ++ 0xd7, 0xdb, 0xd0, 0xde, 0xd4, 0xd1, 0xda, 0xd7, 0xd1, 0xd6, 0xdd, 0xd0, ++ 0xdb, 0xd8, 0xd6, 0xdd, 0xec, 0xea, 0xe1, 0xef, 0xea, 0xe4, 0xef, 0xe2, ++ 0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, 0xe0, 0xe6, 0xed, 0xe1, ++ 0xe3, 0xed, 0xe4, 0xee, 0xee, 0xe0, 0xe7, 0xeb, 0xe5, 0xe3, 0xeb, 0xe8, ++ 0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, 0xe2, 0xe9, 0xe8, 0xe5, ++ 0xec, 0xef, 0xe3, 0xea, 0xe7, 0xeb, 0xe0, 0xee, 0xe4, 0xe1, 0xea, 0xe7, ++ 0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, 0x7c, 0x7a, 0x71, 0x7f, ++ 0x7a, 0x74, 0x7f, 0x72, 0x79, 0x77, 0x72, 0x7c, 0x76, 0x79, 0x78, 0x75, ++ 0x70, 0x76, 0x7d, 0x71, 0x73, 0x7d, 0x74, 0x7e, 0x7e, 0x70, 0x77, 0x7b, ++ 0x75, 0x73, 0x7b, 0x78, 0x79, 0x74, 0x7e, 0x73, 0x7f, 0x72, 0x75, 0x7c, ++ 0x72, 0x79, 0x78, 0x75, 0x7c, 0x7f, 0x73, 0x7a, 0x77, 0x7b, 0x70, 0x7e, ++ 0x74, 0x71, 0x7a, 0x77, 0x71, 0x76, 0x7d, 0x70, 0x7b, 0x78, 0x76, 0x7d, ++ 0x2c, 0x2a, 0x21, 0x2f, 0x2a, 0x24, 0x2f, 0x22, 0x29, 0x27, 0x22, 0x2c, ++ 0x26, 0x29, 0x28, 0x25, 0x20, 0x26, 0x2d, 0x21, 0x23, 0x2d, 0x24, 0x2e, ++ 0x2e, 0x20, 0x27, 0x2b, 0x25, 0x23, 0x2b, 0x28, 0x29, 0x24, 0x2e, 0x23, ++ 0x2f, 0x22, 0x25, 0x2c, 0x22, 0x29, 0x28, 0x25, 0x2c, 0x2f, 0x23, 0x2a, ++ 0x27, 0x2b, 0x20, 0x2e, 0x24, 0x21, 0x2a, 0x27, 0x21, 0x26, 0x2d, 0x20, ++ 0x2b, 0x28, 0x26, 0x2d, 0x8c, 0x8a, 0x81, 0x8f, 0x8a, 0x84, 0x8f, 0x82, ++ 0x89, 0x87, 0x82, 0x8c, 0x86, 0x89, 0x88, 0x85, 0x80, 0x86, 0x8d, 0x81, ++ 0x83, 0x8d, 0x84, 0x8e, 0x8e, 0x80, 0x87, 0x8b, 0x85, 0x83, 0x8b, 0x88, ++ 0x89, 0x84, 0x8e, 0x83, 0x8f, 0x82, 0x85, 0x8c, 0x82, 0x89, 0x88, 0x85, ++ 0x8c, 0x8f, 0x83, 0x8a, 0x87, 0x8b, 0x80, 0x8e, 0x84, 0x81, 0x8a, 0x87, ++ 0x81, 0x86, 0x8d, 0x80, 0x8b, 0x88, 0x86, 0x8d, 0xdc, 0xda, 0xd1, 0xdf, ++ 0xda, 0xd4, 0xdf, 0xd2, 0xd9, 0xd7, 0xd2, 0xdc, 0xd6, 0xd9, 0xd8, 0xd5, ++ 0xd0, 0xd6, 0xdd, 0xd1, 0xd3, 0xdd, 0xd4, 0xde, 0xde, 0xd0, 0xd7, 0xdb, ++ 0xd5, 0xd3, 0xdb, 0xd8, 0xd9, 0xd4, 0xde, 0xd3, 0xdf, 0xd2, 0xd5, 0xdc, ++ 0xd2, 0xd9, 0xd8, 0xd5, 0xdc, 0xdf, 0xd3, 0xda, 0xd7, 0xdb, 0xd0, 0xde, ++ 0xd4, 0xd1, 0xda, 0xd7, 0xd1, 0xd6, 0xdd, 0xd0, 0xdb, 0xd8, 0xd6, 0xdd, ++ 0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, 0xf9, 0xf7, 0xf2, 0xfc, ++ 0xf6, 0xf9, 0xf8, 0xf5, 0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, ++ 0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, 0xf9, 0xf4, 0xfe, 0xf3, ++ 0xff, 0xf2, 0xf5, 0xfc, 0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, ++ 0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, 0xf1, 0xf6, 0xfd, 0xf0, ++ 0xfb, 0xf8, 0xf6, 0xfd, 0x6c, 0x6a, 0x61, 0x6f, 0x6a, 0x64, 0x6f, 0x62, ++ 0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, 0x60, 0x66, 0x6d, 0x61, ++ 0x63, 0x6d, 0x64, 0x6e, 0x6e, 0x60, 0x67, 0x6b, 0x65, 0x63, 0x6b, 0x68, ++ 0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, 0x62, 0x69, 0x68, 0x65, ++ 0x6c, 0x6f, 0x63, 0x6a, 0x67, 0x6b, 0x60, 0x6e, 0x64, 0x61, 0x6a, 0x67, ++ 0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, 0x9c, 0x9a, 0x91, 0x9f, ++ 0x9a, 0x94, 0x9f, 0x92, 0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, ++ 0x90, 0x96, 0x9d, 0x91, 0x93, 0x9d, 0x94, 0x9e, 0x9e, 0x90, 0x97, 0x9b, ++ 0x95, 0x93, 0x9b, 0x98, 0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, ++ 0x92, 0x99, 0x98, 0x95, 0x9c, 0x9f, 0x93, 0x9a, 0x97, 0x9b, 0x90, 0x9e, ++ 0x94, 0x91, 0x9a, 0x97, 0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, ++ 0xfc, 0xfa, 0xf1, 0xff, 0xfa, 0xf4, 0xff, 0xf2, 0xf9, 0xf7, 0xf2, 0xfc, ++ 0xf6, 0xf9, 0xf8, 0xf5, 0xf0, 0xf6, 0xfd, 0xf1, 0xf3, 0xfd, 0xf4, 0xfe, ++ 0xfe, 0xf0, 0xf7, 0xfb, 0xf5, 0xf3, 0xfb, 0xf8, 0xf9, 0xf4, 0xfe, 0xf3, ++ 0xff, 0xf2, 0xf5, 0xfc, 0xf2, 0xf9, 0xf8, 0xf5, 0xfc, 0xff, 0xf3, 0xfa, ++ 0xf7, 0xfb, 0xf0, 0xfe, 0xf4, 0xf1, 0xfa, 0xf7, 0xf1, 0xf6, 0xfd, 0xf0, ++ 0xfb, 0xf8, 0xf6, 0xfd, 0xcc, 0xca, 0xc1, 0xcf, 0xca, 0xc4, 0xcf, 0xc2, ++ 0xc9, 0xc7, 0xc2, 0xcc, 0xc6, 0xc9, 0xc8, 0xc5, 0xc0, 0xc6, 0xcd, 0xc1, ++ 0xc3, 0xcd, 0xc4, 0xce, 0xce, 0xc0, 0xc7, 0xcb, 0xc5, 0xc3, 0xcb, 0xc8, ++ 0xc9, 0xc4, 0xce, 0xc3, 0xcf, 0xc2, 0xc5, 0xcc, 0xc2, 0xc9, 0xc8, 0xc5, ++ 0xcc, 0xcf, 0xc3, 0xca, 0xc7, 0xcb, 0xc0, 0xce, 0xc4, 0xc1, 0xca, 0xc7, ++ 0xc1, 0xc6, 0xcd, 0xc0, 0xcb, 0xc8, 0xc6, 0xcd, 0x0c, 0x0a, 0x01, 0x0f, ++ 0x0a, 0x04, 0x0f, 0x02, 0x09, 0x07, 0x02, 0x0c, 0x06, 0x09, 0x08, 0x05, ++ 0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, 0x0e, 0x00, 0x07, 0x0b, ++ 0x05, 0x03, 0x0b, 0x08, 0x09, 0x04, 0x0e, 0x03, 0x0f, 0x02, 0x05, 0x0c, ++ 0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, 0x07, 0x0b, 0x00, 0x0e, ++ 0x04, 0x01, 0x0a, 0x07, 0x01, 0x06, 0x0d, 0x00, 0x0b, 0x08, 0x06, 0x0d, ++ 0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, 0x59, 0x57, 0x52, 0x5c, ++ 0x56, 0x59, 0x58, 0x55, 0x50, 0x56, 0x5d, 0x51, 0x53, 0x5d, 0x54, 0x5e, ++ 0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, 0x59, 0x54, 0x5e, 0x53, ++ 0x5f, 0x52, 0x55, 0x5c, 0x52, 0x59, 0x58, 0x55, 0x5c, 0x5f, 0x53, 0x5a, ++ 0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, 0x51, 0x56, 0x5d, 0x50, ++ 0x5b, 0x58, 0x56, 0x5d, 0x9c, 0x9a, 0x91, 0x9f, 0x9a, 0x94, 0x9f, 0x92, ++ 0x99, 0x97, 0x92, 0x9c, 0x96, 0x99, 0x98, 0x95, 0x90, 0x96, 0x9d, 0x91, ++ 0x93, 0x9d, 0x94, 0x9e, 0x9e, 0x90, 0x97, 0x9b, 0x95, 0x93, 0x9b, 0x98, ++ 0x99, 0x94, 0x9e, 0x93, 0x9f, 0x92, 0x95, 0x9c, 0x92, 0x99, 0x98, 0x95, ++ 0x9c, 0x9f, 0x93, 0x9a, 0x97, 0x9b, 0x90, 0x9e, 0x94, 0x91, 0x9a, 0x97, ++ 0x91, 0x96, 0x9d, 0x90, 0x9b, 0x98, 0x96, 0x9d, 0x6c, 0x6a, 0x61, 0x6f, ++ 0x6a, 0x64, 0x6f, 0x62, 0x69, 0x67, 0x62, 0x6c, 0x66, 0x69, 0x68, 0x65, ++ 0x60, 0x66, 0x6d, 0x61, 0x63, 0x6d, 0x64, 0x6e, 0x6e, 0x60, 0x67, 0x6b, ++ 0x65, 0x63, 0x6b, 0x68, 0x69, 0x64, 0x6e, 0x63, 0x6f, 0x62, 0x65, 0x6c, ++ 0x62, 0x69, 0x68, 0x65, 0x6c, 0x6f, 0x63, 0x6a, 0x67, 0x6b, 0x60, 0x6e, ++ 0x64, 0x61, 0x6a, 0x67, 0x61, 0x66, 0x6d, 0x60, 0x6b, 0x68, 0x66, 0x6d, ++ 0xac, 0xaa, 0xa1, 0xaf, 0xaa, 0xa4, 0xaf, 0xa2, 0xa9, 0xa7, 0xa2, 0xac, ++ 0xa6, 0xa9, 0xa8, 0xa5, 0xa0, 0xa6, 0xad, 0xa1, 0xa3, 0xad, 0xa4, 0xae, ++ 0xae, 0xa0, 0xa7, 0xab, 0xa5, 0xa3, 0xab, 0xa8, 0xa9, 0xa4, 0xae, 0xa3, ++ 0xaf, 0xa2, 0xa5, 0xac, 0xa2, 0xa9, 0xa8, 0xa5, 0xac, 0xaf, 0xa3, 0xaa, ++ 0xa7, 0xab, 0xa0, 0xae, 0xa4, 0xa1, 0xaa, 0xa7, 0xa1, 0xa6, 0xad, 0xa0, ++ 0xab, 0xa8, 0xa6, 0xad, 0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, ++ 0x39, 0x37, 0x32, 0x3c, 0x36, 0x39, 0x38, 0x35, 0x30, 0x36, 0x3d, 0x31, ++ 0x33, 0x3d, 0x34, 0x3e, 0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, ++ 0x39, 0x34, 0x3e, 0x33, 0x3f, 0x32, 0x35, 0x3c, 0x32, 0x39, 0x38, 0x35, ++ 0x3c, 0x3f, 0x33, 0x3a, 0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, ++ 0x31, 0x36, 0x3d, 0x30, 0x3b, 0x38, 0x36, 0x3d, 0x4c, 0x4a, 0x41, 0x4f, ++ 0x4a, 0x44, 0x4f, 0x42, 0x49, 0x47, 0x42, 0x4c, 0x46, 0x49, 0x48, 0x45, ++ 0x40, 0x46, 0x4d, 0x41, 0x43, 0x4d, 0x44, 0x4e, 0x4e, 0x40, 0x47, 0x4b, ++ 0x45, 0x43, 0x4b, 0x48, 0x49, 0x44, 0x4e, 0x43, 0x4f, 0x42, 0x45, 0x4c, ++ 0x42, 0x49, 0x48, 0x45, 0x4c, 0x4f, 0x43, 0x4a, 0x47, 0x4b, 0x40, 0x4e, ++ 0x44, 0x41, 0x4a, 0x47, 0x41, 0x46, 0x4d, 0x40, 0x4b, 0x48, 0x46, 0x4d, ++ 0x0c, 0x0a, 0x01, 0x0f, 0x0a, 0x04, 0x0f, 0x02, 0x09, 0x07, 0x02, 0x0c, ++ 0x06, 0x09, 0x08, 0x05, 0x00, 0x06, 0x0d, 0x01, 0x03, 0x0d, 0x04, 0x0e, ++ 0x0e, 0x00, 0x07, 0x0b, 0x05, 0x03, 0x0b, 0x08, 0x09, 0x04, 0x0e, 0x03, ++ 0x0f, 0x02, 0x05, 0x0c, 0x02, 0x09, 0x08, 0x05, 0x0c, 0x0f, 0x03, 0x0a, ++ 0x07, 0x0b, 0x00, 0x0e, 0x04, 0x01, 0x0a, 0x07, 0x01, 0x06, 0x0d, 0x00, ++ 0x0b, 0x08, 0x06, 0x0d, 0x5c, 0x5a, 0x51, 0x5f, 0x5a, 0x54, 0x5f, 0x52, ++ 0x59, 0x57, 0x52, 0x5c, 0x56, 0x59, 0x58, 0x55, 0x50, 0x56, 0x5d, 0x51, ++ 0x53, 0x5d, 0x54, 0x5e, 0x5e, 0x50, 0x57, 0x5b, 0x55, 0x53, 0x5b, 0x58, ++ 0x59, 0x54, 0x5e, 0x53, 0x5f, 0x52, 0x55, 0x5c, 0x52, 0x59, 0x58, 0x55, ++ 0x5c, 0x5f, 0x53, 0x5a, 0x57, 0x5b, 0x50, 0x5e, 0x54, 0x51, 0x5a, 0x57, ++ 0x51, 0x56, 0x5d, 0x50, 0x5b, 0x58, 0x56, 0x5d, 0xec, 0xea, 0xe1, 0xef, ++ 0xea, 0xe4, 0xef, 0xe2, 0xe9, 0xe7, 0xe2, 0xec, 0xe6, 0xe9, 0xe8, 0xe5, ++ 0xe0, 0xe6, 0xed, 0xe1, 0xe3, 0xed, 0xe4, 0xee, 0xee, 0xe0, 0xe7, 0xeb, ++ 0xe5, 0xe3, 0xeb, 0xe8, 0xe9, 0xe4, 0xee, 0xe3, 0xef, 0xe2, 0xe5, 0xec, ++ 0xe2, 0xe9, 0xe8, 0xe5, 0xec, 0xef, 0xe3, 0xea, 0xe7, 0xeb, 0xe0, 0xee, ++ 0xe4, 0xe1, 0xea, 0xe7, 0xe1, 0xe6, 0xed, 0xe0, 0xeb, 0xe8, 0xe6, 0xed, ++ 0x3c, 0x3a, 0x31, 0x3f, 0x3a, 0x34, 0x3f, 0x32, 0x39, 0x37, 0x32, 0x3c, ++ 0x36, 0x39, 0x38, 0x35, 0x30, 0x36, 0x3d, 0x31, 0x33, 0x3d, 0x34, 0x3e, ++ 0x3e, 0x30, 0x37, 0x3b, 0x35, 0x33, 0x3b, 0x38, 0x39, 0x34, 0x3e, 0x33, ++ 0x3f, 0x32, 0x35, 0x3c, 0x32, 0x39, 0x38, 0x35, 0x3c, 0x3f, 0x33, 0x3a, ++ 0x37, 0x3b, 0x30, 0x3e, 0x34, 0x31, 0x3a, 0x37, 0x31, 0x36, 0x3d, 0x30, ++ 0x3b, 0x38, 0x36, 0x3d, ++ }, ++ { ++ 0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, 0x46, 0x4a, 0x4f, 0x43, ++ 0x4b, 0x47, 0x41, 0x44, 0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, ++ 0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, 0x47, 0x42, 0x4b, 0x41, ++ 0x44, 0x4e, 0x41, 0x47, 0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, ++ 0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, 0x4f, 0x43, 0x43, 0x45, ++ 0x45, 0x46, 0x48, 0x4b, 0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, ++ 0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, 0xda, 0xdc, 0xd9, 0xd5, ++ 0xd3, 0xd6, 0xde, 0xdb, 0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, ++ 0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, 0xd9, 0xd4, 0xdc, 0xda, ++ 0xde, 0xd8, 0xd2, 0xdd, 0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, ++ 0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, 0xbd, 0xb1, 0xb2, 0xbf, ++ 0xb8, 0xbd, 0xb4, 0xb8, 0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, ++ 0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, 0xb5, 0xb0, 0xb0, 0xbe, ++ 0xbc, 0xb9, 0xb7, 0xb2, 0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, ++ 0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, 0xb0, 0xbf, 0xb6, 0xbc, ++ 0xba, 0xb9, 0xbd, 0xb0, 0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, ++ 0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, 0x06, 0x0a, 0x0f, 0x03, ++ 0x0b, 0x07, 0x01, 0x04, 0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, ++ 0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, 0x07, 0x02, 0x0b, 0x01, ++ 0x04, 0x0e, 0x01, 0x07, 0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, ++ 0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, 0x0f, 0x03, 0x03, 0x05, ++ 0x05, 0x06, 0x08, 0x0b, 0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, ++ 0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, 0x2a, 0x2c, 0x29, 0x25, ++ 0x23, 0x26, 0x2e, 0x2b, 0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, ++ 0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, 0x29, 0x24, 0x2c, 0x2a, ++ 0x2e, 0x28, 0x22, 0x2d, 0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, ++ 0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, 0xbd, 0xb1, 0xb2, 0xbf, ++ 0xb8, 0xbd, 0xb4, 0xb8, 0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, ++ 0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, 0xb5, 0xb0, 0xb0, 0xbe, ++ 0xbc, 0xb9, 0xb7, 0xb2, 0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, ++ 0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, 0xb0, 0xbf, 0xb6, 0xbc, ++ 0xba, 0xb9, 0xbd, 0xb0, 0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, ++ 0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, 0xe6, 0xea, 0xef, 0xe3, ++ 0xeb, 0xe7, 0xe1, 0xe4, 0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, ++ 0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, 0xe7, 0xe2, 0xeb, 0xe1, ++ 0xe4, 0xee, 0xe1, 0xe7, 0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, ++ 0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, 0xef, 0xe3, 0xe3, 0xe5, ++ 0xe5, 0xe6, 0xe8, 0xeb, 0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, ++ 0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, 0x7a, 0x7c, 0x79, 0x75, ++ 0x73, 0x76, 0x7e, 0x7b, 0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, ++ 0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, 0x79, 0x74, 0x7c, 0x7a, ++ 0x7e, 0x78, 0x72, 0x7d, 0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, ++ 0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, 0xfd, 0xf1, 0xf2, 0xff, ++ 0xf8, 0xfd, 0xf4, 0xf8, 0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, ++ 0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, 0xf5, 0xf0, 0xf0, 0xfe, ++ 0xfc, 0xf9, 0xf7, 0xf2, 0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, ++ 0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, 0xf0, 0xff, 0xf6, 0xfc, ++ 0xfa, 0xf9, 0xfd, 0xf0, 0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, ++ 0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, 0x46, 0x4a, 0x4f, 0x43, ++ 0x4b, 0x47, 0x41, 0x44, 0x4a, 0x4c, 0x49, 0x45, 0x43, 0x46, 0x4e, 0x4b, ++ 0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, 0x47, 0x42, 0x4b, 0x41, ++ 0x44, 0x4e, 0x41, 0x47, 0x49, 0x44, 0x4c, 0x4a, 0x4e, 0x48, 0x42, 0x4d, ++ 0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, 0x4f, 0x43, 0x43, 0x45, ++ 0x45, 0x46, 0x48, 0x4b, 0x0d, 0x01, 0x02, 0x0f, 0x08, 0x0d, 0x04, 0x08, ++ 0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, 0x0a, 0x0c, 0x09, 0x05, ++ 0x03, 0x06, 0x0e, 0x0b, 0x05, 0x00, 0x00, 0x0e, 0x0c, 0x09, 0x07, 0x02, ++ 0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, 0x09, 0x04, 0x0c, 0x0a, ++ 0x0e, 0x08, 0x02, 0x0d, 0x00, 0x0f, 0x06, 0x0c, 0x0a, 0x09, 0x0d, 0x00, ++ 0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, 0x9d, 0x91, 0x92, 0x9f, ++ 0x98, 0x9d, 0x94, 0x98, 0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, ++ 0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, 0x95, 0x90, 0x90, 0x9e, ++ 0x9c, 0x99, 0x97, 0x92, 0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, ++ 0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, 0x90, 0x9f, 0x96, 0x9c, ++ 0x9a, 0x99, 0x9d, 0x90, 0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, ++ 0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, 0x86, 0x8a, 0x8f, 0x83, ++ 0x8b, 0x87, 0x81, 0x84, 0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, ++ 0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, 0x87, 0x82, 0x8b, 0x81, ++ 0x84, 0x8e, 0x81, 0x87, 0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, ++ 0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, 0x8f, 0x83, 0x83, 0x85, ++ 0x85, 0x86, 0x88, 0x8b, 0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, ++ 0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, 0x1a, 0x1c, 0x19, 0x15, ++ 0x13, 0x16, 0x1e, 0x1b, 0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, ++ 0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, 0x19, 0x14, 0x1c, 0x1a, ++ 0x1e, 0x18, 0x12, 0x1d, 0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, ++ 0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, 0xdd, 0xd1, 0xd2, 0xdf, ++ 0xd8, 0xdd, 0xd4, 0xd8, 0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, ++ 0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, 0xd5, 0xd0, 0xd0, 0xde, ++ 0xdc, 0xd9, 0xd7, 0xd2, 0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, ++ 0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, 0xd0, 0xdf, 0xd6, 0xdc, ++ 0xda, 0xd9, 0xdd, 0xd0, 0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, ++ 0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, 0xa6, 0xaa, 0xaf, 0xa3, ++ 0xab, 0xa7, 0xa1, 0xa4, 0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, ++ 0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, 0xa7, 0xa2, 0xab, 0xa1, ++ 0xa4, 0xae, 0xa1, 0xa7, 0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, ++ 0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, 0xaf, 0xa3, 0xa3, 0xa5, ++ 0xa5, 0xa6, 0xa8, 0xab, 0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, ++ 0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, 0x3a, 0x3c, 0x39, 0x35, ++ 0x33, 0x36, 0x3e, 0x3b, 0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, ++ 0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, 0x39, 0x34, 0x3c, 0x3a, ++ 0x3e, 0x38, 0x32, 0x3d, 0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, ++ 0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, 0xed, 0xe1, 0xe2, 0xef, ++ 0xe8, 0xed, 0xe4, 0xe8, 0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, ++ 0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, 0xe5, 0xe0, 0xe0, 0xee, ++ 0xec, 0xe9, 0xe7, 0xe2, 0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, ++ 0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, 0xe0, 0xef, 0xe6, 0xec, ++ 0xea, 0xe9, 0xed, 0xe0, 0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, ++ 0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, 0xc6, 0xca, 0xcf, 0xc3, ++ 0xcb, 0xc7, 0xc1, 0xc4, 0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, ++ 0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, 0xc7, 0xc2, 0xcb, 0xc1, ++ 0xc4, 0xce, 0xc1, 0xc7, 0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, ++ 0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, 0xcf, 0xc3, 0xc3, 0xc5, ++ 0xc5, 0xc6, 0xc8, 0xcb, 0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, ++ 0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, 0x3a, 0x3c, 0x39, 0x35, ++ 0x33, 0x36, 0x3e, 0x3b, 0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, ++ 0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, 0x39, 0x34, 0x3c, 0x3a, ++ 0x3e, 0x38, 0x32, 0x3d, 0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, ++ 0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, 0x9d, 0x91, 0x92, 0x9f, ++ 0x98, 0x9d, 0x94, 0x98, 0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, ++ 0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, 0x95, 0x90, 0x90, 0x9e, ++ 0x9c, 0x99, 0x97, 0x92, 0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, ++ 0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, 0x90, 0x9f, 0x96, 0x9c, ++ 0x9a, 0x99, 0x9d, 0x90, 0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, ++ 0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, 0x56, 0x5a, 0x5f, 0x53, ++ 0x5b, 0x57, 0x51, 0x54, 0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, ++ 0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, 0x57, 0x52, 0x5b, 0x51, ++ 0x54, 0x5e, 0x51, 0x57, 0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, ++ 0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, 0x5f, 0x53, 0x53, 0x55, ++ 0x55, 0x56, 0x58, 0x5b, 0x7d, 0x71, 0x72, 0x7f, 0x78, 0x7d, 0x74, 0x78, ++ 0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, 0x7a, 0x7c, 0x79, 0x75, ++ 0x73, 0x76, 0x7e, 0x7b, 0x75, 0x70, 0x70, 0x7e, 0x7c, 0x79, 0x77, 0x72, ++ 0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, 0x79, 0x74, 0x7c, 0x7a, ++ 0x7e, 0x78, 0x72, 0x7d, 0x70, 0x7f, 0x76, 0x7c, 0x7a, 0x79, 0x7d, 0x70, ++ 0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, 0xcd, 0xc1, 0xc2, 0xcf, ++ 0xc8, 0xcd, 0xc4, 0xc8, 0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, ++ 0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, 0xc5, 0xc0, 0xc0, 0xce, ++ 0xcc, 0xc9, 0xc7, 0xc2, 0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, ++ 0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, 0xc0, 0xcf, 0xc6, 0xcc, ++ 0xca, 0xc9, 0xcd, 0xc0, 0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, ++ 0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, 0x56, 0x5a, 0x5f, 0x53, ++ 0x5b, 0x57, 0x51, 0x54, 0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, ++ 0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, 0x57, 0x52, 0x5b, 0x51, ++ 0x54, 0x5e, 0x51, 0x57, 0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, ++ 0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, 0x5f, 0x53, 0x53, 0x55, ++ 0x55, 0x56, 0x58, 0x5b, 0x2d, 0x21, 0x22, 0x2f, 0x28, 0x2d, 0x24, 0x28, ++ 0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, 0x2a, 0x2c, 0x29, 0x25, ++ 0x23, 0x26, 0x2e, 0x2b, 0x25, 0x20, 0x20, 0x2e, 0x2c, 0x29, 0x27, 0x22, ++ 0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, 0x29, 0x24, 0x2c, 0x2a, ++ 0x2e, 0x28, 0x22, 0x2d, 0x20, 0x2f, 0x26, 0x2c, 0x2a, 0x29, 0x2d, 0x20, ++ 0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, 0xad, 0xa1, 0xa2, 0xaf, ++ 0xa8, 0xad, 0xa4, 0xa8, 0xa6, 0xaa, 0xaf, 0xa3, 0xab, 0xa7, 0xa1, 0xa4, ++ 0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, 0xa5, 0xa0, 0xa0, 0xae, ++ 0xac, 0xa9, 0xa7, 0xa2, 0xa7, 0xa2, 0xab, 0xa1, 0xa4, 0xae, 0xa1, 0xa7, ++ 0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, 0xa0, 0xaf, 0xa6, 0xac, ++ 0xaa, 0xa9, 0xad, 0xa0, 0xaf, 0xa3, 0xa3, 0xa5, 0xa5, 0xa6, 0xa8, 0xab, ++ 0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, 0xf6, 0xfa, 0xff, 0xf3, ++ 0xfb, 0xf7, 0xf1, 0xf4, 0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, ++ 0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, 0xf7, 0xf2, 0xfb, 0xf1, ++ 0xf4, 0xfe, 0xf1, 0xf7, 0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, ++ 0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, 0xff, 0xf3, 0xf3, 0xf5, ++ 0xf5, 0xf6, 0xf8, 0xfb, 0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, ++ 0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, 0x6a, 0x6c, 0x69, 0x65, ++ 0x63, 0x66, 0x6e, 0x6b, 0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, ++ 0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, 0x69, 0x64, 0x6c, 0x6a, ++ 0x6e, 0x68, 0x62, 0x6d, 0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, ++ 0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, 0x8d, 0x81, 0x82, 0x8f, ++ 0x88, 0x8d, 0x84, 0x88, 0x86, 0x8a, 0x8f, 0x83, 0x8b, 0x87, 0x81, 0x84, ++ 0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, 0x85, 0x80, 0x80, 0x8e, ++ 0x8c, 0x89, 0x87, 0x82, 0x87, 0x82, 0x8b, 0x81, 0x84, 0x8e, 0x81, 0x87, ++ 0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, 0x80, 0x8f, 0x86, 0x8c, ++ 0x8a, 0x89, 0x8d, 0x80, 0x8f, 0x83, 0x83, 0x85, 0x85, 0x86, 0x88, 0x8b, ++ 0x1d, 0x11, 0x12, 0x1f, 0x18, 0x1d, 0x14, 0x18, 0x16, 0x1a, 0x1f, 0x13, ++ 0x1b, 0x17, 0x11, 0x14, 0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, ++ 0x15, 0x10, 0x10, 0x1e, 0x1c, 0x19, 0x17, 0x12, 0x17, 0x12, 0x1b, 0x11, ++ 0x14, 0x1e, 0x11, 0x17, 0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, ++ 0x10, 0x1f, 0x16, 0x1c, 0x1a, 0x19, 0x1d, 0x10, 0x1f, 0x13, 0x13, 0x15, ++ 0x15, 0x16, 0x18, 0x1b, 0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, ++ 0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, 0x6a, 0x6c, 0x69, 0x65, ++ 0x63, 0x66, 0x6e, 0x6b, 0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, ++ 0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, 0x69, 0x64, 0x6c, 0x6a, ++ 0x6e, 0x68, 0x62, 0x6d, 0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, ++ 0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, 0x1d, 0x11, 0x12, 0x1f, ++ 0x18, 0x1d, 0x14, 0x18, 0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, ++ 0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, 0x15, 0x10, 0x10, 0x1e, ++ 0x1c, 0x19, 0x17, 0x12, 0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, ++ 0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, 0x10, 0x1f, 0x16, 0x1c, ++ 0x1a, 0x19, 0x1d, 0x10, 0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, ++ 0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, 0x66, 0x6a, 0x6f, 0x63, ++ 0x6b, 0x67, 0x61, 0x64, 0x6a, 0x6c, 0x69, 0x65, 0x63, 0x66, 0x6e, 0x6b, ++ 0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, 0x67, 0x62, 0x6b, 0x61, ++ 0x64, 0x6e, 0x61, 0x67, 0x69, 0x64, 0x6c, 0x6a, 0x6e, 0x68, 0x62, 0x6d, ++ 0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, 0x6f, 0x63, 0x63, 0x65, ++ 0x65, 0x66, 0x68, 0x6b, 0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, ++ 0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, 0x4a, 0x4c, 0x49, 0x45, ++ 0x43, 0x46, 0x4e, 0x4b, 0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, ++ 0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, 0x49, 0x44, 0x4c, 0x4a, ++ 0x4e, 0x48, 0x42, 0x4d, 0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, ++ 0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, 0xbd, 0xb1, 0xb2, 0xbf, ++ 0xb8, 0xbd, 0xb4, 0xb8, 0xb6, 0xba, 0xbf, 0xb3, 0xbb, 0xb7, 0xb1, 0xb4, ++ 0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, 0xb5, 0xb0, 0xb0, 0xbe, ++ 0xbc, 0xb9, 0xb7, 0xb2, 0xb7, 0xb2, 0xbb, 0xb1, 0xb4, 0xbe, 0xb1, 0xb7, ++ 0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, 0xb0, 0xbf, 0xb6, 0xbc, ++ 0xba, 0xb9, 0xbd, 0xb0, 0xbf, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb8, 0xbb, ++ 0xbd, 0xb1, 0xb2, 0xbf, 0xb8, 0xbd, 0xb4, 0xb8, 0xb6, 0xba, 0xbf, 0xb3, ++ 0xbb, 0xb7, 0xb1, 0xb4, 0xba, 0xbc, 0xb9, 0xb5, 0xb3, 0xb6, 0xbe, 0xbb, ++ 0xb5, 0xb0, 0xb0, 0xbe, 0xbc, 0xb9, 0xb7, 0xb2, 0xb7, 0xb2, 0xbb, 0xb1, ++ 0xb4, 0xbe, 0xb1, 0xb7, 0xb9, 0xb4, 0xbc, 0xba, 0xbe, 0xb8, 0xb2, 0xbd, ++ 0xb0, 0xbf, 0xb6, 0xbc, 0xba, 0xb9, 0xbd, 0xb0, 0xbf, 0xb3, 0xb3, 0xb5, ++ 0xb5, 0xb6, 0xb8, 0xbb, 0xdd, 0xd1, 0xd2, 0xdf, 0xd8, 0xdd, 0xd4, 0xd8, ++ 0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, 0xda, 0xdc, 0xd9, 0xd5, ++ 0xd3, 0xd6, 0xde, 0xdb, 0xd5, 0xd0, 0xd0, 0xde, 0xdc, 0xd9, 0xd7, 0xd2, ++ 0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, 0xd9, 0xd4, 0xdc, 0xda, ++ 0xde, 0xd8, 0xd2, 0xdd, 0xd0, 0xdf, 0xd6, 0xdc, 0xda, 0xd9, 0xdd, 0xd0, ++ 0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, 0xdd, 0xd1, 0xd2, 0xdf, ++ 0xd8, 0xdd, 0xd4, 0xd8, 0xd6, 0xda, 0xdf, 0xd3, 0xdb, 0xd7, 0xd1, 0xd4, ++ 0xda, 0xdc, 0xd9, 0xd5, 0xd3, 0xd6, 0xde, 0xdb, 0xd5, 0xd0, 0xd0, 0xde, ++ 0xdc, 0xd9, 0xd7, 0xd2, 0xd7, 0xd2, 0xdb, 0xd1, 0xd4, 0xde, 0xd1, 0xd7, ++ 0xd9, 0xd4, 0xdc, 0xda, 0xde, 0xd8, 0xd2, 0xdd, 0xd0, 0xdf, 0xd6, 0xdc, ++ 0xda, 0xd9, 0xdd, 0xd0, 0xdf, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd8, 0xdb, ++ 0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, 0x86, 0x8a, 0x8f, 0x83, ++ 0x8b, 0x87, 0x81, 0x84, 0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, ++ 0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, 0x87, 0x82, 0x8b, 0x81, ++ 0x84, 0x8e, 0x81, 0x87, 0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, ++ 0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, 0x8f, 0x83, 0x83, 0x85, ++ 0x85, 0x86, 0x88, 0x8b, 0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, ++ 0xc6, 0xca, 0xcf, 0xc3, 0xcb, 0xc7, 0xc1, 0xc4, 0xca, 0xcc, 0xc9, 0xc5, ++ 0xc3, 0xc6, 0xce, 0xcb, 0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, ++ 0xc7, 0xc2, 0xcb, 0xc1, 0xc4, 0xce, 0xc1, 0xc7, 0xc9, 0xc4, 0xcc, 0xca, ++ 0xce, 0xc8, 0xc2, 0xcd, 0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, ++ 0xcf, 0xc3, 0xc3, 0xc5, 0xc5, 0xc6, 0xc8, 0xcb, 0x1d, 0x11, 0x12, 0x1f, ++ 0x18, 0x1d, 0x14, 0x18, 0x16, 0x1a, 0x1f, 0x13, 0x1b, 0x17, 0x11, 0x14, ++ 0x1a, 0x1c, 0x19, 0x15, 0x13, 0x16, 0x1e, 0x1b, 0x15, 0x10, 0x10, 0x1e, ++ 0x1c, 0x19, 0x17, 0x12, 0x17, 0x12, 0x1b, 0x11, 0x14, 0x1e, 0x11, 0x17, ++ 0x19, 0x14, 0x1c, 0x1a, 0x1e, 0x18, 0x12, 0x1d, 0x10, 0x1f, 0x16, 0x1c, ++ 0x1a, 0x19, 0x1d, 0x10, 0x1f, 0x13, 0x13, 0x15, 0x15, 0x16, 0x18, 0x1b, ++ 0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, 0x36, 0x3a, 0x3f, 0x33, ++ 0x3b, 0x37, 0x31, 0x34, 0x3a, 0x3c, 0x39, 0x35, 0x33, 0x36, 0x3e, 0x3b, ++ 0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, 0x37, 0x32, 0x3b, 0x31, ++ 0x34, 0x3e, 0x31, 0x37, 0x39, 0x34, 0x3c, 0x3a, 0x3e, 0x38, 0x32, 0x3d, ++ 0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, 0x3f, 0x33, 0x33, 0x35, ++ 0x35, 0x36, 0x38, 0x3b, 0x4d, 0x41, 0x42, 0x4f, 0x48, 0x4d, 0x44, 0x48, ++ 0x46, 0x4a, 0x4f, 0x43, 0x4b, 0x47, 0x41, 0x44, 0x4a, 0x4c, 0x49, 0x45, ++ 0x43, 0x46, 0x4e, 0x4b, 0x45, 0x40, 0x40, 0x4e, 0x4c, 0x49, 0x47, 0x42, ++ 0x47, 0x42, 0x4b, 0x41, 0x44, 0x4e, 0x41, 0x47, 0x49, 0x44, 0x4c, 0x4a, ++ 0x4e, 0x48, 0x42, 0x4d, 0x40, 0x4f, 0x46, 0x4c, 0x4a, 0x49, 0x4d, 0x40, ++ 0x4f, 0x43, 0x43, 0x45, 0x45, 0x46, 0x48, 0x4b, 0x7d, 0x71, 0x72, 0x7f, ++ 0x78, 0x7d, 0x74, 0x78, 0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, ++ 0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, 0x75, 0x70, 0x70, 0x7e, ++ 0x7c, 0x79, 0x77, 0x72, 0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, ++ 0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, 0x70, 0x7f, 0x76, 0x7c, ++ 0x7a, 0x79, 0x7d, 0x70, 0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, ++ 0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, 0xa6, 0xaa, 0xaf, 0xa3, ++ 0xab, 0xa7, 0xa1, 0xa4, 0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, ++ 0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, 0xa7, 0xa2, 0xab, 0xa1, ++ 0xa4, 0xae, 0xa1, 0xa7, 0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, ++ 0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, 0xaf, 0xa3, 0xa3, 0xa5, ++ 0xa5, 0xa6, 0xa8, 0xab, 0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, ++ 0xe6, 0xea, 0xef, 0xe3, 0xeb, 0xe7, 0xe1, 0xe4, 0xea, 0xec, 0xe9, 0xe5, ++ 0xe3, 0xe6, 0xee, 0xeb, 0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, ++ 0xe7, 0xe2, 0xeb, 0xe1, 0xe4, 0xee, 0xe1, 0xe7, 0xe9, 0xe4, 0xec, 0xea, ++ 0xee, 0xe8, 0xe2, 0xed, 0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, ++ 0xef, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe8, 0xeb, 0x7d, 0x71, 0x72, 0x7f, ++ 0x78, 0x7d, 0x74, 0x78, 0x76, 0x7a, 0x7f, 0x73, 0x7b, 0x77, 0x71, 0x74, ++ 0x7a, 0x7c, 0x79, 0x75, 0x73, 0x76, 0x7e, 0x7b, 0x75, 0x70, 0x70, 0x7e, ++ 0x7c, 0x79, 0x77, 0x72, 0x77, 0x72, 0x7b, 0x71, 0x74, 0x7e, 0x71, 0x77, ++ 0x79, 0x74, 0x7c, 0x7a, 0x7e, 0x78, 0x72, 0x7d, 0x70, 0x7f, 0x76, 0x7c, ++ 0x7a, 0x79, 0x7d, 0x70, 0x7f, 0x73, 0x73, 0x75, 0x75, 0x76, 0x78, 0x7b, ++ 0xad, 0xa1, 0xa2, 0xaf, 0xa8, 0xad, 0xa4, 0xa8, 0xa6, 0xaa, 0xaf, 0xa3, ++ 0xab, 0xa7, 0xa1, 0xa4, 0xaa, 0xac, 0xa9, 0xa5, 0xa3, 0xa6, 0xae, 0xab, ++ 0xa5, 0xa0, 0xa0, 0xae, 0xac, 0xa9, 0xa7, 0xa2, 0xa7, 0xa2, 0xab, 0xa1, ++ 0xa4, 0xae, 0xa1, 0xa7, 0xa9, 0xa4, 0xac, 0xaa, 0xae, 0xa8, 0xa2, 0xad, ++ 0xa0, 0xaf, 0xa6, 0xac, 0xaa, 0xa9, 0xad, 0xa0, 0xaf, 0xa3, 0xa3, 0xa5, ++ 0xa5, 0xa6, 0xa8, 0xab, 0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, ++ 0x96, 0x9a, 0x9f, 0x93, 0x9b, 0x97, 0x91, 0x94, 0x9a, 0x9c, 0x99, 0x95, ++ 0x93, 0x96, 0x9e, 0x9b, 0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, ++ 0x97, 0x92, 0x9b, 0x91, 0x94, 0x9e, 0x91, 0x97, 0x99, 0x94, 0x9c, 0x9a, ++ 0x9e, 0x98, 0x92, 0x9d, 0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, ++ 0x9f, 0x93, 0x93, 0x95, 0x95, 0x96, 0x98, 0x9b, 0xfd, 0xf1, 0xf2, 0xff, ++ 0xf8, 0xfd, 0xf4, 0xf8, 0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, ++ 0xfa, 0xfc, 0xf9, 0xf5, 0xf3, 0xf6, 0xfe, 0xfb, 0xf5, 0xf0, 0xf0, 0xfe, ++ 0xfc, 0xf9, 0xf7, 0xf2, 0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, ++ 0xf9, 0xf4, 0xfc, 0xfa, 0xfe, 0xf8, 0xf2, 0xfd, 0xf0, 0xff, 0xf6, 0xfc, ++ 0xfa, 0xf9, 0xfd, 0xf0, 0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, ++ 0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, 0x56, 0x5a, 0x5f, 0x53, ++ 0x5b, 0x57, 0x51, 0x54, 0x5a, 0x5c, 0x59, 0x55, 0x53, 0x56, 0x5e, 0x5b, ++ 0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, 0x57, 0x52, 0x5b, 0x51, ++ 0x54, 0x5e, 0x51, 0x57, 0x59, 0x54, 0x5c, 0x5a, 0x5e, 0x58, 0x52, 0x5d, ++ 0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, 0x5f, 0x53, 0x53, 0x55, ++ 0x55, 0x56, 0x58, 0x5b, 0x6d, 0x61, 0x62, 0x6f, 0x68, 0x6d, 0x64, 0x68, ++ 0x66, 0x6a, 0x6f, 0x63, 0x6b, 0x67, 0x61, 0x64, 0x6a, 0x6c, 0x69, 0x65, ++ 0x63, 0x66, 0x6e, 0x6b, 0x65, 0x60, 0x60, 0x6e, 0x6c, 0x69, 0x67, 0x62, ++ 0x67, 0x62, 0x6b, 0x61, 0x64, 0x6e, 0x61, 0x67, 0x69, 0x64, 0x6c, 0x6a, ++ 0x6e, 0x68, 0x62, 0x6d, 0x60, 0x6f, 0x66, 0x6c, 0x6a, 0x69, 0x6d, 0x60, ++ 0x6f, 0x63, 0x63, 0x65, 0x65, 0x66, 0x68, 0x6b, 0x0d, 0x01, 0x02, 0x0f, ++ 0x08, 0x0d, 0x04, 0x08, 0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, ++ 0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, 0x05, 0x00, 0x00, 0x0e, ++ 0x0c, 0x09, 0x07, 0x02, 0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, ++ 0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, 0x00, 0x0f, 0x06, 0x0c, ++ 0x0a, 0x09, 0x0d, 0x00, 0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, ++ 0x8d, 0x81, 0x82, 0x8f, 0x88, 0x8d, 0x84, 0x88, 0x86, 0x8a, 0x8f, 0x83, ++ 0x8b, 0x87, 0x81, 0x84, 0x8a, 0x8c, 0x89, 0x85, 0x83, 0x86, 0x8e, 0x8b, ++ 0x85, 0x80, 0x80, 0x8e, 0x8c, 0x89, 0x87, 0x82, 0x87, 0x82, 0x8b, 0x81, ++ 0x84, 0x8e, 0x81, 0x87, 0x89, 0x84, 0x8c, 0x8a, 0x8e, 0x88, 0x82, 0x8d, ++ 0x80, 0x8f, 0x86, 0x8c, 0x8a, 0x89, 0x8d, 0x80, 0x8f, 0x83, 0x83, 0x85, ++ 0x85, 0x86, 0x88, 0x8b, 0xfd, 0xf1, 0xf2, 0xff, 0xf8, 0xfd, 0xf4, 0xf8, ++ 0xf6, 0xfa, 0xff, 0xf3, 0xfb, 0xf7, 0xf1, 0xf4, 0xfa, 0xfc, 0xf9, 0xf5, ++ 0xf3, 0xf6, 0xfe, 0xfb, 0xf5, 0xf0, 0xf0, 0xfe, 0xfc, 0xf9, 0xf7, 0xf2, ++ 0xf7, 0xf2, 0xfb, 0xf1, 0xf4, 0xfe, 0xf1, 0xf7, 0xf9, 0xf4, 0xfc, 0xfa, ++ 0xfe, 0xf8, 0xf2, 0xfd, 0xf0, 0xff, 0xf6, 0xfc, 0xfa, 0xf9, 0xfd, 0xf0, ++ 0xff, 0xf3, 0xf3, 0xf5, 0xf5, 0xf6, 0xf8, 0xfb, 0x0d, 0x01, 0x02, 0x0f, ++ 0x08, 0x0d, 0x04, 0x08, 0x06, 0x0a, 0x0f, 0x03, 0x0b, 0x07, 0x01, 0x04, ++ 0x0a, 0x0c, 0x09, 0x05, 0x03, 0x06, 0x0e, 0x0b, 0x05, 0x00, 0x00, 0x0e, ++ 0x0c, 0x09, 0x07, 0x02, 0x07, 0x02, 0x0b, 0x01, 0x04, 0x0e, 0x01, 0x07, ++ 0x09, 0x04, 0x0c, 0x0a, 0x0e, 0x08, 0x02, 0x0d, 0x00, 0x0f, 0x06, 0x0c, ++ 0x0a, 0x09, 0x0d, 0x00, 0x0f, 0x03, 0x03, 0x05, 0x05, 0x06, 0x08, 0x0b, ++ 0xed, 0xe1, 0xe2, 0xef, 0xe8, 0xed, 0xe4, 0xe8, 0xe6, 0xea, 0xef, 0xe3, ++ 0xeb, 0xe7, 0xe1, 0xe4, 0xea, 0xec, 0xe9, 0xe5, 0xe3, 0xe6, 0xee, 0xeb, ++ 0xe5, 0xe0, 0xe0, 0xee, 0xec, 0xe9, 0xe7, 0xe2, 0xe7, 0xe2, 0xeb, 0xe1, ++ 0xe4, 0xee, 0xe1, 0xe7, 0xe9, 0xe4, 0xec, 0xea, 0xee, 0xe8, 0xe2, 0xed, ++ 0xe0, 0xef, 0xe6, 0xec, 0xea, 0xe9, 0xed, 0xe0, 0xef, 0xe3, 0xe3, 0xe5, ++ 0xe5, 0xe6, 0xe8, 0xeb, 0x5d, 0x51, 0x52, 0x5f, 0x58, 0x5d, 0x54, 0x58, ++ 0x56, 0x5a, 0x5f, 0x53, 0x5b, 0x57, 0x51, 0x54, 0x5a, 0x5c, 0x59, 0x55, ++ 0x53, 0x56, 0x5e, 0x5b, 0x55, 0x50, 0x50, 0x5e, 0x5c, 0x59, 0x57, 0x52, ++ 0x57, 0x52, 0x5b, 0x51, 0x54, 0x5e, 0x51, 0x57, 0x59, 0x54, 0x5c, 0x5a, ++ 0x5e, 0x58, 0x52, 0x5d, 0x50, 0x5f, 0x56, 0x5c, 0x5a, 0x59, 0x5d, 0x50, ++ 0x5f, 0x53, 0x53, 0x55, 0x55, 0x56, 0x58, 0x5b, 0x2d, 0x21, 0x22, 0x2f, ++ 0x28, 0x2d, 0x24, 0x28, 0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, ++ 0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, 0x25, 0x20, 0x20, 0x2e, ++ 0x2c, 0x29, 0x27, 0x22, 0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, ++ 0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, 0x20, 0x2f, 0x26, 0x2c, ++ 0x2a, 0x29, 0x2d, 0x20, 0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, ++ 0x9d, 0x91, 0x92, 0x9f, 0x98, 0x9d, 0x94, 0x98, 0x96, 0x9a, 0x9f, 0x93, ++ 0x9b, 0x97, 0x91, 0x94, 0x9a, 0x9c, 0x99, 0x95, 0x93, 0x96, 0x9e, 0x9b, ++ 0x95, 0x90, 0x90, 0x9e, 0x9c, 0x99, 0x97, 0x92, 0x97, 0x92, 0x9b, 0x91, ++ 0x94, 0x9e, 0x91, 0x97, 0x99, 0x94, 0x9c, 0x9a, 0x9e, 0x98, 0x92, 0x9d, ++ 0x90, 0x9f, 0x96, 0x9c, 0x9a, 0x99, 0x9d, 0x90, 0x9f, 0x93, 0x93, 0x95, ++ 0x95, 0x96, 0x98, 0x9b, 0x3d, 0x31, 0x32, 0x3f, 0x38, 0x3d, 0x34, 0x38, ++ 0x36, 0x3a, 0x3f, 0x33, 0x3b, 0x37, 0x31, 0x34, 0x3a, 0x3c, 0x39, 0x35, ++ 0x33, 0x36, 0x3e, 0x3b, 0x35, 0x30, 0x30, 0x3e, 0x3c, 0x39, 0x37, 0x32, ++ 0x37, 0x32, 0x3b, 0x31, 0x34, 0x3e, 0x31, 0x37, 0x39, 0x34, 0x3c, 0x3a, ++ 0x3e, 0x38, 0x32, 0x3d, 0x30, 0x3f, 0x36, 0x3c, 0x3a, 0x39, 0x3d, 0x30, ++ 0x3f, 0x33, 0x33, 0x35, 0x35, 0x36, 0x38, 0x3b, 0x2d, 0x21, 0x22, 0x2f, ++ 0x28, 0x2d, 0x24, 0x28, 0x26, 0x2a, 0x2f, 0x23, 0x2b, 0x27, 0x21, 0x24, ++ 0x2a, 0x2c, 0x29, 0x25, 0x23, 0x26, 0x2e, 0x2b, 0x25, 0x20, 0x20, 0x2e, ++ 0x2c, 0x29, 0x27, 0x22, 0x27, 0x22, 0x2b, 0x21, 0x24, 0x2e, 0x21, 0x27, ++ 0x29, 0x24, 0x2c, 0x2a, 0x2e, 0x28, 0x22, 0x2d, 0x20, 0x2f, 0x26, 0x2c, ++ 0x2a, 0x29, 0x2d, 0x20, 0x2f, 0x23, 0x23, 0x25, 0x25, 0x26, 0x28, 0x2b, ++ 0xcd, 0xc1, 0xc2, 0xcf, 0xc8, 0xcd, 0xc4, 0xc8, 0xc6, 0xca, 0xcf, 0xc3, ++ 0xcb, 0xc7, 0xc1, 0xc4, 0xca, 0xcc, 0xc9, 0xc5, 0xc3, 0xc6, 0xce, 0xcb, ++ 0xc5, 0xc0, 0xc0, 0xce, 0xcc, 0xc9, 0xc7, 0xc2, 0xc7, 0xc2, 0xcb, 0xc1, ++ 0xc4, 0xce, 0xc1, 0xc7, 0xc9, 0xc4, 0xcc, 0xca, 0xce, 0xc8, 0xc2, 0xcd, ++ 0xc0, 0xcf, 0xc6, 0xcc, 0xca, 0xc9, 0xcd, 0xc0, 0xcf, 0xc3, 0xc3, 0xc5, ++ 0xc5, 0xc6, 0xc8, 0xcb, ++ }, ++}; ++ ++const uint32_t ip_maskl[8][256] = { ++ { ++ 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000100, 0x00000101, ++ 0x00000100, 0x00000101, 0x00000000, 0x00000001, 0x00000000, 0x00000001, ++ 0x00000100, 0x00000101, 0x00000100, 0x00000101, 0x00010000, 0x00010001, ++ 0x00010000, 0x00010001, 0x00010100, 0x00010101, 0x00010100, 0x00010101, ++ 0x00010000, 0x00010001, 0x00010000, 0x00010001, 0x00010100, 0x00010101, ++ 0x00010100, 0x00010101, 0x00000000, 0x00000001, 0x00000000, 0x00000001, ++ 0x00000100, 0x00000101, 0x00000100, 0x00000101, 0x00000000, 0x00000001, ++ 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00000100, 0x00000101, ++ 0x00010000, 0x00010001, 0x00010000, 0x00010001, 0x00010100, 0x00010101, ++ 0x00010100, 0x00010101, 0x00010000, 0x00010001, 0x00010000, 0x00010001, ++ 0x00010100, 0x00010101, 0x00010100, 0x00010101, 0x01000000, 0x01000001, ++ 0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01000100, 0x01000101, ++ 0x01000000, 0x01000001, 0x01000000, 0x01000001, 0x01000100, 0x01000101, ++ 0x01000100, 0x01000101, 0x01010000, 0x01010001, 0x01010000, 0x01010001, ++ 0x01010100, 0x01010101, 0x01010100, 0x01010101, 0x01010000, 0x01010001, ++ 0x01010000, 0x01010001, 0x01010100, 0x01010101, 0x01010100, 0x01010101, ++ 0x01000000, 0x01000001, 0x01000000, 0x01000001, 0x01000100, 0x01000101, ++ 0x01000100, 0x01000101, 0x01000000, 0x01000001, 0x01000000, 0x01000001, ++ 0x01000100, 0x01000101, 0x01000100, 0x01000101, 0x01010000, 0x01010001, ++ 0x01010000, 0x01010001, 0x01010100, 0x01010101, 0x01010100, 0x01010101, ++ 0x01010000, 0x01010001, 0x01010000, 0x01010001, 0x01010100, 0x01010101, ++ 0x01010100, 0x01010101, 0x00000000, 0x00000001, 0x00000000, 0x00000001, ++ 0x00000100, 0x00000101, 0x00000100, 0x00000101, 0x00000000, 0x00000001, ++ 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00000100, 0x00000101, ++ 0x00010000, 0x00010001, 0x00010000, 0x00010001, 0x00010100, 0x00010101, ++ 0x00010100, 0x00010101, 0x00010000, 0x00010001, 0x00010000, 0x00010001, ++ 0x00010100, 0x00010101, 0x00010100, 0x00010101, 0x00000000, 0x00000001, ++ 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00000100, 0x00000101, ++ 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000100, 0x00000101, ++ 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010000, 0x00010001, ++ 0x00010100, 0x00010101, 0x00010100, 0x00010101, 0x00010000, 0x00010001, ++ 0x00010000, 0x00010001, 0x00010100, 0x00010101, 0x00010100, 0x00010101, ++ 0x01000000, 0x01000001, 0x01000000, 0x01000001, 0x01000100, 0x01000101, ++ 0x01000100, 0x01000101, 0x01000000, 0x01000001, 0x01000000, 0x01000001, ++ 0x01000100, 0x01000101, 0x01000100, 0x01000101, 0x01010000, 0x01010001, ++ 0x01010000, 0x01010001, 0x01010100, 0x01010101, 0x01010100, 0x01010101, ++ 0x01010000, 0x01010001, 0x01010000, 0x01010001, 0x01010100, 0x01010101, ++ 0x01010100, 0x01010101, 0x01000000, 0x01000001, 0x01000000, 0x01000001, ++ 0x01000100, 0x01000101, 0x01000100, 0x01000101, 0x01000000, 0x01000001, ++ 0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01000100, 0x01000101, ++ 0x01010000, 0x01010001, 0x01010000, 0x01010001, 0x01010100, 0x01010101, ++ 0x01010100, 0x01010101, 0x01010000, 0x01010001, 0x01010000, 0x01010001, ++ 0x01010100, 0x01010101, 0x01010100, 0x01010101, ++ }, ++ { ++ 0x00000000, 0x00000002, 0x00000000, 0x00000002, 0x00000200, 0x00000202, ++ 0x00000200, 0x00000202, 0x00000000, 0x00000002, 0x00000000, 0x00000002, ++ 0x00000200, 0x00000202, 0x00000200, 0x00000202, 0x00020000, 0x00020002, ++ 0x00020000, 0x00020002, 0x00020200, 0x00020202, 0x00020200, 0x00020202, ++ 0x00020000, 0x00020002, 0x00020000, 0x00020002, 0x00020200, 0x00020202, ++ 0x00020200, 0x00020202, 0x00000000, 0x00000002, 0x00000000, 0x00000002, ++ 0x00000200, 0x00000202, 0x00000200, 0x00000202, 0x00000000, 0x00000002, ++ 0x00000000, 0x00000002, 0x00000200, 0x00000202, 0x00000200, 0x00000202, ++ 0x00020000, 0x00020002, 0x00020000, 0x00020002, 0x00020200, 0x00020202, ++ 0x00020200, 0x00020202, 0x00020000, 0x00020002, 0x00020000, 0x00020002, ++ 0x00020200, 0x00020202, 0x00020200, 0x00020202, 0x02000000, 0x02000002, ++ 0x02000000, 0x02000002, 0x02000200, 0x02000202, 0x02000200, 0x02000202, ++ 0x02000000, 0x02000002, 0x02000000, 0x02000002, 0x02000200, 0x02000202, ++ 0x02000200, 0x02000202, 0x02020000, 0x02020002, 0x02020000, 0x02020002, ++ 0x02020200, 0x02020202, 0x02020200, 0x02020202, 0x02020000, 0x02020002, ++ 0x02020000, 0x02020002, 0x02020200, 0x02020202, 0x02020200, 0x02020202, ++ 0x02000000, 0x02000002, 0x02000000, 0x02000002, 0x02000200, 0x02000202, ++ 0x02000200, 0x02000202, 0x02000000, 0x02000002, 0x02000000, 0x02000002, ++ 0x02000200, 0x02000202, 0x02000200, 0x02000202, 0x02020000, 0x02020002, ++ 0x02020000, 0x02020002, 0x02020200, 0x02020202, 0x02020200, 0x02020202, ++ 0x02020000, 0x02020002, 0x02020000, 0x02020002, 0x02020200, 0x02020202, ++ 0x02020200, 0x02020202, 0x00000000, 0x00000002, 0x00000000, 0x00000002, ++ 0x00000200, 0x00000202, 0x00000200, 0x00000202, 0x00000000, 0x00000002, ++ 0x00000000, 0x00000002, 0x00000200, 0x00000202, 0x00000200, 0x00000202, ++ 0x00020000, 0x00020002, 0x00020000, 0x00020002, 0x00020200, 0x00020202, ++ 0x00020200, 0x00020202, 0x00020000, 0x00020002, 0x00020000, 0x00020002, ++ 0x00020200, 0x00020202, 0x00020200, 0x00020202, 0x00000000, 0x00000002, ++ 0x00000000, 0x00000002, 0x00000200, 0x00000202, 0x00000200, 0x00000202, ++ 0x00000000, 0x00000002, 0x00000000, 0x00000002, 0x00000200, 0x00000202, ++ 0x00000200, 0x00000202, 0x00020000, 0x00020002, 0x00020000, 0x00020002, ++ 0x00020200, 0x00020202, 0x00020200, 0x00020202, 0x00020000, 0x00020002, ++ 0x00020000, 0x00020002, 0x00020200, 0x00020202, 0x00020200, 0x00020202, ++ 0x02000000, 0x02000002, 0x02000000, 0x02000002, 0x02000200, 0x02000202, ++ 0x02000200, 0x02000202, 0x02000000, 0x02000002, 0x02000000, 0x02000002, ++ 0x02000200, 0x02000202, 0x02000200, 0x02000202, 0x02020000, 0x02020002, ++ 0x02020000, 0x02020002, 0x02020200, 0x02020202, 0x02020200, 0x02020202, ++ 0x02020000, 0x02020002, 0x02020000, 0x02020002, 0x02020200, 0x02020202, ++ 0x02020200, 0x02020202, 0x02000000, 0x02000002, 0x02000000, 0x02000002, ++ 0x02000200, 0x02000202, 0x02000200, 0x02000202, 0x02000000, 0x02000002, ++ 0x02000000, 0x02000002, 0x02000200, 0x02000202, 0x02000200, 0x02000202, ++ 0x02020000, 0x02020002, 0x02020000, 0x02020002, 0x02020200, 0x02020202, ++ 0x02020200, 0x02020202, 0x02020000, 0x02020002, 0x02020000, 0x02020002, ++ 0x02020200, 0x02020202, 0x02020200, 0x02020202, ++ }, ++ { ++ 0x00000000, 0x00000004, 0x00000000, 0x00000004, 0x00000400, 0x00000404, ++ 0x00000400, 0x00000404, 0x00000000, 0x00000004, 0x00000000, 0x00000004, ++ 0x00000400, 0x00000404, 0x00000400, 0x00000404, 0x00040000, 0x00040004, ++ 0x00040000, 0x00040004, 0x00040400, 0x00040404, 0x00040400, 0x00040404, ++ 0x00040000, 0x00040004, 0x00040000, 0x00040004, 0x00040400, 0x00040404, ++ 0x00040400, 0x00040404, 0x00000000, 0x00000004, 0x00000000, 0x00000004, ++ 0x00000400, 0x00000404, 0x00000400, 0x00000404, 0x00000000, 0x00000004, ++ 0x00000000, 0x00000004, 0x00000400, 0x00000404, 0x00000400, 0x00000404, ++ 0x00040000, 0x00040004, 0x00040000, 0x00040004, 0x00040400, 0x00040404, ++ 0x00040400, 0x00040404, 0x00040000, 0x00040004, 0x00040000, 0x00040004, ++ 0x00040400, 0x00040404, 0x00040400, 0x00040404, 0x04000000, 0x04000004, ++ 0x04000000, 0x04000004, 0x04000400, 0x04000404, 0x04000400, 0x04000404, ++ 0x04000000, 0x04000004, 0x04000000, 0x04000004, 0x04000400, 0x04000404, ++ 0x04000400, 0x04000404, 0x04040000, 0x04040004, 0x04040000, 0x04040004, ++ 0x04040400, 0x04040404, 0x04040400, 0x04040404, 0x04040000, 0x04040004, ++ 0x04040000, 0x04040004, 0x04040400, 0x04040404, 0x04040400, 0x04040404, ++ 0x04000000, 0x04000004, 0x04000000, 0x04000004, 0x04000400, 0x04000404, ++ 0x04000400, 0x04000404, 0x04000000, 0x04000004, 0x04000000, 0x04000004, ++ 0x04000400, 0x04000404, 0x04000400, 0x04000404, 0x04040000, 0x04040004, ++ 0x04040000, 0x04040004, 0x04040400, 0x04040404, 0x04040400, 0x04040404, ++ 0x04040000, 0x04040004, 0x04040000, 0x04040004, 0x04040400, 0x04040404, ++ 0x04040400, 0x04040404, 0x00000000, 0x00000004, 0x00000000, 0x00000004, ++ 0x00000400, 0x00000404, 0x00000400, 0x00000404, 0x00000000, 0x00000004, ++ 0x00000000, 0x00000004, 0x00000400, 0x00000404, 0x00000400, 0x00000404, ++ 0x00040000, 0x00040004, 0x00040000, 0x00040004, 0x00040400, 0x00040404, ++ 0x00040400, 0x00040404, 0x00040000, 0x00040004, 0x00040000, 0x00040004, ++ 0x00040400, 0x00040404, 0x00040400, 0x00040404, 0x00000000, 0x00000004, ++ 0x00000000, 0x00000004, 0x00000400, 0x00000404, 0x00000400, 0x00000404, ++ 0x00000000, 0x00000004, 0x00000000, 0x00000004, 0x00000400, 0x00000404, ++ 0x00000400, 0x00000404, 0x00040000, 0x00040004, 0x00040000, 0x00040004, ++ 0x00040400, 0x00040404, 0x00040400, 0x00040404, 0x00040000, 0x00040004, ++ 0x00040000, 0x00040004, 0x00040400, 0x00040404, 0x00040400, 0x00040404, ++ 0x04000000, 0x04000004, 0x04000000, 0x04000004, 0x04000400, 0x04000404, ++ 0x04000400, 0x04000404, 0x04000000, 0x04000004, 0x04000000, 0x04000004, ++ 0x04000400, 0x04000404, 0x04000400, 0x04000404, 0x04040000, 0x04040004, ++ 0x04040000, 0x04040004, 0x04040400, 0x04040404, 0x04040400, 0x04040404, ++ 0x04040000, 0x04040004, 0x04040000, 0x04040004, 0x04040400, 0x04040404, ++ 0x04040400, 0x04040404, 0x04000000, 0x04000004, 0x04000000, 0x04000004, ++ 0x04000400, 0x04000404, 0x04000400, 0x04000404, 0x04000000, 0x04000004, ++ 0x04000000, 0x04000004, 0x04000400, 0x04000404, 0x04000400, 0x04000404, ++ 0x04040000, 0x04040004, 0x04040000, 0x04040004, 0x04040400, 0x04040404, ++ 0x04040400, 0x04040404, 0x04040000, 0x04040004, 0x04040000, 0x04040004, ++ 0x04040400, 0x04040404, 0x04040400, 0x04040404, ++ }, ++ { ++ 0x00000000, 0x00000008, 0x00000000, 0x00000008, 0x00000800, 0x00000808, ++ 0x00000800, 0x00000808, 0x00000000, 0x00000008, 0x00000000, 0x00000008, ++ 0x00000800, 0x00000808, 0x00000800, 0x00000808, 0x00080000, 0x00080008, ++ 0x00080000, 0x00080008, 0x00080800, 0x00080808, 0x00080800, 0x00080808, ++ 0x00080000, 0x00080008, 0x00080000, 0x00080008, 0x00080800, 0x00080808, ++ 0x00080800, 0x00080808, 0x00000000, 0x00000008, 0x00000000, 0x00000008, ++ 0x00000800, 0x00000808, 0x00000800, 0x00000808, 0x00000000, 0x00000008, ++ 0x00000000, 0x00000008, 0x00000800, 0x00000808, 0x00000800, 0x00000808, ++ 0x00080000, 0x00080008, 0x00080000, 0x00080008, 0x00080800, 0x00080808, ++ 0x00080800, 0x00080808, 0x00080000, 0x00080008, 0x00080000, 0x00080008, ++ 0x00080800, 0x00080808, 0x00080800, 0x00080808, 0x08000000, 0x08000008, ++ 0x08000000, 0x08000008, 0x08000800, 0x08000808, 0x08000800, 0x08000808, ++ 0x08000000, 0x08000008, 0x08000000, 0x08000008, 0x08000800, 0x08000808, ++ 0x08000800, 0x08000808, 0x08080000, 0x08080008, 0x08080000, 0x08080008, ++ 0x08080800, 0x08080808, 0x08080800, 0x08080808, 0x08080000, 0x08080008, ++ 0x08080000, 0x08080008, 0x08080800, 0x08080808, 0x08080800, 0x08080808, ++ 0x08000000, 0x08000008, 0x08000000, 0x08000008, 0x08000800, 0x08000808, ++ 0x08000800, 0x08000808, 0x08000000, 0x08000008, 0x08000000, 0x08000008, ++ 0x08000800, 0x08000808, 0x08000800, 0x08000808, 0x08080000, 0x08080008, ++ 0x08080000, 0x08080008, 0x08080800, 0x08080808, 0x08080800, 0x08080808, ++ 0x08080000, 0x08080008, 0x08080000, 0x08080008, 0x08080800, 0x08080808, ++ 0x08080800, 0x08080808, 0x00000000, 0x00000008, 0x00000000, 0x00000008, ++ 0x00000800, 0x00000808, 0x00000800, 0x00000808, 0x00000000, 0x00000008, ++ 0x00000000, 0x00000008, 0x00000800, 0x00000808, 0x00000800, 0x00000808, ++ 0x00080000, 0x00080008, 0x00080000, 0x00080008, 0x00080800, 0x00080808, ++ 0x00080800, 0x00080808, 0x00080000, 0x00080008, 0x00080000, 0x00080008, ++ 0x00080800, 0x00080808, 0x00080800, 0x00080808, 0x00000000, 0x00000008, ++ 0x00000000, 0x00000008, 0x00000800, 0x00000808, 0x00000800, 0x00000808, ++ 0x00000000, 0x00000008, 0x00000000, 0x00000008, 0x00000800, 0x00000808, ++ 0x00000800, 0x00000808, 0x00080000, 0x00080008, 0x00080000, 0x00080008, ++ 0x00080800, 0x00080808, 0x00080800, 0x00080808, 0x00080000, 0x00080008, ++ 0x00080000, 0x00080008, 0x00080800, 0x00080808, 0x00080800, 0x00080808, ++ 0x08000000, 0x08000008, 0x08000000, 0x08000008, 0x08000800, 0x08000808, ++ 0x08000800, 0x08000808, 0x08000000, 0x08000008, 0x08000000, 0x08000008, ++ 0x08000800, 0x08000808, 0x08000800, 0x08000808, 0x08080000, 0x08080008, ++ 0x08080000, 0x08080008, 0x08080800, 0x08080808, 0x08080800, 0x08080808, ++ 0x08080000, 0x08080008, 0x08080000, 0x08080008, 0x08080800, 0x08080808, ++ 0x08080800, 0x08080808, 0x08000000, 0x08000008, 0x08000000, 0x08000008, ++ 0x08000800, 0x08000808, 0x08000800, 0x08000808, 0x08000000, 0x08000008, ++ 0x08000000, 0x08000008, 0x08000800, 0x08000808, 0x08000800, 0x08000808, ++ 0x08080000, 0x08080008, 0x08080000, 0x08080008, 0x08080800, 0x08080808, ++ 0x08080800, 0x08080808, 0x08080000, 0x08080008, 0x08080000, 0x08080008, ++ 0x08080800, 0x08080808, 0x08080800, 0x08080808, ++ }, ++ { ++ 0x00000000, 0x00000010, 0x00000000, 0x00000010, 0x00001000, 0x00001010, ++ 0x00001000, 0x00001010, 0x00000000, 0x00000010, 0x00000000, 0x00000010, ++ 0x00001000, 0x00001010, 0x00001000, 0x00001010, 0x00100000, 0x00100010, ++ 0x00100000, 0x00100010, 0x00101000, 0x00101010, 0x00101000, 0x00101010, ++ 0x00100000, 0x00100010, 0x00100000, 0x00100010, 0x00101000, 0x00101010, ++ 0x00101000, 0x00101010, 0x00000000, 0x00000010, 0x00000000, 0x00000010, ++ 0x00001000, 0x00001010, 0x00001000, 0x00001010, 0x00000000, 0x00000010, ++ 0x00000000, 0x00000010, 0x00001000, 0x00001010, 0x00001000, 0x00001010, ++ 0x00100000, 0x00100010, 0x00100000, 0x00100010, 0x00101000, 0x00101010, ++ 0x00101000, 0x00101010, 0x00100000, 0x00100010, 0x00100000, 0x00100010, ++ 0x00101000, 0x00101010, 0x00101000, 0x00101010, 0x10000000, 0x10000010, ++ 0x10000000, 0x10000010, 0x10001000, 0x10001010, 0x10001000, 0x10001010, ++ 0x10000000, 0x10000010, 0x10000000, 0x10000010, 0x10001000, 0x10001010, ++ 0x10001000, 0x10001010, 0x10100000, 0x10100010, 0x10100000, 0x10100010, ++ 0x10101000, 0x10101010, 0x10101000, 0x10101010, 0x10100000, 0x10100010, ++ 0x10100000, 0x10100010, 0x10101000, 0x10101010, 0x10101000, 0x10101010, ++ 0x10000000, 0x10000010, 0x10000000, 0x10000010, 0x10001000, 0x10001010, ++ 0x10001000, 0x10001010, 0x10000000, 0x10000010, 0x10000000, 0x10000010, ++ 0x10001000, 0x10001010, 0x10001000, 0x10001010, 0x10100000, 0x10100010, ++ 0x10100000, 0x10100010, 0x10101000, 0x10101010, 0x10101000, 0x10101010, ++ 0x10100000, 0x10100010, 0x10100000, 0x10100010, 0x10101000, 0x10101010, ++ 0x10101000, 0x10101010, 0x00000000, 0x00000010, 0x00000000, 0x00000010, ++ 0x00001000, 0x00001010, 0x00001000, 0x00001010, 0x00000000, 0x00000010, ++ 0x00000000, 0x00000010, 0x00001000, 0x00001010, 0x00001000, 0x00001010, ++ 0x00100000, 0x00100010, 0x00100000, 0x00100010, 0x00101000, 0x00101010, ++ 0x00101000, 0x00101010, 0x00100000, 0x00100010, 0x00100000, 0x00100010, ++ 0x00101000, 0x00101010, 0x00101000, 0x00101010, 0x00000000, 0x00000010, ++ 0x00000000, 0x00000010, 0x00001000, 0x00001010, 0x00001000, 0x00001010, ++ 0x00000000, 0x00000010, 0x00000000, 0x00000010, 0x00001000, 0x00001010, ++ 0x00001000, 0x00001010, 0x00100000, 0x00100010, 0x00100000, 0x00100010, ++ 0x00101000, 0x00101010, 0x00101000, 0x00101010, 0x00100000, 0x00100010, ++ 0x00100000, 0x00100010, 0x00101000, 0x00101010, 0x00101000, 0x00101010, ++ 0x10000000, 0x10000010, 0x10000000, 0x10000010, 0x10001000, 0x10001010, ++ 0x10001000, 0x10001010, 0x10000000, 0x10000010, 0x10000000, 0x10000010, ++ 0x10001000, 0x10001010, 0x10001000, 0x10001010, 0x10100000, 0x10100010, ++ 0x10100000, 0x10100010, 0x10101000, 0x10101010, 0x10101000, 0x10101010, ++ 0x10100000, 0x10100010, 0x10100000, 0x10100010, 0x10101000, 0x10101010, ++ 0x10101000, 0x10101010, 0x10000000, 0x10000010, 0x10000000, 0x10000010, ++ 0x10001000, 0x10001010, 0x10001000, 0x10001010, 0x10000000, 0x10000010, ++ 0x10000000, 0x10000010, 0x10001000, 0x10001010, 0x10001000, 0x10001010, ++ 0x10100000, 0x10100010, 0x10100000, 0x10100010, 0x10101000, 0x10101010, ++ 0x10101000, 0x10101010, 0x10100000, 0x10100010, 0x10100000, 0x10100010, ++ 0x10101000, 0x10101010, 0x10101000, 0x10101010, ++ }, ++ { ++ 0x00000000, 0x00000020, 0x00000000, 0x00000020, 0x00002000, 0x00002020, ++ 0x00002000, 0x00002020, 0x00000000, 0x00000020, 0x00000000, 0x00000020, ++ 0x00002000, 0x00002020, 0x00002000, 0x00002020, 0x00200000, 0x00200020, ++ 0x00200000, 0x00200020, 0x00202000, 0x00202020, 0x00202000, 0x00202020, ++ 0x00200000, 0x00200020, 0x00200000, 0x00200020, 0x00202000, 0x00202020, ++ 0x00202000, 0x00202020, 0x00000000, 0x00000020, 0x00000000, 0x00000020, ++ 0x00002000, 0x00002020, 0x00002000, 0x00002020, 0x00000000, 0x00000020, ++ 0x00000000, 0x00000020, 0x00002000, 0x00002020, 0x00002000, 0x00002020, ++ 0x00200000, 0x00200020, 0x00200000, 0x00200020, 0x00202000, 0x00202020, ++ 0x00202000, 0x00202020, 0x00200000, 0x00200020, 0x00200000, 0x00200020, ++ 0x00202000, 0x00202020, 0x00202000, 0x00202020, 0x20000000, 0x20000020, ++ 0x20000000, 0x20000020, 0x20002000, 0x20002020, 0x20002000, 0x20002020, ++ 0x20000000, 0x20000020, 0x20000000, 0x20000020, 0x20002000, 0x20002020, ++ 0x20002000, 0x20002020, 0x20200000, 0x20200020, 0x20200000, 0x20200020, ++ 0x20202000, 0x20202020, 0x20202000, 0x20202020, 0x20200000, 0x20200020, ++ 0x20200000, 0x20200020, 0x20202000, 0x20202020, 0x20202000, 0x20202020, ++ 0x20000000, 0x20000020, 0x20000000, 0x20000020, 0x20002000, 0x20002020, ++ 0x20002000, 0x20002020, 0x20000000, 0x20000020, 0x20000000, 0x20000020, ++ 0x20002000, 0x20002020, 0x20002000, 0x20002020, 0x20200000, 0x20200020, ++ 0x20200000, 0x20200020, 0x20202000, 0x20202020, 0x20202000, 0x20202020, ++ 0x20200000, 0x20200020, 0x20200000, 0x20200020, 0x20202000, 0x20202020, ++ 0x20202000, 0x20202020, 0x00000000, 0x00000020, 0x00000000, 0x00000020, ++ 0x00002000, 0x00002020, 0x00002000, 0x00002020, 0x00000000, 0x00000020, ++ 0x00000000, 0x00000020, 0x00002000, 0x00002020, 0x00002000, 0x00002020, ++ 0x00200000, 0x00200020, 0x00200000, 0x00200020, 0x00202000, 0x00202020, ++ 0x00202000, 0x00202020, 0x00200000, 0x00200020, 0x00200000, 0x00200020, ++ 0x00202000, 0x00202020, 0x00202000, 0x00202020, 0x00000000, 0x00000020, ++ 0x00000000, 0x00000020, 0x00002000, 0x00002020, 0x00002000, 0x00002020, ++ 0x00000000, 0x00000020, 0x00000000, 0x00000020, 0x00002000, 0x00002020, ++ 0x00002000, 0x00002020, 0x00200000, 0x00200020, 0x00200000, 0x00200020, ++ 0x00202000, 0x00202020, 0x00202000, 0x00202020, 0x00200000, 0x00200020, ++ 0x00200000, 0x00200020, 0x00202000, 0x00202020, 0x00202000, 0x00202020, ++ 0x20000000, 0x20000020, 0x20000000, 0x20000020, 0x20002000, 0x20002020, ++ 0x20002000, 0x20002020, 0x20000000, 0x20000020, 0x20000000, 0x20000020, ++ 0x20002000, 0x20002020, 0x20002000, 0x20002020, 0x20200000, 0x20200020, ++ 0x20200000, 0x20200020, 0x20202000, 0x20202020, 0x20202000, 0x20202020, ++ 0x20200000, 0x20200020, 0x20200000, 0x20200020, 0x20202000, 0x20202020, ++ 0x20202000, 0x20202020, 0x20000000, 0x20000020, 0x20000000, 0x20000020, ++ 0x20002000, 0x20002020, 0x20002000, 0x20002020, 0x20000000, 0x20000020, ++ 0x20000000, 0x20000020, 0x20002000, 0x20002020, 0x20002000, 0x20002020, ++ 0x20200000, 0x20200020, 0x20200000, 0x20200020, 0x20202000, 0x20202020, ++ 0x20202000, 0x20202020, 0x20200000, 0x20200020, 0x20200000, 0x20200020, ++ 0x20202000, 0x20202020, 0x20202000, 0x20202020, ++ }, ++ { ++ 0x00000000, 0x00000040, 0x00000000, 0x00000040, 0x00004000, 0x00004040, ++ 0x00004000, 0x00004040, 0x00000000, 0x00000040, 0x00000000, 0x00000040, ++ 0x00004000, 0x00004040, 0x00004000, 0x00004040, 0x00400000, 0x00400040, ++ 0x00400000, 0x00400040, 0x00404000, 0x00404040, 0x00404000, 0x00404040, ++ 0x00400000, 0x00400040, 0x00400000, 0x00400040, 0x00404000, 0x00404040, ++ 0x00404000, 0x00404040, 0x00000000, 0x00000040, 0x00000000, 0x00000040, ++ 0x00004000, 0x00004040, 0x00004000, 0x00004040, 0x00000000, 0x00000040, ++ 0x00000000, 0x00000040, 0x00004000, 0x00004040, 0x00004000, 0x00004040, ++ 0x00400000, 0x00400040, 0x00400000, 0x00400040, 0x00404000, 0x00404040, ++ 0x00404000, 0x00404040, 0x00400000, 0x00400040, 0x00400000, 0x00400040, ++ 0x00404000, 0x00404040, 0x00404000, 0x00404040, 0x40000000, 0x40000040, ++ 0x40000000, 0x40000040, 0x40004000, 0x40004040, 0x40004000, 0x40004040, ++ 0x40000000, 0x40000040, 0x40000000, 0x40000040, 0x40004000, 0x40004040, ++ 0x40004000, 0x40004040, 0x40400000, 0x40400040, 0x40400000, 0x40400040, ++ 0x40404000, 0x40404040, 0x40404000, 0x40404040, 0x40400000, 0x40400040, ++ 0x40400000, 0x40400040, 0x40404000, 0x40404040, 0x40404000, 0x40404040, ++ 0x40000000, 0x40000040, 0x40000000, 0x40000040, 0x40004000, 0x40004040, ++ 0x40004000, 0x40004040, 0x40000000, 0x40000040, 0x40000000, 0x40000040, ++ 0x40004000, 0x40004040, 0x40004000, 0x40004040, 0x40400000, 0x40400040, ++ 0x40400000, 0x40400040, 0x40404000, 0x40404040, 0x40404000, 0x40404040, ++ 0x40400000, 0x40400040, 0x40400000, 0x40400040, 0x40404000, 0x40404040, ++ 0x40404000, 0x40404040, 0x00000000, 0x00000040, 0x00000000, 0x00000040, ++ 0x00004000, 0x00004040, 0x00004000, 0x00004040, 0x00000000, 0x00000040, ++ 0x00000000, 0x00000040, 0x00004000, 0x00004040, 0x00004000, 0x00004040, ++ 0x00400000, 0x00400040, 0x00400000, 0x00400040, 0x00404000, 0x00404040, ++ 0x00404000, 0x00404040, 0x00400000, 0x00400040, 0x00400000, 0x00400040, ++ 0x00404000, 0x00404040, 0x00404000, 0x00404040, 0x00000000, 0x00000040, ++ 0x00000000, 0x00000040, 0x00004000, 0x00004040, 0x00004000, 0x00004040, ++ 0x00000000, 0x00000040, 0x00000000, 0x00000040, 0x00004000, 0x00004040, ++ 0x00004000, 0x00004040, 0x00400000, 0x00400040, 0x00400000, 0x00400040, ++ 0x00404000, 0x00404040, 0x00404000, 0x00404040, 0x00400000, 0x00400040, ++ 0x00400000, 0x00400040, 0x00404000, 0x00404040, 0x00404000, 0x00404040, ++ 0x40000000, 0x40000040, 0x40000000, 0x40000040, 0x40004000, 0x40004040, ++ 0x40004000, 0x40004040, 0x40000000, 0x40000040, 0x40000000, 0x40000040, ++ 0x40004000, 0x40004040, 0x40004000, 0x40004040, 0x40400000, 0x40400040, ++ 0x40400000, 0x40400040, 0x40404000, 0x40404040, 0x40404000, 0x40404040, ++ 0x40400000, 0x40400040, 0x40400000, 0x40400040, 0x40404000, 0x40404040, ++ 0x40404000, 0x40404040, 0x40000000, 0x40000040, 0x40000000, 0x40000040, ++ 0x40004000, 0x40004040, 0x40004000, 0x40004040, 0x40000000, 0x40000040, ++ 0x40000000, 0x40000040, 0x40004000, 0x40004040, 0x40004000, 0x40004040, ++ 0x40400000, 0x40400040, 0x40400000, 0x40400040, 0x40404000, 0x40404040, ++ 0x40404000, 0x40404040, 0x40400000, 0x40400040, 0x40400000, 0x40400040, ++ 0x40404000, 0x40404040, 0x40404000, 0x40404040, ++ }, ++ { ++ 0x00000000, 0x00000080, 0x00000000, 0x00000080, 0x00008000, 0x00008080, ++ 0x00008000, 0x00008080, 0x00000000, 0x00000080, 0x00000000, 0x00000080, ++ 0x00008000, 0x00008080, 0x00008000, 0x00008080, 0x00800000, 0x00800080, ++ 0x00800000, 0x00800080, 0x00808000, 0x00808080, 0x00808000, 0x00808080, ++ 0x00800000, 0x00800080, 0x00800000, 0x00800080, 0x00808000, 0x00808080, ++ 0x00808000, 0x00808080, 0x00000000, 0x00000080, 0x00000000, 0x00000080, ++ 0x00008000, 0x00008080, 0x00008000, 0x00008080, 0x00000000, 0x00000080, ++ 0x00000000, 0x00000080, 0x00008000, 0x00008080, 0x00008000, 0x00008080, ++ 0x00800000, 0x00800080, 0x00800000, 0x00800080, 0x00808000, 0x00808080, ++ 0x00808000, 0x00808080, 0x00800000, 0x00800080, 0x00800000, 0x00800080, ++ 0x00808000, 0x00808080, 0x00808000, 0x00808080, 0x80000000, 0x80000080, ++ 0x80000000, 0x80000080, 0x80008000, 0x80008080, 0x80008000, 0x80008080, ++ 0x80000000, 0x80000080, 0x80000000, 0x80000080, 0x80008000, 0x80008080, ++ 0x80008000, 0x80008080, 0x80800000, 0x80800080, 0x80800000, 0x80800080, ++ 0x80808000, 0x80808080, 0x80808000, 0x80808080, 0x80800000, 0x80800080, ++ 0x80800000, 0x80800080, 0x80808000, 0x80808080, 0x80808000, 0x80808080, ++ 0x80000000, 0x80000080, 0x80000000, 0x80000080, 0x80008000, 0x80008080, ++ 0x80008000, 0x80008080, 0x80000000, 0x80000080, 0x80000000, 0x80000080, ++ 0x80008000, 0x80008080, 0x80008000, 0x80008080, 0x80800000, 0x80800080, ++ 0x80800000, 0x80800080, 0x80808000, 0x80808080, 0x80808000, 0x80808080, ++ 0x80800000, 0x80800080, 0x80800000, 0x80800080, 0x80808000, 0x80808080, ++ 0x80808000, 0x80808080, 0x00000000, 0x00000080, 0x00000000, 0x00000080, ++ 0x00008000, 0x00008080, 0x00008000, 0x00008080, 0x00000000, 0x00000080, ++ 0x00000000, 0x00000080, 0x00008000, 0x00008080, 0x00008000, 0x00008080, ++ 0x00800000, 0x00800080, 0x00800000, 0x00800080, 0x00808000, 0x00808080, ++ 0x00808000, 0x00808080, 0x00800000, 0x00800080, 0x00800000, 0x00800080, ++ 0x00808000, 0x00808080, 0x00808000, 0x00808080, 0x00000000, 0x00000080, ++ 0x00000000, 0x00000080, 0x00008000, 0x00008080, 0x00008000, 0x00008080, ++ 0x00000000, 0x00000080, 0x00000000, 0x00000080, 0x00008000, 0x00008080, ++ 0x00008000, 0x00008080, 0x00800000, 0x00800080, 0x00800000, 0x00800080, ++ 0x00808000, 0x00808080, 0x00808000, 0x00808080, 0x00800000, 0x00800080, ++ 0x00800000, 0x00800080, 0x00808000, 0x00808080, 0x00808000, 0x00808080, ++ 0x80000000, 0x80000080, 0x80000000, 0x80000080, 0x80008000, 0x80008080, ++ 0x80008000, 0x80008080, 0x80000000, 0x80000080, 0x80000000, 0x80000080, ++ 0x80008000, 0x80008080, 0x80008000, 0x80008080, 0x80800000, 0x80800080, ++ 0x80800000, 0x80800080, 0x80808000, 0x80808080, 0x80808000, 0x80808080, ++ 0x80800000, 0x80800080, 0x80800000, 0x80800080, 0x80808000, 0x80808080, ++ 0x80808000, 0x80808080, 0x80000000, 0x80000080, 0x80000000, 0x80000080, ++ 0x80008000, 0x80008080, 0x80008000, 0x80008080, 0x80000000, 0x80000080, ++ 0x80000000, 0x80000080, 0x80008000, 0x80008080, 0x80008000, 0x80008080, ++ 0x80800000, 0x80800080, 0x80800000, 0x80800080, 0x80808000, 0x80808080, ++ 0x80808000, 0x80808080, 0x80800000, 0x80800080, 0x80800000, 0x80800080, ++ 0x80808000, 0x80808080, 0x80808000, 0x80808080, ++ }, ++}; ++ ++const uint32_t ip_maskr[8][256] = { ++ { ++ 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000000, ++ 0x00000001, 0x00000001, 0x00000100, 0x00000100, 0x00000101, 0x00000101, ++ 0x00000100, 0x00000100, 0x00000101, 0x00000101, 0x00000000, 0x00000000, ++ 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, ++ 0x00000100, 0x00000100, 0x00000101, 0x00000101, 0x00000100, 0x00000100, ++ 0x00000101, 0x00000101, 0x00010000, 0x00010000, 0x00010001, 0x00010001, ++ 0x00010000, 0x00010000, 0x00010001, 0x00010001, 0x00010100, 0x00010100, ++ 0x00010101, 0x00010101, 0x00010100, 0x00010100, 0x00010101, 0x00010101, ++ 0x00010000, 0x00010000, 0x00010001, 0x00010001, 0x00010000, 0x00010000, ++ 0x00010001, 0x00010001, 0x00010100, 0x00010100, 0x00010101, 0x00010101, ++ 0x00010100, 0x00010100, 0x00010101, 0x00010101, 0x00000000, 0x00000000, ++ 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, ++ 0x00000100, 0x00000100, 0x00000101, 0x00000101, 0x00000100, 0x00000100, ++ 0x00000101, 0x00000101, 0x00000000, 0x00000000, 0x00000001, 0x00000001, ++ 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000100, 0x00000100, ++ 0x00000101, 0x00000101, 0x00000100, 0x00000100, 0x00000101, 0x00000101, ++ 0x00010000, 0x00010000, 0x00010001, 0x00010001, 0x00010000, 0x00010000, ++ 0x00010001, 0x00010001, 0x00010100, 0x00010100, 0x00010101, 0x00010101, ++ 0x00010100, 0x00010100, 0x00010101, 0x00010101, 0x00010000, 0x00010000, ++ 0x00010001, 0x00010001, 0x00010000, 0x00010000, 0x00010001, 0x00010001, ++ 0x00010100, 0x00010100, 0x00010101, 0x00010101, 0x00010100, 0x00010100, ++ 0x00010101, 0x00010101, 0x01000000, 0x01000000, 0x01000001, 0x01000001, ++ 0x01000000, 0x01000000, 0x01000001, 0x01000001, 0x01000100, 0x01000100, ++ 0x01000101, 0x01000101, 0x01000100, 0x01000100, 0x01000101, 0x01000101, ++ 0x01000000, 0x01000000, 0x01000001, 0x01000001, 0x01000000, 0x01000000, ++ 0x01000001, 0x01000001, 0x01000100, 0x01000100, 0x01000101, 0x01000101, ++ 0x01000100, 0x01000100, 0x01000101, 0x01000101, 0x01010000, 0x01010000, ++ 0x01010001, 0x01010001, 0x01010000, 0x01010000, 0x01010001, 0x01010001, ++ 0x01010100, 0x01010100, 0x01010101, 0x01010101, 0x01010100, 0x01010100, ++ 0x01010101, 0x01010101, 0x01010000, 0x01010000, 0x01010001, 0x01010001, ++ 0x01010000, 0x01010000, 0x01010001, 0x01010001, 0x01010100, 0x01010100, ++ 0x01010101, 0x01010101, 0x01010100, 0x01010100, 0x01010101, 0x01010101, ++ 0x01000000, 0x01000000, 0x01000001, 0x01000001, 0x01000000, 0x01000000, ++ 0x01000001, 0x01000001, 0x01000100, 0x01000100, 0x01000101, 0x01000101, ++ 0x01000100, 0x01000100, 0x01000101, 0x01000101, 0x01000000, 0x01000000, ++ 0x01000001, 0x01000001, 0x01000000, 0x01000000, 0x01000001, 0x01000001, ++ 0x01000100, 0x01000100, 0x01000101, 0x01000101, 0x01000100, 0x01000100, ++ 0x01000101, 0x01000101, 0x01010000, 0x01010000, 0x01010001, 0x01010001, ++ 0x01010000, 0x01010000, 0x01010001, 0x01010001, 0x01010100, 0x01010100, ++ 0x01010101, 0x01010101, 0x01010100, 0x01010100, 0x01010101, 0x01010101, ++ 0x01010000, 0x01010000, 0x01010001, 0x01010001, 0x01010000, 0x01010000, ++ 0x01010001, 0x01010001, 0x01010100, 0x01010100, 0x01010101, 0x01010101, ++ 0x01010100, 0x01010100, 0x01010101, 0x01010101, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000000, 0x00000000, ++ 0x00000002, 0x00000002, 0x00000200, 0x00000200, 0x00000202, 0x00000202, ++ 0x00000200, 0x00000200, 0x00000202, 0x00000202, 0x00000000, 0x00000000, ++ 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000002, ++ 0x00000200, 0x00000200, 0x00000202, 0x00000202, 0x00000200, 0x00000200, ++ 0x00000202, 0x00000202, 0x00020000, 0x00020000, 0x00020002, 0x00020002, ++ 0x00020000, 0x00020000, 0x00020002, 0x00020002, 0x00020200, 0x00020200, ++ 0x00020202, 0x00020202, 0x00020200, 0x00020200, 0x00020202, 0x00020202, ++ 0x00020000, 0x00020000, 0x00020002, 0x00020002, 0x00020000, 0x00020000, ++ 0x00020002, 0x00020002, 0x00020200, 0x00020200, 0x00020202, 0x00020202, ++ 0x00020200, 0x00020200, 0x00020202, 0x00020202, 0x00000000, 0x00000000, ++ 0x00000002, 0x00000002, 0x00000000, 0x00000000, 0x00000002, 0x00000002, ++ 0x00000200, 0x00000200, 0x00000202, 0x00000202, 0x00000200, 0x00000200, ++ 0x00000202, 0x00000202, 0x00000000, 0x00000000, 0x00000002, 0x00000002, ++ 0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000200, 0x00000200, ++ 0x00000202, 0x00000202, 0x00000200, 0x00000200, 0x00000202, 0x00000202, ++ 0x00020000, 0x00020000, 0x00020002, 0x00020002, 0x00020000, 0x00020000, ++ 0x00020002, 0x00020002, 0x00020200, 0x00020200, 0x00020202, 0x00020202, ++ 0x00020200, 0x00020200, 0x00020202, 0x00020202, 0x00020000, 0x00020000, ++ 0x00020002, 0x00020002, 0x00020000, 0x00020000, 0x00020002, 0x00020002, ++ 0x00020200, 0x00020200, 0x00020202, 0x00020202, 0x00020200, 0x00020200, ++ 0x00020202, 0x00020202, 0x02000000, 0x02000000, 0x02000002, 0x02000002, ++ 0x02000000, 0x02000000, 0x02000002, 0x02000002, 0x02000200, 0x02000200, ++ 0x02000202, 0x02000202, 0x02000200, 0x02000200, 0x02000202, 0x02000202, ++ 0x02000000, 0x02000000, 0x02000002, 0x02000002, 0x02000000, 0x02000000, ++ 0x02000002, 0x02000002, 0x02000200, 0x02000200, 0x02000202, 0x02000202, ++ 0x02000200, 0x02000200, 0x02000202, 0x02000202, 0x02020000, 0x02020000, ++ 0x02020002, 0x02020002, 0x02020000, 0x02020000, 0x02020002, 0x02020002, ++ 0x02020200, 0x02020200, 0x02020202, 0x02020202, 0x02020200, 0x02020200, ++ 0x02020202, 0x02020202, 0x02020000, 0x02020000, 0x02020002, 0x02020002, ++ 0x02020000, 0x02020000, 0x02020002, 0x02020002, 0x02020200, 0x02020200, ++ 0x02020202, 0x02020202, 0x02020200, 0x02020200, 0x02020202, 0x02020202, ++ 0x02000000, 0x02000000, 0x02000002, 0x02000002, 0x02000000, 0x02000000, ++ 0x02000002, 0x02000002, 0x02000200, 0x02000200, 0x02000202, 0x02000202, ++ 0x02000200, 0x02000200, 0x02000202, 0x02000202, 0x02000000, 0x02000000, ++ 0x02000002, 0x02000002, 0x02000000, 0x02000000, 0x02000002, 0x02000002, ++ 0x02000200, 0x02000200, 0x02000202, 0x02000202, 0x02000200, 0x02000200, ++ 0x02000202, 0x02000202, 0x02020000, 0x02020000, 0x02020002, 0x02020002, ++ 0x02020000, 0x02020000, 0x02020002, 0x02020002, 0x02020200, 0x02020200, ++ 0x02020202, 0x02020202, 0x02020200, 0x02020200, 0x02020202, 0x02020202, ++ 0x02020000, 0x02020000, 0x02020002, 0x02020002, 0x02020000, 0x02020000, ++ 0x02020002, 0x02020002, 0x02020200, 0x02020200, 0x02020202, 0x02020202, ++ 0x02020200, 0x02020200, 0x02020202, 0x02020202, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000000, 0x00000000, ++ 0x00000004, 0x00000004, 0x00000400, 0x00000400, 0x00000404, 0x00000404, ++ 0x00000400, 0x00000400, 0x00000404, 0x00000404, 0x00000000, 0x00000000, ++ 0x00000004, 0x00000004, 0x00000000, 0x00000000, 0x00000004, 0x00000004, ++ 0x00000400, 0x00000400, 0x00000404, 0x00000404, 0x00000400, 0x00000400, ++ 0x00000404, 0x00000404, 0x00040000, 0x00040000, 0x00040004, 0x00040004, ++ 0x00040000, 0x00040000, 0x00040004, 0x00040004, 0x00040400, 0x00040400, ++ 0x00040404, 0x00040404, 0x00040400, 0x00040400, 0x00040404, 0x00040404, ++ 0x00040000, 0x00040000, 0x00040004, 0x00040004, 0x00040000, 0x00040000, ++ 0x00040004, 0x00040004, 0x00040400, 0x00040400, 0x00040404, 0x00040404, ++ 0x00040400, 0x00040400, 0x00040404, 0x00040404, 0x00000000, 0x00000000, ++ 0x00000004, 0x00000004, 0x00000000, 0x00000000, 0x00000004, 0x00000004, ++ 0x00000400, 0x00000400, 0x00000404, 0x00000404, 0x00000400, 0x00000400, ++ 0x00000404, 0x00000404, 0x00000000, 0x00000000, 0x00000004, 0x00000004, ++ 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000400, 0x00000400, ++ 0x00000404, 0x00000404, 0x00000400, 0x00000400, 0x00000404, 0x00000404, ++ 0x00040000, 0x00040000, 0x00040004, 0x00040004, 0x00040000, 0x00040000, ++ 0x00040004, 0x00040004, 0x00040400, 0x00040400, 0x00040404, 0x00040404, ++ 0x00040400, 0x00040400, 0x00040404, 0x00040404, 0x00040000, 0x00040000, ++ 0x00040004, 0x00040004, 0x00040000, 0x00040000, 0x00040004, 0x00040004, ++ 0x00040400, 0x00040400, 0x00040404, 0x00040404, 0x00040400, 0x00040400, ++ 0x00040404, 0x00040404, 0x04000000, 0x04000000, 0x04000004, 0x04000004, ++ 0x04000000, 0x04000000, 0x04000004, 0x04000004, 0x04000400, 0x04000400, ++ 0x04000404, 0x04000404, 0x04000400, 0x04000400, 0x04000404, 0x04000404, ++ 0x04000000, 0x04000000, 0x04000004, 0x04000004, 0x04000000, 0x04000000, ++ 0x04000004, 0x04000004, 0x04000400, 0x04000400, 0x04000404, 0x04000404, ++ 0x04000400, 0x04000400, 0x04000404, 0x04000404, 0x04040000, 0x04040000, ++ 0x04040004, 0x04040004, 0x04040000, 0x04040000, 0x04040004, 0x04040004, ++ 0x04040400, 0x04040400, 0x04040404, 0x04040404, 0x04040400, 0x04040400, ++ 0x04040404, 0x04040404, 0x04040000, 0x04040000, 0x04040004, 0x04040004, ++ 0x04040000, 0x04040000, 0x04040004, 0x04040004, 0x04040400, 0x04040400, ++ 0x04040404, 0x04040404, 0x04040400, 0x04040400, 0x04040404, 0x04040404, ++ 0x04000000, 0x04000000, 0x04000004, 0x04000004, 0x04000000, 0x04000000, ++ 0x04000004, 0x04000004, 0x04000400, 0x04000400, 0x04000404, 0x04000404, ++ 0x04000400, 0x04000400, 0x04000404, 0x04000404, 0x04000000, 0x04000000, ++ 0x04000004, 0x04000004, 0x04000000, 0x04000000, 0x04000004, 0x04000004, ++ 0x04000400, 0x04000400, 0x04000404, 0x04000404, 0x04000400, 0x04000400, ++ 0x04000404, 0x04000404, 0x04040000, 0x04040000, 0x04040004, 0x04040004, ++ 0x04040000, 0x04040000, 0x04040004, 0x04040004, 0x04040400, 0x04040400, ++ 0x04040404, 0x04040404, 0x04040400, 0x04040400, 0x04040404, 0x04040404, ++ 0x04040000, 0x04040000, 0x04040004, 0x04040004, 0x04040000, 0x04040000, ++ 0x04040004, 0x04040004, 0x04040400, 0x04040400, 0x04040404, 0x04040404, ++ 0x04040400, 0x04040400, 0x04040404, 0x04040404, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000000, 0x00000000, ++ 0x00000008, 0x00000008, 0x00000800, 0x00000800, 0x00000808, 0x00000808, ++ 0x00000800, 0x00000800, 0x00000808, 0x00000808, 0x00000000, 0x00000000, ++ 0x00000008, 0x00000008, 0x00000000, 0x00000000, 0x00000008, 0x00000008, ++ 0x00000800, 0x00000800, 0x00000808, 0x00000808, 0x00000800, 0x00000800, ++ 0x00000808, 0x00000808, 0x00080000, 0x00080000, 0x00080008, 0x00080008, ++ 0x00080000, 0x00080000, 0x00080008, 0x00080008, 0x00080800, 0x00080800, ++ 0x00080808, 0x00080808, 0x00080800, 0x00080800, 0x00080808, 0x00080808, ++ 0x00080000, 0x00080000, 0x00080008, 0x00080008, 0x00080000, 0x00080000, ++ 0x00080008, 0x00080008, 0x00080800, 0x00080800, 0x00080808, 0x00080808, ++ 0x00080800, 0x00080800, 0x00080808, 0x00080808, 0x00000000, 0x00000000, ++ 0x00000008, 0x00000008, 0x00000000, 0x00000000, 0x00000008, 0x00000008, ++ 0x00000800, 0x00000800, 0x00000808, 0x00000808, 0x00000800, 0x00000800, ++ 0x00000808, 0x00000808, 0x00000000, 0x00000000, 0x00000008, 0x00000008, ++ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000800, 0x00000800, ++ 0x00000808, 0x00000808, 0x00000800, 0x00000800, 0x00000808, 0x00000808, ++ 0x00080000, 0x00080000, 0x00080008, 0x00080008, 0x00080000, 0x00080000, ++ 0x00080008, 0x00080008, 0x00080800, 0x00080800, 0x00080808, 0x00080808, ++ 0x00080800, 0x00080800, 0x00080808, 0x00080808, 0x00080000, 0x00080000, ++ 0x00080008, 0x00080008, 0x00080000, 0x00080000, 0x00080008, 0x00080008, ++ 0x00080800, 0x00080800, 0x00080808, 0x00080808, 0x00080800, 0x00080800, ++ 0x00080808, 0x00080808, 0x08000000, 0x08000000, 0x08000008, 0x08000008, ++ 0x08000000, 0x08000000, 0x08000008, 0x08000008, 0x08000800, 0x08000800, ++ 0x08000808, 0x08000808, 0x08000800, 0x08000800, 0x08000808, 0x08000808, ++ 0x08000000, 0x08000000, 0x08000008, 0x08000008, 0x08000000, 0x08000000, ++ 0x08000008, 0x08000008, 0x08000800, 0x08000800, 0x08000808, 0x08000808, ++ 0x08000800, 0x08000800, 0x08000808, 0x08000808, 0x08080000, 0x08080000, ++ 0x08080008, 0x08080008, 0x08080000, 0x08080000, 0x08080008, 0x08080008, ++ 0x08080800, 0x08080800, 0x08080808, 0x08080808, 0x08080800, 0x08080800, ++ 0x08080808, 0x08080808, 0x08080000, 0x08080000, 0x08080008, 0x08080008, ++ 0x08080000, 0x08080000, 0x08080008, 0x08080008, 0x08080800, 0x08080800, ++ 0x08080808, 0x08080808, 0x08080800, 0x08080800, 0x08080808, 0x08080808, ++ 0x08000000, 0x08000000, 0x08000008, 0x08000008, 0x08000000, 0x08000000, ++ 0x08000008, 0x08000008, 0x08000800, 0x08000800, 0x08000808, 0x08000808, ++ 0x08000800, 0x08000800, 0x08000808, 0x08000808, 0x08000000, 0x08000000, ++ 0x08000008, 0x08000008, 0x08000000, 0x08000000, 0x08000008, 0x08000008, ++ 0x08000800, 0x08000800, 0x08000808, 0x08000808, 0x08000800, 0x08000800, ++ 0x08000808, 0x08000808, 0x08080000, 0x08080000, 0x08080008, 0x08080008, ++ 0x08080000, 0x08080000, 0x08080008, 0x08080008, 0x08080800, 0x08080800, ++ 0x08080808, 0x08080808, 0x08080800, 0x08080800, 0x08080808, 0x08080808, ++ 0x08080000, 0x08080000, 0x08080008, 0x08080008, 0x08080000, 0x08080000, ++ 0x08080008, 0x08080008, 0x08080800, 0x08080800, 0x08080808, 0x08080808, ++ 0x08080800, 0x08080800, 0x08080808, 0x08080808, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000000, 0x00000000, ++ 0x00000010, 0x00000010, 0x00001000, 0x00001000, 0x00001010, 0x00001010, ++ 0x00001000, 0x00001000, 0x00001010, 0x00001010, 0x00000000, 0x00000000, ++ 0x00000010, 0x00000010, 0x00000000, 0x00000000, 0x00000010, 0x00000010, ++ 0x00001000, 0x00001000, 0x00001010, 0x00001010, 0x00001000, 0x00001000, ++ 0x00001010, 0x00001010, 0x00100000, 0x00100000, 0x00100010, 0x00100010, ++ 0x00100000, 0x00100000, 0x00100010, 0x00100010, 0x00101000, 0x00101000, ++ 0x00101010, 0x00101010, 0x00101000, 0x00101000, 0x00101010, 0x00101010, ++ 0x00100000, 0x00100000, 0x00100010, 0x00100010, 0x00100000, 0x00100000, ++ 0x00100010, 0x00100010, 0x00101000, 0x00101000, 0x00101010, 0x00101010, ++ 0x00101000, 0x00101000, 0x00101010, 0x00101010, 0x00000000, 0x00000000, ++ 0x00000010, 0x00000010, 0x00000000, 0x00000000, 0x00000010, 0x00000010, ++ 0x00001000, 0x00001000, 0x00001010, 0x00001010, 0x00001000, 0x00001000, ++ 0x00001010, 0x00001010, 0x00000000, 0x00000000, 0x00000010, 0x00000010, ++ 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00001000, 0x00001000, ++ 0x00001010, 0x00001010, 0x00001000, 0x00001000, 0x00001010, 0x00001010, ++ 0x00100000, 0x00100000, 0x00100010, 0x00100010, 0x00100000, 0x00100000, ++ 0x00100010, 0x00100010, 0x00101000, 0x00101000, 0x00101010, 0x00101010, ++ 0x00101000, 0x00101000, 0x00101010, 0x00101010, 0x00100000, 0x00100000, ++ 0x00100010, 0x00100010, 0x00100000, 0x00100000, 0x00100010, 0x00100010, ++ 0x00101000, 0x00101000, 0x00101010, 0x00101010, 0x00101000, 0x00101000, ++ 0x00101010, 0x00101010, 0x10000000, 0x10000000, 0x10000010, 0x10000010, ++ 0x10000000, 0x10000000, 0x10000010, 0x10000010, 0x10001000, 0x10001000, ++ 0x10001010, 0x10001010, 0x10001000, 0x10001000, 0x10001010, 0x10001010, ++ 0x10000000, 0x10000000, 0x10000010, 0x10000010, 0x10000000, 0x10000000, ++ 0x10000010, 0x10000010, 0x10001000, 0x10001000, 0x10001010, 0x10001010, ++ 0x10001000, 0x10001000, 0x10001010, 0x10001010, 0x10100000, 0x10100000, ++ 0x10100010, 0x10100010, 0x10100000, 0x10100000, 0x10100010, 0x10100010, ++ 0x10101000, 0x10101000, 0x10101010, 0x10101010, 0x10101000, 0x10101000, ++ 0x10101010, 0x10101010, 0x10100000, 0x10100000, 0x10100010, 0x10100010, ++ 0x10100000, 0x10100000, 0x10100010, 0x10100010, 0x10101000, 0x10101000, ++ 0x10101010, 0x10101010, 0x10101000, 0x10101000, 0x10101010, 0x10101010, ++ 0x10000000, 0x10000000, 0x10000010, 0x10000010, 0x10000000, 0x10000000, ++ 0x10000010, 0x10000010, 0x10001000, 0x10001000, 0x10001010, 0x10001010, ++ 0x10001000, 0x10001000, 0x10001010, 0x10001010, 0x10000000, 0x10000000, ++ 0x10000010, 0x10000010, 0x10000000, 0x10000000, 0x10000010, 0x10000010, ++ 0x10001000, 0x10001000, 0x10001010, 0x10001010, 0x10001000, 0x10001000, ++ 0x10001010, 0x10001010, 0x10100000, 0x10100000, 0x10100010, 0x10100010, ++ 0x10100000, 0x10100000, 0x10100010, 0x10100010, 0x10101000, 0x10101000, ++ 0x10101010, 0x10101010, 0x10101000, 0x10101000, 0x10101010, 0x10101010, ++ 0x10100000, 0x10100000, 0x10100010, 0x10100010, 0x10100000, 0x10100000, ++ 0x10100010, 0x10100010, 0x10101000, 0x10101000, 0x10101010, 0x10101010, ++ 0x10101000, 0x10101000, 0x10101010, 0x10101010, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000020, 0x00000020, 0x00000000, 0x00000000, ++ 0x00000020, 0x00000020, 0x00002000, 0x00002000, 0x00002020, 0x00002020, ++ 0x00002000, 0x00002000, 0x00002020, 0x00002020, 0x00000000, 0x00000000, ++ 0x00000020, 0x00000020, 0x00000000, 0x00000000, 0x00000020, 0x00000020, ++ 0x00002000, 0x00002000, 0x00002020, 0x00002020, 0x00002000, 0x00002000, ++ 0x00002020, 0x00002020, 0x00200000, 0x00200000, 0x00200020, 0x00200020, ++ 0x00200000, 0x00200000, 0x00200020, 0x00200020, 0x00202000, 0x00202000, ++ 0x00202020, 0x00202020, 0x00202000, 0x00202000, 0x00202020, 0x00202020, ++ 0x00200000, 0x00200000, 0x00200020, 0x00200020, 0x00200000, 0x00200000, ++ 0x00200020, 0x00200020, 0x00202000, 0x00202000, 0x00202020, 0x00202020, ++ 0x00202000, 0x00202000, 0x00202020, 0x00202020, 0x00000000, 0x00000000, ++ 0x00000020, 0x00000020, 0x00000000, 0x00000000, 0x00000020, 0x00000020, ++ 0x00002000, 0x00002000, 0x00002020, 0x00002020, 0x00002000, 0x00002000, ++ 0x00002020, 0x00002020, 0x00000000, 0x00000000, 0x00000020, 0x00000020, ++ 0x00000000, 0x00000000, 0x00000020, 0x00000020, 0x00002000, 0x00002000, ++ 0x00002020, 0x00002020, 0x00002000, 0x00002000, 0x00002020, 0x00002020, ++ 0x00200000, 0x00200000, 0x00200020, 0x00200020, 0x00200000, 0x00200000, ++ 0x00200020, 0x00200020, 0x00202000, 0x00202000, 0x00202020, 0x00202020, ++ 0x00202000, 0x00202000, 0x00202020, 0x00202020, 0x00200000, 0x00200000, ++ 0x00200020, 0x00200020, 0x00200000, 0x00200000, 0x00200020, 0x00200020, ++ 0x00202000, 0x00202000, 0x00202020, 0x00202020, 0x00202000, 0x00202000, ++ 0x00202020, 0x00202020, 0x20000000, 0x20000000, 0x20000020, 0x20000020, ++ 0x20000000, 0x20000000, 0x20000020, 0x20000020, 0x20002000, 0x20002000, ++ 0x20002020, 0x20002020, 0x20002000, 0x20002000, 0x20002020, 0x20002020, ++ 0x20000000, 0x20000000, 0x20000020, 0x20000020, 0x20000000, 0x20000000, ++ 0x20000020, 0x20000020, 0x20002000, 0x20002000, 0x20002020, 0x20002020, ++ 0x20002000, 0x20002000, 0x20002020, 0x20002020, 0x20200000, 0x20200000, ++ 0x20200020, 0x20200020, 0x20200000, 0x20200000, 0x20200020, 0x20200020, ++ 0x20202000, 0x20202000, 0x20202020, 0x20202020, 0x20202000, 0x20202000, ++ 0x20202020, 0x20202020, 0x20200000, 0x20200000, 0x20200020, 0x20200020, ++ 0x20200000, 0x20200000, 0x20200020, 0x20200020, 0x20202000, 0x20202000, ++ 0x20202020, 0x20202020, 0x20202000, 0x20202000, 0x20202020, 0x20202020, ++ 0x20000000, 0x20000000, 0x20000020, 0x20000020, 0x20000000, 0x20000000, ++ 0x20000020, 0x20000020, 0x20002000, 0x20002000, 0x20002020, 0x20002020, ++ 0x20002000, 0x20002000, 0x20002020, 0x20002020, 0x20000000, 0x20000000, ++ 0x20000020, 0x20000020, 0x20000000, 0x20000000, 0x20000020, 0x20000020, ++ 0x20002000, 0x20002000, 0x20002020, 0x20002020, 0x20002000, 0x20002000, ++ 0x20002020, 0x20002020, 0x20200000, 0x20200000, 0x20200020, 0x20200020, ++ 0x20200000, 0x20200000, 0x20200020, 0x20200020, 0x20202000, 0x20202000, ++ 0x20202020, 0x20202020, 0x20202000, 0x20202000, 0x20202020, 0x20202020, ++ 0x20200000, 0x20200000, 0x20200020, 0x20200020, 0x20200000, 0x20200000, ++ 0x20200020, 0x20200020, 0x20202000, 0x20202000, 0x20202020, 0x20202020, ++ 0x20202000, 0x20202000, 0x20202020, 0x20202020, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000040, 0x00000040, 0x00000000, 0x00000000, ++ 0x00000040, 0x00000040, 0x00004000, 0x00004000, 0x00004040, 0x00004040, ++ 0x00004000, 0x00004000, 0x00004040, 0x00004040, 0x00000000, 0x00000000, ++ 0x00000040, 0x00000040, 0x00000000, 0x00000000, 0x00000040, 0x00000040, ++ 0x00004000, 0x00004000, 0x00004040, 0x00004040, 0x00004000, 0x00004000, ++ 0x00004040, 0x00004040, 0x00400000, 0x00400000, 0x00400040, 0x00400040, ++ 0x00400000, 0x00400000, 0x00400040, 0x00400040, 0x00404000, 0x00404000, ++ 0x00404040, 0x00404040, 0x00404000, 0x00404000, 0x00404040, 0x00404040, ++ 0x00400000, 0x00400000, 0x00400040, 0x00400040, 0x00400000, 0x00400000, ++ 0x00400040, 0x00400040, 0x00404000, 0x00404000, 0x00404040, 0x00404040, ++ 0x00404000, 0x00404000, 0x00404040, 0x00404040, 0x00000000, 0x00000000, ++ 0x00000040, 0x00000040, 0x00000000, 0x00000000, 0x00000040, 0x00000040, ++ 0x00004000, 0x00004000, 0x00004040, 0x00004040, 0x00004000, 0x00004000, ++ 0x00004040, 0x00004040, 0x00000000, 0x00000000, 0x00000040, 0x00000040, ++ 0x00000000, 0x00000000, 0x00000040, 0x00000040, 0x00004000, 0x00004000, ++ 0x00004040, 0x00004040, 0x00004000, 0x00004000, 0x00004040, 0x00004040, ++ 0x00400000, 0x00400000, 0x00400040, 0x00400040, 0x00400000, 0x00400000, ++ 0x00400040, 0x00400040, 0x00404000, 0x00404000, 0x00404040, 0x00404040, ++ 0x00404000, 0x00404000, 0x00404040, 0x00404040, 0x00400000, 0x00400000, ++ 0x00400040, 0x00400040, 0x00400000, 0x00400000, 0x00400040, 0x00400040, ++ 0x00404000, 0x00404000, 0x00404040, 0x00404040, 0x00404000, 0x00404000, ++ 0x00404040, 0x00404040, 0x40000000, 0x40000000, 0x40000040, 0x40000040, ++ 0x40000000, 0x40000000, 0x40000040, 0x40000040, 0x40004000, 0x40004000, ++ 0x40004040, 0x40004040, 0x40004000, 0x40004000, 0x40004040, 0x40004040, ++ 0x40000000, 0x40000000, 0x40000040, 0x40000040, 0x40000000, 0x40000000, ++ 0x40000040, 0x40000040, 0x40004000, 0x40004000, 0x40004040, 0x40004040, ++ 0x40004000, 0x40004000, 0x40004040, 0x40004040, 0x40400000, 0x40400000, ++ 0x40400040, 0x40400040, 0x40400000, 0x40400000, 0x40400040, 0x40400040, ++ 0x40404000, 0x40404000, 0x40404040, 0x40404040, 0x40404000, 0x40404000, ++ 0x40404040, 0x40404040, 0x40400000, 0x40400000, 0x40400040, 0x40400040, ++ 0x40400000, 0x40400000, 0x40400040, 0x40400040, 0x40404000, 0x40404000, ++ 0x40404040, 0x40404040, 0x40404000, 0x40404000, 0x40404040, 0x40404040, ++ 0x40000000, 0x40000000, 0x40000040, 0x40000040, 0x40000000, 0x40000000, ++ 0x40000040, 0x40000040, 0x40004000, 0x40004000, 0x40004040, 0x40004040, ++ 0x40004000, 0x40004000, 0x40004040, 0x40004040, 0x40000000, 0x40000000, ++ 0x40000040, 0x40000040, 0x40000000, 0x40000000, 0x40000040, 0x40000040, ++ 0x40004000, 0x40004000, 0x40004040, 0x40004040, 0x40004000, 0x40004000, ++ 0x40004040, 0x40004040, 0x40400000, 0x40400000, 0x40400040, 0x40400040, ++ 0x40400000, 0x40400000, 0x40400040, 0x40400040, 0x40404000, 0x40404000, ++ 0x40404040, 0x40404040, 0x40404000, 0x40404000, 0x40404040, 0x40404040, ++ 0x40400000, 0x40400000, 0x40400040, 0x40400040, 0x40400000, 0x40400000, ++ 0x40400040, 0x40400040, 0x40404000, 0x40404000, 0x40404040, 0x40404040, ++ 0x40404000, 0x40404000, 0x40404040, 0x40404040, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000080, 0x00000080, 0x00000000, 0x00000000, ++ 0x00000080, 0x00000080, 0x00008000, 0x00008000, 0x00008080, 0x00008080, ++ 0x00008000, 0x00008000, 0x00008080, 0x00008080, 0x00000000, 0x00000000, ++ 0x00000080, 0x00000080, 0x00000000, 0x00000000, 0x00000080, 0x00000080, ++ 0x00008000, 0x00008000, 0x00008080, 0x00008080, 0x00008000, 0x00008000, ++ 0x00008080, 0x00008080, 0x00800000, 0x00800000, 0x00800080, 0x00800080, ++ 0x00800000, 0x00800000, 0x00800080, 0x00800080, 0x00808000, 0x00808000, ++ 0x00808080, 0x00808080, 0x00808000, 0x00808000, 0x00808080, 0x00808080, ++ 0x00800000, 0x00800000, 0x00800080, 0x00800080, 0x00800000, 0x00800000, ++ 0x00800080, 0x00800080, 0x00808000, 0x00808000, 0x00808080, 0x00808080, ++ 0x00808000, 0x00808000, 0x00808080, 0x00808080, 0x00000000, 0x00000000, ++ 0x00000080, 0x00000080, 0x00000000, 0x00000000, 0x00000080, 0x00000080, ++ 0x00008000, 0x00008000, 0x00008080, 0x00008080, 0x00008000, 0x00008000, ++ 0x00008080, 0x00008080, 0x00000000, 0x00000000, 0x00000080, 0x00000080, ++ 0x00000000, 0x00000000, 0x00000080, 0x00000080, 0x00008000, 0x00008000, ++ 0x00008080, 0x00008080, 0x00008000, 0x00008000, 0x00008080, 0x00008080, ++ 0x00800000, 0x00800000, 0x00800080, 0x00800080, 0x00800000, 0x00800000, ++ 0x00800080, 0x00800080, 0x00808000, 0x00808000, 0x00808080, 0x00808080, ++ 0x00808000, 0x00808000, 0x00808080, 0x00808080, 0x00800000, 0x00800000, ++ 0x00800080, 0x00800080, 0x00800000, 0x00800000, 0x00800080, 0x00800080, ++ 0x00808000, 0x00808000, 0x00808080, 0x00808080, 0x00808000, 0x00808000, ++ 0x00808080, 0x00808080, 0x80000000, 0x80000000, 0x80000080, 0x80000080, ++ 0x80000000, 0x80000000, 0x80000080, 0x80000080, 0x80008000, 0x80008000, ++ 0x80008080, 0x80008080, 0x80008000, 0x80008000, 0x80008080, 0x80008080, ++ 0x80000000, 0x80000000, 0x80000080, 0x80000080, 0x80000000, 0x80000000, ++ 0x80000080, 0x80000080, 0x80008000, 0x80008000, 0x80008080, 0x80008080, ++ 0x80008000, 0x80008000, 0x80008080, 0x80008080, 0x80800000, 0x80800000, ++ 0x80800080, 0x80800080, 0x80800000, 0x80800000, 0x80800080, 0x80800080, ++ 0x80808000, 0x80808000, 0x80808080, 0x80808080, 0x80808000, 0x80808000, ++ 0x80808080, 0x80808080, 0x80800000, 0x80800000, 0x80800080, 0x80800080, ++ 0x80800000, 0x80800000, 0x80800080, 0x80800080, 0x80808000, 0x80808000, ++ 0x80808080, 0x80808080, 0x80808000, 0x80808000, 0x80808080, 0x80808080, ++ 0x80000000, 0x80000000, 0x80000080, 0x80000080, 0x80000000, 0x80000000, ++ 0x80000080, 0x80000080, 0x80008000, 0x80008000, 0x80008080, 0x80008080, ++ 0x80008000, 0x80008000, 0x80008080, 0x80008080, 0x80000000, 0x80000000, ++ 0x80000080, 0x80000080, 0x80000000, 0x80000000, 0x80000080, 0x80000080, ++ 0x80008000, 0x80008000, 0x80008080, 0x80008080, 0x80008000, 0x80008000, ++ 0x80008080, 0x80008080, 0x80800000, 0x80800000, 0x80800080, 0x80800080, ++ 0x80800000, 0x80800000, 0x80800080, 0x80800080, 0x80808000, 0x80808000, ++ 0x80808080, 0x80808080, 0x80808000, 0x80808000, 0x80808080, 0x80808080, ++ 0x80800000, 0x80800000, 0x80800080, 0x80800080, 0x80800000, 0x80800000, ++ 0x80800080, 0x80800080, 0x80808000, 0x80808000, 0x80808080, 0x80808080, ++ 0x80808000, 0x80808000, 0x80808080, 0x80808080, ++ }, ++}; ++ ++const uint32_t fp_maskl[8][256] = { ++ { ++ 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, ++ 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, ++ 0x00004040, 0x40004040, 0x00404040, 0x40404040, 0x00000000, 0x40000000, ++ 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, ++ 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, ++ 0x00404040, 0x40404040, 0x00000000, 0x40000000, 0x00400000, 0x40400000, ++ 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, ++ 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, ++ 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, ++ 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, ++ 0x00004040, 0x40004040, 0x00404040, 0x40404040, 0x00000000, 0x40000000, ++ 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, ++ 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, ++ 0x00404040, 0x40404040, 0x00000000, 0x40000000, 0x00400000, 0x40400000, ++ 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, ++ 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, ++ 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, ++ 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, ++ 0x00004040, 0x40004040, 0x00404040, 0x40404040, 0x00000000, 0x40000000, ++ 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, ++ 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, ++ 0x00404040, 0x40404040, 0x00000000, 0x40000000, 0x00400000, 0x40400000, ++ 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, ++ 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, ++ 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, ++ 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, ++ 0x00004040, 0x40004040, 0x00404040, 0x40404040, 0x00000000, 0x40000000, ++ 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, ++ 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, ++ 0x00404040, 0x40404040, 0x00000000, 0x40000000, 0x00400000, 0x40400000, ++ 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, ++ 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, ++ 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, ++ 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, ++ 0x00004040, 0x40004040, 0x00404040, 0x40404040, 0x00000000, 0x40000000, ++ 0x00400000, 0x40400000, 0x00004000, 0x40004000, 0x00404000, 0x40404000, ++ 0x00000040, 0x40000040, 0x00400040, 0x40400040, 0x00004040, 0x40004040, ++ 0x00404040, 0x40404040, 0x00000000, 0x40000000, 0x00400000, 0x40400000, ++ 0x00004000, 0x40004000, 0x00404000, 0x40404000, 0x00000040, 0x40000040, ++ 0x00400040, 0x40400040, 0x00004040, 0x40004040, 0x00404040, 0x40404040, ++ 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, 0x10000000, ++ 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, ++ 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, ++ 0x00101010, 0x10101010, 0x00000000, 0x10000000, 0x00100000, 0x10100000, ++ 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, ++ 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, ++ 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, ++ 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, ++ 0x00001010, 0x10001010, 0x00101010, 0x10101010, 0x00000000, 0x10000000, ++ 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, ++ 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, ++ 0x00101010, 0x10101010, 0x00000000, 0x10000000, 0x00100000, 0x10100000, ++ 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, ++ 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, ++ 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, ++ 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, ++ 0x00001010, 0x10001010, 0x00101010, 0x10101010, 0x00000000, 0x10000000, ++ 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, ++ 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, ++ 0x00101010, 0x10101010, 0x00000000, 0x10000000, 0x00100000, 0x10100000, ++ 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, ++ 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, ++ 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, ++ 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, ++ 0x00001010, 0x10001010, 0x00101010, 0x10101010, 0x00000000, 0x10000000, ++ 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, ++ 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, ++ 0x00101010, 0x10101010, 0x00000000, 0x10000000, 0x00100000, 0x10100000, ++ 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, ++ 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, ++ 0x00000000, 0x10000000, 0x00100000, 0x10100000, 0x00001000, 0x10001000, ++ 0x00101000, 0x10101000, 0x00000010, 0x10000010, 0x00100010, 0x10100010, ++ 0x00001010, 0x10001010, 0x00101010, 0x10101010, 0x00000000, 0x10000000, ++ 0x00100000, 0x10100000, 0x00001000, 0x10001000, 0x00101000, 0x10101000, ++ 0x00000010, 0x10000010, 0x00100010, 0x10100010, 0x00001010, 0x10001010, ++ 0x00101010, 0x10101010, 0x00000000, 0x10000000, 0x00100000, 0x10100000, ++ 0x00001000, 0x10001000, 0x00101000, 0x10101000, 0x00000010, 0x10000010, ++ 0x00100010, 0x10100010, 0x00001010, 0x10001010, 0x00101010, 0x10101010, ++ 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, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, ++ 0x00040404, 0x04040404, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, ++ 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, ++ 0x00000404, 0x04000404, 0x00040404, 0x04040404, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, ++ 0x00040404, 0x04040404, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, ++ 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, ++ 0x00000404, 0x04000404, 0x00040404, 0x04040404, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, ++ 0x00040404, 0x04040404, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, ++ 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, ++ 0x00000404, 0x04000404, 0x00040404, 0x04040404, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, ++ 0x00040404, 0x04040404, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, ++ 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000004, 0x04000004, 0x00040004, 0x04040004, ++ 0x00000404, 0x04000404, 0x00040404, 0x04040404, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000004, 0x04000004, 0x00040004, 0x04040004, 0x00000404, 0x04000404, ++ 0x00040404, 0x04040404, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000004, 0x04000004, ++ 0x00040004, 0x04040004, 0x00000404, 0x04000404, 0x00040404, 0x04040404, ++ 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, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, ++ 0x00010101, 0x01010101, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, ++ 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, ++ 0x00000101, 0x01000101, 0x00010101, 0x01010101, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, ++ 0x00010101, 0x01010101, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, ++ 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, ++ 0x00000101, 0x01000101, 0x00010101, 0x01010101, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, ++ 0x00010101, 0x01010101, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, ++ 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, ++ 0x00000101, 0x01000101, 0x00010101, 0x01010101, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, ++ 0x00010101, 0x01010101, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, ++ 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, ++ 0x00000101, 0x01000101, 0x00010101, 0x01010101, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, ++ 0x00010101, 0x01010101, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, ++ 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, ++ 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, 0x80000000, ++ 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, ++ 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, ++ 0x00808080, 0x80808080, 0x00000000, 0x80000000, 0x00800000, 0x80800000, ++ 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, ++ 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, ++ 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, ++ 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, ++ 0x00008080, 0x80008080, 0x00808080, 0x80808080, 0x00000000, 0x80000000, ++ 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, ++ 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, ++ 0x00808080, 0x80808080, 0x00000000, 0x80000000, 0x00800000, 0x80800000, ++ 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, ++ 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, ++ 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, ++ 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, ++ 0x00008080, 0x80008080, 0x00808080, 0x80808080, 0x00000000, 0x80000000, ++ 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, ++ 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, ++ 0x00808080, 0x80808080, 0x00000000, 0x80000000, 0x00800000, 0x80800000, ++ 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, ++ 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, ++ 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, ++ 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, ++ 0x00008080, 0x80008080, 0x00808080, 0x80808080, 0x00000000, 0x80000000, ++ 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, ++ 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, ++ 0x00808080, 0x80808080, 0x00000000, 0x80000000, 0x00800000, 0x80800000, ++ 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, ++ 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, ++ 0x00000000, 0x80000000, 0x00800000, 0x80800000, 0x00008000, 0x80008000, ++ 0x00808000, 0x80808000, 0x00000080, 0x80000080, 0x00800080, 0x80800080, ++ 0x00008080, 0x80008080, 0x00808080, 0x80808080, 0x00000000, 0x80000000, ++ 0x00800000, 0x80800000, 0x00008000, 0x80008000, 0x00808000, 0x80808000, ++ 0x00000080, 0x80000080, 0x00800080, 0x80800080, 0x00008080, 0x80008080, ++ 0x00808080, 0x80808080, 0x00000000, 0x80000000, 0x00800000, 0x80800000, ++ 0x00008000, 0x80008000, 0x00808000, 0x80808000, 0x00000080, 0x80000080, ++ 0x00800080, 0x80800080, 0x00008080, 0x80008080, 0x00808080, 0x80808080, ++ 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, 0x20000000, ++ 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, ++ 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, ++ 0x00202020, 0x20202020, 0x00000000, 0x20000000, 0x00200000, 0x20200000, ++ 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, ++ 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, ++ 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, ++ 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, ++ 0x00002020, 0x20002020, 0x00202020, 0x20202020, 0x00000000, 0x20000000, ++ 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, ++ 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, ++ 0x00202020, 0x20202020, 0x00000000, 0x20000000, 0x00200000, 0x20200000, ++ 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, ++ 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, ++ 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, ++ 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, ++ 0x00002020, 0x20002020, 0x00202020, 0x20202020, 0x00000000, 0x20000000, ++ 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, ++ 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, ++ 0x00202020, 0x20202020, 0x00000000, 0x20000000, 0x00200000, 0x20200000, ++ 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, ++ 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, ++ 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, ++ 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, ++ 0x00002020, 0x20002020, 0x00202020, 0x20202020, 0x00000000, 0x20000000, ++ 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, ++ 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, ++ 0x00202020, 0x20202020, 0x00000000, 0x20000000, 0x00200000, 0x20200000, ++ 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, ++ 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, ++ 0x00000000, 0x20000000, 0x00200000, 0x20200000, 0x00002000, 0x20002000, ++ 0x00202000, 0x20202000, 0x00000020, 0x20000020, 0x00200020, 0x20200020, ++ 0x00002020, 0x20002020, 0x00202020, 0x20202020, 0x00000000, 0x20000000, ++ 0x00200000, 0x20200000, 0x00002000, 0x20002000, 0x00202000, 0x20202000, ++ 0x00000020, 0x20000020, 0x00200020, 0x20200020, 0x00002020, 0x20002020, ++ 0x00202020, 0x20202020, 0x00000000, 0x20000000, 0x00200000, 0x20200000, ++ 0x00002000, 0x20002000, 0x00202000, 0x20202000, 0x00000020, 0x20000020, ++ 0x00200020, 0x20200020, 0x00002020, 0x20002020, 0x00202020, 0x20202020, ++ 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, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, ++ 0x00080808, 0x08080808, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, ++ 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, ++ 0x00000808, 0x08000808, 0x00080808, 0x08080808, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, ++ 0x00080808, 0x08080808, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, ++ 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, ++ 0x00000808, 0x08000808, 0x00080808, 0x08080808, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, ++ 0x00080808, 0x08080808, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, ++ 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, ++ 0x00000808, 0x08000808, 0x00080808, 0x08080808, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, ++ 0x00080808, 0x08080808, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, ++ 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000008, 0x08000008, 0x00080008, 0x08080008, ++ 0x00000808, 0x08000808, 0x00080808, 0x08080808, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000008, 0x08000008, 0x00080008, 0x08080008, 0x00000808, 0x08000808, ++ 0x00080808, 0x08080808, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000008, 0x08000008, ++ 0x00080008, 0x08080008, 0x00000808, 0x08000808, 0x00080808, 0x08080808, ++ 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, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, ++ 0x00020202, 0x02020202, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, ++ 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, ++ 0x00000202, 0x02000202, 0x00020202, 0x02020202, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, ++ 0x00020202, 0x02020202, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, ++ 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, ++ 0x00000202, 0x02000202, 0x00020202, 0x02020202, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, ++ 0x00020202, 0x02020202, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, ++ 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, ++ 0x00000202, 0x02000202, 0x00020202, 0x02020202, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, ++ 0x00020202, 0x02020202, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, ++ 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, ++ 0x00000202, 0x02000202, 0x00020202, 0x02020202, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202, 0x02000202, ++ 0x00020202, 0x02020202, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000002, 0x02000002, ++ 0x00020002, 0x02020002, 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, ++ 0x00000202, 0x02000202, 0x00020202, 0x02020202, ++ }, ++}; ++ ++const uint32_t fp_maskr[8][256] = { ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x40000000, 0x40000000, ++ 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, ++ 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, ++ 0x40000000, 0x40000000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, ++ 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, ++ 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, ++ 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000, ++ 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000, ++ 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x00004000, 0x00004000, ++ 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, ++ 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, ++ 0x00004000, 0x00004000, 0x40004000, 0x40004000, 0x40004000, 0x40004000, ++ 0x40004000, 0x40004000, 0x40004000, 0x40004000, 0x40004000, 0x40004000, ++ 0x40004000, 0x40004000, 0x40004000, 0x40004000, 0x40004000, 0x40004000, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x40404000, 0x40404000, ++ 0x40404000, 0x40404000, 0x40404000, 0x40404000, 0x40404000, 0x40404000, ++ 0x40404000, 0x40404000, 0x40404000, 0x40404000, 0x40404000, 0x40404000, ++ 0x40404000, 0x40404000, 0x00000040, 0x00000040, 0x00000040, 0x00000040, ++ 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, ++ 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, ++ 0x40000040, 0x40000040, 0x40000040, 0x40000040, 0x40000040, 0x40000040, ++ 0x40000040, 0x40000040, 0x40000040, 0x40000040, 0x40000040, 0x40000040, ++ 0x40000040, 0x40000040, 0x40000040, 0x40000040, 0x00400040, 0x00400040, ++ 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, ++ 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, ++ 0x00400040, 0x00400040, 0x40400040, 0x40400040, 0x40400040, 0x40400040, ++ 0x40400040, 0x40400040, 0x40400040, 0x40400040, 0x40400040, 0x40400040, ++ 0x40400040, 0x40400040, 0x40400040, 0x40400040, 0x40400040, 0x40400040, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x40004040, 0x40004040, ++ 0x40004040, 0x40004040, 0x40004040, 0x40004040, 0x40004040, 0x40004040, ++ 0x40004040, 0x40004040, 0x40004040, 0x40004040, 0x40004040, 0x40004040, ++ 0x40004040, 0x40004040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, ++ 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, ++ 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, ++ 0x40404040, 0x40404040, 0x40404040, 0x40404040, 0x40404040, 0x40404040, ++ 0x40404040, 0x40404040, 0x40404040, 0x40404040, 0x40404040, 0x40404040, ++ 0x40404040, 0x40404040, 0x40404040, 0x40404040, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x10000000, ++ 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000, ++ 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000, ++ 0x10000000, 0x10000000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, ++ 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, ++ 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, ++ 0x10100000, 0x10100000, 0x10100000, 0x10100000, 0x10100000, 0x10100000, ++ 0x10100000, 0x10100000, 0x10100000, 0x10100000, 0x10100000, 0x10100000, ++ 0x10100000, 0x10100000, 0x10100000, 0x10100000, 0x00001000, 0x00001000, ++ 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, ++ 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, ++ 0x00001000, 0x00001000, 0x10001000, 0x10001000, 0x10001000, 0x10001000, ++ 0x10001000, 0x10001000, 0x10001000, 0x10001000, 0x10001000, 0x10001000, ++ 0x10001000, 0x10001000, 0x10001000, 0x10001000, 0x10001000, 0x10001000, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x10101000, 0x10101000, ++ 0x10101000, 0x10101000, 0x10101000, 0x10101000, 0x10101000, 0x10101000, ++ 0x10101000, 0x10101000, 0x10101000, 0x10101000, 0x10101000, 0x10101000, ++ 0x10101000, 0x10101000, 0x00000010, 0x00000010, 0x00000010, 0x00000010, ++ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, ++ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, ++ 0x10000010, 0x10000010, 0x10000010, 0x10000010, 0x10000010, 0x10000010, ++ 0x10000010, 0x10000010, 0x10000010, 0x10000010, 0x10000010, 0x10000010, ++ 0x10000010, 0x10000010, 0x10000010, 0x10000010, 0x00100010, 0x00100010, ++ 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, ++ 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, ++ 0x00100010, 0x00100010, 0x10100010, 0x10100010, 0x10100010, 0x10100010, ++ 0x10100010, 0x10100010, 0x10100010, 0x10100010, 0x10100010, 0x10100010, ++ 0x10100010, 0x10100010, 0x10100010, 0x10100010, 0x10100010, 0x10100010, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x10001010, 0x10001010, ++ 0x10001010, 0x10001010, 0x10001010, 0x10001010, 0x10001010, 0x10001010, ++ 0x10001010, 0x10001010, 0x10001010, 0x10001010, 0x10001010, 0x10001010, ++ 0x10001010, 0x10001010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, ++ 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, ++ 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, ++ 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, ++ 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, ++ 0x10101010, 0x10101010, 0x10101010, 0x10101010, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000000, 0x04000000, ++ 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, ++ 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, ++ 0x04000000, 0x04000000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, ++ 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, ++ 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040000, ++ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, ++ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, ++ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x00000400, 0x00000400, ++ 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, ++ 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, ++ 0x00000400, 0x00000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400, ++ 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400, ++ 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000400, ++ 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, ++ 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, ++ 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x04040400, 0x04040400, ++ 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, ++ 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, ++ 0x04040400, 0x04040400, 0x00000004, 0x00000004, 0x00000004, 0x00000004, ++ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, ++ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, ++ 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, ++ 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, ++ 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x00040004, 0x00040004, ++ 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, ++ 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, ++ 0x00040004, 0x00040004, 0x04040004, 0x04040004, 0x04040004, 0x04040004, ++ 0x04040004, 0x04040004, 0x04040004, 0x04040004, 0x04040004, 0x04040004, ++ 0x04040004, 0x04040004, 0x04040004, 0x04040004, 0x04040004, 0x04040004, ++ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, ++ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, ++ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x04000404, 0x04000404, ++ 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, ++ 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, ++ 0x04000404, 0x04000404, 0x00040404, 0x00040404, 0x00040404, 0x00040404, ++ 0x00040404, 0x00040404, 0x00040404, 0x00040404, 0x00040404, 0x00040404, ++ 0x00040404, 0x00040404, 0x00040404, 0x00040404, 0x00040404, 0x00040404, ++ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, ++ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, ++ 0x04040404, 0x04040404, 0x04040404, 0x04040404, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000000, 0x01000000, ++ 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, ++ 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, ++ 0x01000000, 0x01000000, 0x00010000, 0x00010000, 0x00010000, 0x00010000, ++ 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000, ++ 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000, ++ 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, ++ 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, ++ 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x00000100, 0x00000100, ++ 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, ++ 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, ++ 0x00000100, 0x00000100, 0x01000100, 0x01000100, 0x01000100, 0x01000100, ++ 0x01000100, 0x01000100, 0x01000100, 0x01000100, 0x01000100, 0x01000100, ++ 0x01000100, 0x01000100, 0x01000100, 0x01000100, 0x01000100, 0x01000100, ++ 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, ++ 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, ++ 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x01010100, 0x01010100, ++ 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, ++ 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, ++ 0x01010100, 0x01010100, 0x00000001, 0x00000001, 0x00000001, 0x00000001, ++ 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, ++ 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, ++ 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, ++ 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, ++ 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x00010001, 0x00010001, ++ 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, ++ 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, ++ 0x00010001, 0x00010001, 0x01010001, 0x01010001, 0x01010001, 0x01010001, ++ 0x01010001, 0x01010001, 0x01010001, 0x01010001, 0x01010001, 0x01010001, ++ 0x01010001, 0x01010001, 0x01010001, 0x01010001, 0x01010001, 0x01010001, ++ 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, ++ 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, ++ 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x01000101, 0x01000101, ++ 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, ++ 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, ++ 0x01000101, 0x01000101, 0x00010101, 0x00010101, 0x00010101, 0x00010101, ++ 0x00010101, 0x00010101, 0x00010101, 0x00010101, 0x00010101, 0x00010101, ++ 0x00010101, 0x00010101, 0x00010101, 0x00010101, 0x00010101, 0x00010101, ++ 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, ++ 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, ++ 0x01010101, 0x01010101, 0x01010101, 0x01010101, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0x80000000, ++ 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, ++ 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, 0x80000000, ++ 0x80000000, 0x80000000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, ++ 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, ++ 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, ++ 0x80800000, 0x80800000, 0x80800000, 0x80800000, 0x80800000, 0x80800000, ++ 0x80800000, 0x80800000, 0x80800000, 0x80800000, 0x80800000, 0x80800000, ++ 0x80800000, 0x80800000, 0x80800000, 0x80800000, 0x00008000, 0x00008000, ++ 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, ++ 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, ++ 0x00008000, 0x00008000, 0x80008000, 0x80008000, 0x80008000, 0x80008000, ++ 0x80008000, 0x80008000, 0x80008000, 0x80008000, 0x80008000, 0x80008000, ++ 0x80008000, 0x80008000, 0x80008000, 0x80008000, 0x80008000, 0x80008000, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x80808000, 0x80808000, ++ 0x80808000, 0x80808000, 0x80808000, 0x80808000, 0x80808000, 0x80808000, ++ 0x80808000, 0x80808000, 0x80808000, 0x80808000, 0x80808000, 0x80808000, ++ 0x80808000, 0x80808000, 0x00000080, 0x00000080, 0x00000080, 0x00000080, ++ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, ++ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, ++ 0x80000080, 0x80000080, 0x80000080, 0x80000080, 0x80000080, 0x80000080, ++ 0x80000080, 0x80000080, 0x80000080, 0x80000080, 0x80000080, 0x80000080, ++ 0x80000080, 0x80000080, 0x80000080, 0x80000080, 0x00800080, 0x00800080, ++ 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, ++ 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, ++ 0x00800080, 0x00800080, 0x80800080, 0x80800080, 0x80800080, 0x80800080, ++ 0x80800080, 0x80800080, 0x80800080, 0x80800080, 0x80800080, 0x80800080, ++ 0x80800080, 0x80800080, 0x80800080, 0x80800080, 0x80800080, 0x80800080, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x80008080, 0x80008080, ++ 0x80008080, 0x80008080, 0x80008080, 0x80008080, 0x80008080, 0x80008080, ++ 0x80008080, 0x80008080, 0x80008080, 0x80008080, 0x80008080, 0x80008080, ++ 0x80008080, 0x80008080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, ++ 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, ++ 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, ++ 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, ++ 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, 0x80808080, ++ 0x80808080, 0x80808080, 0x80808080, 0x80808080, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x20000000, 0x20000000, ++ 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, ++ 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, ++ 0x20000000, 0x20000000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, ++ 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, ++ 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, ++ 0x20200000, 0x20200000, 0x20200000, 0x20200000, 0x20200000, 0x20200000, ++ 0x20200000, 0x20200000, 0x20200000, 0x20200000, 0x20200000, 0x20200000, ++ 0x20200000, 0x20200000, 0x20200000, 0x20200000, 0x00002000, 0x00002000, ++ 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, ++ 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, ++ 0x00002000, 0x00002000, 0x20002000, 0x20002000, 0x20002000, 0x20002000, ++ 0x20002000, 0x20002000, 0x20002000, 0x20002000, 0x20002000, 0x20002000, ++ 0x20002000, 0x20002000, 0x20002000, 0x20002000, 0x20002000, 0x20002000, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x20202000, 0x20202000, ++ 0x20202000, 0x20202000, 0x20202000, 0x20202000, 0x20202000, 0x20202000, ++ 0x20202000, 0x20202000, 0x20202000, 0x20202000, 0x20202000, 0x20202000, ++ 0x20202000, 0x20202000, 0x00000020, 0x00000020, 0x00000020, 0x00000020, ++ 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, ++ 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, ++ 0x20000020, 0x20000020, 0x20000020, 0x20000020, 0x20000020, 0x20000020, ++ 0x20000020, 0x20000020, 0x20000020, 0x20000020, 0x20000020, 0x20000020, ++ 0x20000020, 0x20000020, 0x20000020, 0x20000020, 0x00200020, 0x00200020, ++ 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, ++ 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, ++ 0x00200020, 0x00200020, 0x20200020, 0x20200020, 0x20200020, 0x20200020, ++ 0x20200020, 0x20200020, 0x20200020, 0x20200020, 0x20200020, 0x20200020, ++ 0x20200020, 0x20200020, 0x20200020, 0x20200020, 0x20200020, 0x20200020, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x20002020, 0x20002020, ++ 0x20002020, 0x20002020, 0x20002020, 0x20002020, 0x20002020, 0x20002020, ++ 0x20002020, 0x20002020, 0x20002020, 0x20002020, 0x20002020, 0x20002020, ++ 0x20002020, 0x20002020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, ++ 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, ++ 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, ++ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, ++ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, ++ 0x20202020, 0x20202020, 0x20202020, 0x20202020, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000, 0x08000000, ++ 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, ++ 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, ++ 0x08000000, 0x08000000, 0x00080000, 0x00080000, 0x00080000, 0x00080000, ++ 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000, ++ 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000, ++ 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, ++ 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, ++ 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x00000800, 0x00000800, ++ 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, ++ 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, ++ 0x00000800, 0x00000800, 0x08000800, 0x08000800, 0x08000800, 0x08000800, ++ 0x08000800, 0x08000800, 0x08000800, 0x08000800, 0x08000800, 0x08000800, ++ 0x08000800, 0x08000800, 0x08000800, 0x08000800, 0x08000800, 0x08000800, ++ 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, ++ 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, ++ 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x08080800, 0x08080800, ++ 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, ++ 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, ++ 0x08080800, 0x08080800, 0x00000008, 0x00000008, 0x00000008, 0x00000008, ++ 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, ++ 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, ++ 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, ++ 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, ++ 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x00080008, 0x00080008, ++ 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, ++ 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, ++ 0x00080008, 0x00080008, 0x08080008, 0x08080008, 0x08080008, 0x08080008, ++ 0x08080008, 0x08080008, 0x08080008, 0x08080008, 0x08080008, 0x08080008, ++ 0x08080008, 0x08080008, 0x08080008, 0x08080008, 0x08080008, 0x08080008, ++ 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, ++ 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, ++ 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x08000808, 0x08000808, ++ 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, ++ 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, ++ 0x08000808, 0x08000808, 0x00080808, 0x00080808, 0x00080808, 0x00080808, ++ 0x00080808, 0x00080808, 0x00080808, 0x00080808, 0x00080808, 0x00080808, ++ 0x00080808, 0x00080808, 0x00080808, 0x00080808, 0x00080808, 0x00080808, ++ 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, ++ 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, ++ 0x08080808, 0x08080808, 0x08080808, 0x08080808, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x02000000, ++ 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, ++ 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, ++ 0x02000000, 0x02000000, 0x00020000, 0x00020000, 0x00020000, 0x00020000, ++ 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000, ++ 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000, ++ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, ++ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, ++ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x00000200, 0x00000200, ++ 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, ++ 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, ++ 0x00000200, 0x00000200, 0x02000200, 0x02000200, 0x02000200, 0x02000200, ++ 0x02000200, 0x02000200, 0x02000200, 0x02000200, 0x02000200, 0x02000200, ++ 0x02000200, 0x02000200, 0x02000200, 0x02000200, 0x02000200, 0x02000200, ++ 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, ++ 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, ++ 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x02020200, 0x02020200, ++ 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, ++ 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, ++ 0x02020200, 0x02020200, 0x00000002, 0x00000002, 0x00000002, 0x00000002, ++ 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, ++ 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, ++ 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, ++ 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, ++ 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x00020002, 0x00020002, ++ 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, ++ 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, ++ 0x00020002, 0x00020002, 0x02020002, 0x02020002, 0x02020002, 0x02020002, ++ 0x02020002, 0x02020002, 0x02020002, 0x02020002, 0x02020002, 0x02020002, ++ 0x02020002, 0x02020002, 0x02020002, 0x02020002, 0x02020002, 0x02020002, ++ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, ++ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, ++ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x02000202, 0x02000202, ++ 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, ++ 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, ++ 0x02000202, 0x02000202, 0x00020202, 0x00020202, 0x00020202, 0x00020202, ++ 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00020202, ++ 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x00020202, ++ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, ++ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, ++ 0x02020202, 0x02020202, 0x02020202, 0x02020202, ++ }, ++}; ++ ++const uint32_t key_perm_maskl[8][128] = { ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000010, ++ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, ++ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, ++ 0x00000010, 0x00000010, 0x00001000, 0x00001000, 0x00001000, 0x00001000, ++ 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, ++ 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, 0x00001000, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00001010, ++ 0x00001010, 0x00001010, 0x00001010, 0x00001010, 0x00100000, 0x00100000, ++ 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, ++ 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000, ++ 0x00100000, 0x00100000, 0x00100010, 0x00100010, 0x00100010, 0x00100010, ++ 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, ++ 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, 0x00100010, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101000, ++ 0x00101000, 0x00101000, 0x00101000, 0x00101000, 0x00101010, 0x00101010, ++ 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, ++ 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, 0x00101010, ++ 0x00101010, 0x00101010, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000020, ++ 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, ++ 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, ++ 0x00000020, 0x00000020, 0x00002000, 0x00002000, 0x00002000, 0x00002000, ++ 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, ++ 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, 0x00002000, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00002020, ++ 0x00002020, 0x00002020, 0x00002020, 0x00002020, 0x00200000, 0x00200000, ++ 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, ++ 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000, ++ 0x00200000, 0x00200000, 0x00200020, 0x00200020, 0x00200020, 0x00200020, ++ 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, ++ 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, 0x00200020, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202000, ++ 0x00202000, 0x00202000, 0x00202000, 0x00202000, 0x00202020, 0x00202020, ++ 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, ++ 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, 0x00202020, ++ 0x00202020, 0x00202020, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0x00000040, ++ 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, ++ 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, 0x00000040, ++ 0x00000040, 0x00000040, 0x00004000, 0x00004000, 0x00004000, 0x00004000, ++ 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, ++ 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, 0x00004000, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00004040, ++ 0x00004040, 0x00004040, 0x00004040, 0x00004040, 0x00400000, 0x00400000, ++ 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, ++ 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000, ++ 0x00400000, 0x00400000, 0x00400040, 0x00400040, 0x00400040, 0x00400040, ++ 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, ++ 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, 0x00400040, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404000, ++ 0x00404000, 0x00404000, 0x00404000, 0x00404000, 0x00404040, 0x00404040, ++ 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, ++ 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, 0x00404040, ++ 0x00404040, 0x00404040, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000080, 0x00000080, ++ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, ++ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080, ++ 0x00000080, 0x00000080, 0x00008000, 0x00008000, 0x00008000, 0x00008000, ++ 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, ++ 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00008000, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00008080, ++ 0x00008080, 0x00008080, 0x00008080, 0x00008080, 0x00800000, 0x00800000, ++ 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, ++ 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000, ++ 0x00800000, 0x00800000, 0x00800080, 0x00800080, 0x00800080, 0x00800080, ++ 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, ++ 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, 0x00800080, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808000, ++ 0x00808000, 0x00808000, 0x00808000, 0x00808000, 0x00808080, 0x00808080, ++ 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, ++ 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, ++ 0x00808080, 0x00808080, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, ++ 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000100, 0x00000100, ++ 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, 0x00000100, ++ 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, 0x00000101, ++ 0x00000101, 0x00000101, 0x00010000, 0x00010000, 0x00010000, 0x00010000, ++ 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010001, 0x00010001, ++ 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, 0x00010001, ++ 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, 0x00010100, ++ 0x00010100, 0x00010100, 0x00010101, 0x00010101, 0x00010101, 0x00010101, ++ 0x00010101, 0x00010101, 0x00010101, 0x00010101, 0x01000000, 0x01000000, ++ 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000, ++ 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, 0x01000001, ++ 0x01000001, 0x01000001, 0x01000100, 0x01000100, 0x01000100, 0x01000100, ++ 0x01000100, 0x01000100, 0x01000100, 0x01000100, 0x01000101, 0x01000101, ++ 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, 0x01000101, ++ 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, 0x01010000, ++ 0x01010000, 0x01010000, 0x01010001, 0x01010001, 0x01010001, 0x01010001, ++ 0x01010001, 0x01010001, 0x01010001, 0x01010001, 0x01010100, 0x01010100, ++ 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, 0x01010100, ++ 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x01010101, ++ 0x01010101, 0x01010101, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00000002, ++ 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000200, 0x00000200, ++ 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, 0x00000200, ++ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, ++ 0x00000202, 0x00000202, 0x00020000, 0x00020000, 0x00020000, 0x00020000, ++ 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020002, 0x00020002, ++ 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, 0x00020002, ++ 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, 0x00020200, ++ 0x00020200, 0x00020200, 0x00020202, 0x00020202, 0x00020202, 0x00020202, ++ 0x00020202, 0x00020202, 0x00020202, 0x00020202, 0x02000000, 0x02000000, ++ 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000, ++ 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, 0x02000002, ++ 0x02000002, 0x02000002, 0x02000200, 0x02000200, 0x02000200, 0x02000200, ++ 0x02000200, 0x02000200, 0x02000200, 0x02000200, 0x02000202, 0x02000202, ++ 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, 0x02000202, ++ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, ++ 0x02020000, 0x02020000, 0x02020002, 0x02020002, 0x02020002, 0x02020002, ++ 0x02020002, 0x02020002, 0x02020002, 0x02020002, 0x02020200, 0x02020200, ++ 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200, ++ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, ++ 0x02020202, 0x02020202, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004, 0x00000004, ++ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000400, 0x00000400, ++ 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, 0x00000400, ++ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, ++ 0x00000404, 0x00000404, 0x00040000, 0x00040000, 0x00040000, 0x00040000, ++ 0x00040000, 0x00040000, 0x00040000, 0x00040000, 0x00040004, 0x00040004, ++ 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, 0x00040004, ++ 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, 0x00040400, ++ 0x00040400, 0x00040400, 0x00040404, 0x00040404, 0x00040404, 0x00040404, ++ 0x00040404, 0x00040404, 0x00040404, 0x00040404, 0x04000000, 0x04000000, ++ 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000, ++ 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, 0x04000004, ++ 0x04000004, 0x04000004, 0x04000400, 0x04000400, 0x04000400, 0x04000400, ++ 0x04000400, 0x04000400, 0x04000400, 0x04000400, 0x04000404, 0x04000404, ++ 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, 0x04000404, ++ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, ++ 0x04040000, 0x04040000, 0x04040004, 0x04040004, 0x04040004, 0x04040004, ++ 0x04040004, 0x04040004, 0x04040004, 0x04040004, 0x04040400, 0x04040400, ++ 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, 0x04040400, ++ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, ++ 0x04040404, 0x04040404, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008, 0x00000008, ++ 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000800, 0x00000800, ++ 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800, ++ 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, ++ 0x00000808, 0x00000808, 0x00080000, 0x00080000, 0x00080000, 0x00080000, ++ 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080008, 0x00080008, ++ 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, 0x00080008, ++ 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, 0x00080800, ++ 0x00080800, 0x00080800, 0x00080808, 0x00080808, 0x00080808, 0x00080808, ++ 0x00080808, 0x00080808, 0x00080808, 0x00080808, 0x08000000, 0x08000000, ++ 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, 0x08000000, ++ 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, 0x08000008, ++ 0x08000008, 0x08000008, 0x08000800, 0x08000800, 0x08000800, 0x08000800, ++ 0x08000800, 0x08000800, 0x08000800, 0x08000800, 0x08000808, 0x08000808, ++ 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, 0x08000808, ++ 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, ++ 0x08080000, 0x08080000, 0x08080008, 0x08080008, 0x08080008, 0x08080008, ++ 0x08080008, 0x08080008, 0x08080008, 0x08080008, 0x08080800, 0x08080800, ++ 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, 0x08080800, ++ 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, ++ 0x08080808, 0x08080808, ++ }, ++}; ++ ++const uint32_t key_perm_maskr[8][128] = { ++ { ++ 0x00000000, 0x00100000, 0x00001000, 0x00101000, 0x00000010, 0x00100010, ++ 0x00001010, 0x00101010, 0x00000001, 0x00100001, 0x00001001, 0x00101001, ++ 0x00000011, 0x00100011, 0x00001011, 0x00101011, 0x00000000, 0x00100000, ++ 0x00001000, 0x00101000, 0x00000010, 0x00100010, 0x00001010, 0x00101010, ++ 0x00000001, 0x00100001, 0x00001001, 0x00101001, 0x00000011, 0x00100011, ++ 0x00001011, 0x00101011, 0x00000000, 0x00100000, 0x00001000, 0x00101000, ++ 0x00000010, 0x00100010, 0x00001010, 0x00101010, 0x00000001, 0x00100001, ++ 0x00001001, 0x00101001, 0x00000011, 0x00100011, 0x00001011, 0x00101011, ++ 0x00000000, 0x00100000, 0x00001000, 0x00101000, 0x00000010, 0x00100010, ++ 0x00001010, 0x00101010, 0x00000001, 0x00100001, 0x00001001, 0x00101001, ++ 0x00000011, 0x00100011, 0x00001011, 0x00101011, 0x00000000, 0x00100000, ++ 0x00001000, 0x00101000, 0x00000010, 0x00100010, 0x00001010, 0x00101010, ++ 0x00000001, 0x00100001, 0x00001001, 0x00101001, 0x00000011, 0x00100011, ++ 0x00001011, 0x00101011, 0x00000000, 0x00100000, 0x00001000, 0x00101000, ++ 0x00000010, 0x00100010, 0x00001010, 0x00101010, 0x00000001, 0x00100001, ++ 0x00001001, 0x00101001, 0x00000011, 0x00100011, 0x00001011, 0x00101011, ++ 0x00000000, 0x00100000, 0x00001000, 0x00101000, 0x00000010, 0x00100010, ++ 0x00001010, 0x00101010, 0x00000001, 0x00100001, 0x00001001, 0x00101001, ++ 0x00000011, 0x00100011, 0x00001011, 0x00101011, 0x00000000, 0x00100000, ++ 0x00001000, 0x00101000, 0x00000010, 0x00100010, 0x00001010, 0x00101010, ++ 0x00000001, 0x00100001, 0x00001001, 0x00101001, 0x00000011, 0x00100011, ++ 0x00001011, 0x00101011, ++ }, ++ { ++ 0x00000000, 0x00200000, 0x00002000, 0x00202000, 0x00000020, 0x00200020, ++ 0x00002020, 0x00202020, 0x00000002, 0x00200002, 0x00002002, 0x00202002, ++ 0x00000022, 0x00200022, 0x00002022, 0x00202022, 0x00000000, 0x00200000, ++ 0x00002000, 0x00202000, 0x00000020, 0x00200020, 0x00002020, 0x00202020, ++ 0x00000002, 0x00200002, 0x00002002, 0x00202002, 0x00000022, 0x00200022, ++ 0x00002022, 0x00202022, 0x00000000, 0x00200000, 0x00002000, 0x00202000, ++ 0x00000020, 0x00200020, 0x00002020, 0x00202020, 0x00000002, 0x00200002, ++ 0x00002002, 0x00202002, 0x00000022, 0x00200022, 0x00002022, 0x00202022, ++ 0x00000000, 0x00200000, 0x00002000, 0x00202000, 0x00000020, 0x00200020, ++ 0x00002020, 0x00202020, 0x00000002, 0x00200002, 0x00002002, 0x00202002, ++ 0x00000022, 0x00200022, 0x00002022, 0x00202022, 0x00000000, 0x00200000, ++ 0x00002000, 0x00202000, 0x00000020, 0x00200020, 0x00002020, 0x00202020, ++ 0x00000002, 0x00200002, 0x00002002, 0x00202002, 0x00000022, 0x00200022, ++ 0x00002022, 0x00202022, 0x00000000, 0x00200000, 0x00002000, 0x00202000, ++ 0x00000020, 0x00200020, 0x00002020, 0x00202020, 0x00000002, 0x00200002, ++ 0x00002002, 0x00202002, 0x00000022, 0x00200022, 0x00002022, 0x00202022, ++ 0x00000000, 0x00200000, 0x00002000, 0x00202000, 0x00000020, 0x00200020, ++ 0x00002020, 0x00202020, 0x00000002, 0x00200002, 0x00002002, 0x00202002, ++ 0x00000022, 0x00200022, 0x00002022, 0x00202022, 0x00000000, 0x00200000, ++ 0x00002000, 0x00202000, 0x00000020, 0x00200020, 0x00002020, 0x00202020, ++ 0x00000002, 0x00200002, 0x00002002, 0x00202002, 0x00000022, 0x00200022, ++ 0x00002022, 0x00202022, ++ }, ++ { ++ 0x00000000, 0x00400000, 0x00004000, 0x00404000, 0x00000040, 0x00400040, ++ 0x00004040, 0x00404040, 0x00000004, 0x00400004, 0x00004004, 0x00404004, ++ 0x00000044, 0x00400044, 0x00004044, 0x00404044, 0x00000000, 0x00400000, ++ 0x00004000, 0x00404000, 0x00000040, 0x00400040, 0x00004040, 0x00404040, ++ 0x00000004, 0x00400004, 0x00004004, 0x00404004, 0x00000044, 0x00400044, ++ 0x00004044, 0x00404044, 0x00000000, 0x00400000, 0x00004000, 0x00404000, ++ 0x00000040, 0x00400040, 0x00004040, 0x00404040, 0x00000004, 0x00400004, ++ 0x00004004, 0x00404004, 0x00000044, 0x00400044, 0x00004044, 0x00404044, ++ 0x00000000, 0x00400000, 0x00004000, 0x00404000, 0x00000040, 0x00400040, ++ 0x00004040, 0x00404040, 0x00000004, 0x00400004, 0x00004004, 0x00404004, ++ 0x00000044, 0x00400044, 0x00004044, 0x00404044, 0x00000000, 0x00400000, ++ 0x00004000, 0x00404000, 0x00000040, 0x00400040, 0x00004040, 0x00404040, ++ 0x00000004, 0x00400004, 0x00004004, 0x00404004, 0x00000044, 0x00400044, ++ 0x00004044, 0x00404044, 0x00000000, 0x00400000, 0x00004000, 0x00404000, ++ 0x00000040, 0x00400040, 0x00004040, 0x00404040, 0x00000004, 0x00400004, ++ 0x00004004, 0x00404004, 0x00000044, 0x00400044, 0x00004044, 0x00404044, ++ 0x00000000, 0x00400000, 0x00004000, 0x00404000, 0x00000040, 0x00400040, ++ 0x00004040, 0x00404040, 0x00000004, 0x00400004, 0x00004004, 0x00404004, ++ 0x00000044, 0x00400044, 0x00004044, 0x00404044, 0x00000000, 0x00400000, ++ 0x00004000, 0x00404000, 0x00000040, 0x00400040, 0x00004040, 0x00404040, ++ 0x00000004, 0x00400004, 0x00004004, 0x00404004, 0x00000044, 0x00400044, ++ 0x00004044, 0x00404044, ++ }, ++ { ++ 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, ++ 0x00008080, 0x00808080, 0x00000008, 0x00800008, 0x00008008, 0x00808008, ++ 0x00000088, 0x00800088, 0x00008088, 0x00808088, 0x00000000, 0x00800000, ++ 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00808080, ++ 0x00000008, 0x00800008, 0x00008008, 0x00808008, 0x00000088, 0x00800088, ++ 0x00008088, 0x00808088, 0x00000000, 0x00800000, 0x00008000, 0x00808000, ++ 0x00000080, 0x00800080, 0x00008080, 0x00808080, 0x00000008, 0x00800008, ++ 0x00008008, 0x00808008, 0x00000088, 0x00800088, 0x00008088, 0x00808088, ++ 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, ++ 0x00008080, 0x00808080, 0x00000008, 0x00800008, 0x00008008, 0x00808008, ++ 0x00000088, 0x00800088, 0x00008088, 0x00808088, 0x00000000, 0x00800000, ++ 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00808080, ++ 0x00000008, 0x00800008, 0x00008008, 0x00808008, 0x00000088, 0x00800088, ++ 0x00008088, 0x00808088, 0x00000000, 0x00800000, 0x00008000, 0x00808000, ++ 0x00000080, 0x00800080, 0x00008080, 0x00808080, 0x00000008, 0x00800008, ++ 0x00008008, 0x00808008, 0x00000088, 0x00800088, 0x00008088, 0x00808088, ++ 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080, ++ 0x00008080, 0x00808080, 0x00000008, 0x00800008, 0x00008008, 0x00808008, ++ 0x00000088, 0x00800088, 0x00008088, 0x00808088, 0x00000000, 0x00800000, ++ 0x00008000, 0x00808000, 0x00000080, 0x00800080, 0x00008080, 0x00808080, ++ 0x00000008, 0x00800008, 0x00008008, 0x00808008, 0x00000088, 0x00800088, ++ 0x00008088, 0x00808088, ++ }, ++ { ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, 0x00000000, 0x01000000, 0x00010000, 0x01010000, ++ 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000000, 0x01000000, ++ 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, ++ 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, ++ 0x00010100, 0x01010100, ++ }, ++ { ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, 0x00000000, 0x02000000, 0x00020000, 0x02020000, ++ 0x00000200, 0x02000200, 0x00020200, 0x02020200, 0x00000000, 0x02000000, ++ 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200, 0x02020200, ++ 0x00000000, 0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, ++ 0x00020200, 0x02020200, ++ }, ++ { ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, 0x00000000, 0x04000000, 0x00040000, 0x04040000, ++ 0x00000400, 0x04000400, 0x00040400, 0x04040400, 0x00000000, 0x04000000, ++ 0x00040000, 0x04040000, 0x00000400, 0x04000400, 0x00040400, 0x04040400, ++ 0x00000000, 0x04000000, 0x00040000, 0x04040000, 0x00000400, 0x04000400, ++ 0x00040400, 0x04040400, ++ }, ++ { ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, 0x00000000, 0x08000000, 0x00080000, 0x08080000, ++ 0x00000800, 0x08000800, 0x00080800, 0x08080800, 0x00000000, 0x08000000, ++ 0x00080000, 0x08080000, 0x00000800, 0x08000800, 0x00080800, 0x08080800, ++ 0x00000000, 0x08000000, 0x00080000, 0x08080000, 0x00000800, 0x08000800, ++ 0x00080800, 0x08080800, ++ }, ++}; ++ ++const uint32_t comp_maskl[8][128] = { ++ { ++ 0x00000000, 0x00000010, 0x00004000, 0x00004010, 0x00040000, 0x00040010, ++ 0x00044000, 0x00044010, 0x00000100, 0x00000110, 0x00004100, 0x00004110, ++ 0x00040100, 0x00040110, 0x00044100, 0x00044110, 0x00020000, 0x00020010, ++ 0x00024000, 0x00024010, 0x00060000, 0x00060010, 0x00064000, 0x00064010, ++ 0x00020100, 0x00020110, 0x00024100, 0x00024110, 0x00060100, 0x00060110, ++ 0x00064100, 0x00064110, 0x00000001, 0x00000011, 0x00004001, 0x00004011, ++ 0x00040001, 0x00040011, 0x00044001, 0x00044011, 0x00000101, 0x00000111, ++ 0x00004101, 0x00004111, 0x00040101, 0x00040111, 0x00044101, 0x00044111, ++ 0x00020001, 0x00020011, 0x00024001, 0x00024011, 0x00060001, 0x00060011, ++ 0x00064001, 0x00064011, 0x00020101, 0x00020111, 0x00024101, 0x00024111, ++ 0x00060101, 0x00060111, 0x00064101, 0x00064111, 0x00080000, 0x00080010, ++ 0x00084000, 0x00084010, 0x000c0000, 0x000c0010, 0x000c4000, 0x000c4010, ++ 0x00080100, 0x00080110, 0x00084100, 0x00084110, 0x000c0100, 0x000c0110, ++ 0x000c4100, 0x000c4110, 0x000a0000, 0x000a0010, 0x000a4000, 0x000a4010, ++ 0x000e0000, 0x000e0010, 0x000e4000, 0x000e4010, 0x000a0100, 0x000a0110, ++ 0x000a4100, 0x000a4110, 0x000e0100, 0x000e0110, 0x000e4100, 0x000e4110, ++ 0x00080001, 0x00080011, 0x00084001, 0x00084011, 0x000c0001, 0x000c0011, ++ 0x000c4001, 0x000c4011, 0x00080101, 0x00080111, 0x00084101, 0x00084111, ++ 0x000c0101, 0x000c0111, 0x000c4101, 0x000c4111, 0x000a0001, 0x000a0011, ++ 0x000a4001, 0x000a4011, 0x000e0001, 0x000e0011, 0x000e4001, 0x000e4011, ++ 0x000a0101, 0x000a0111, 0x000a4101, 0x000a4111, 0x000e0101, 0x000e0111, ++ 0x000e4101, 0x000e4111, ++ }, ++ { ++ 0x00000000, 0x00800000, 0x00000002, 0x00800002, 0x00000200, 0x00800200, ++ 0x00000202, 0x00800202, 0x00200000, 0x00a00000, 0x00200002, 0x00a00002, ++ 0x00200200, 0x00a00200, 0x00200202, 0x00a00202, 0x00001000, 0x00801000, ++ 0x00001002, 0x00801002, 0x00001200, 0x00801200, 0x00001202, 0x00801202, ++ 0x00201000, 0x00a01000, 0x00201002, 0x00a01002, 0x00201200, 0x00a01200, ++ 0x00201202, 0x00a01202, 0x00000000, 0x00800000, 0x00000002, 0x00800002, ++ 0x00000200, 0x00800200, 0x00000202, 0x00800202, 0x00200000, 0x00a00000, ++ 0x00200002, 0x00a00002, 0x00200200, 0x00a00200, 0x00200202, 0x00a00202, ++ 0x00001000, 0x00801000, 0x00001002, 0x00801002, 0x00001200, 0x00801200, ++ 0x00001202, 0x00801202, 0x00201000, 0x00a01000, 0x00201002, 0x00a01002, ++ 0x00201200, 0x00a01200, 0x00201202, 0x00a01202, 0x00000040, 0x00800040, ++ 0x00000042, 0x00800042, 0x00000240, 0x00800240, 0x00000242, 0x00800242, ++ 0x00200040, 0x00a00040, 0x00200042, 0x00a00042, 0x00200240, 0x00a00240, ++ 0x00200242, 0x00a00242, 0x00001040, 0x00801040, 0x00001042, 0x00801042, ++ 0x00001240, 0x00801240, 0x00001242, 0x00801242, 0x00201040, 0x00a01040, ++ 0x00201042, 0x00a01042, 0x00201240, 0x00a01240, 0x00201242, 0x00a01242, ++ 0x00000040, 0x00800040, 0x00000042, 0x00800042, 0x00000240, 0x00800240, ++ 0x00000242, 0x00800242, 0x00200040, 0x00a00040, 0x00200042, 0x00a00042, ++ 0x00200240, 0x00a00240, 0x00200242, 0x00a00242, 0x00001040, 0x00801040, ++ 0x00001042, 0x00801042, 0x00001240, 0x00801240, 0x00001242, 0x00801242, ++ 0x00201040, 0x00a01040, 0x00201042, 0x00a01042, 0x00201240, 0x00a01240, ++ 0x00201242, 0x00a01242, ++ }, ++ { ++ 0x00000000, 0x00002000, 0x00000004, 0x00002004, 0x00000400, 0x00002400, ++ 0x00000404, 0x00002404, 0x00000000, 0x00002000, 0x00000004, 0x00002004, ++ 0x00000400, 0x00002400, 0x00000404, 0x00002404, 0x00400000, 0x00402000, ++ 0x00400004, 0x00402004, 0x00400400, 0x00402400, 0x00400404, 0x00402404, ++ 0x00400000, 0x00402000, 0x00400004, 0x00402004, 0x00400400, 0x00402400, ++ 0x00400404, 0x00402404, 0x00000020, 0x00002020, 0x00000024, 0x00002024, ++ 0x00000420, 0x00002420, 0x00000424, 0x00002424, 0x00000020, 0x00002020, ++ 0x00000024, 0x00002024, 0x00000420, 0x00002420, 0x00000424, 0x00002424, ++ 0x00400020, 0x00402020, 0x00400024, 0x00402024, 0x00400420, 0x00402420, ++ 0x00400424, 0x00402424, 0x00400020, 0x00402020, 0x00400024, 0x00402024, ++ 0x00400420, 0x00402420, 0x00400424, 0x00402424, 0x00008000, 0x0000a000, ++ 0x00008004, 0x0000a004, 0x00008400, 0x0000a400, 0x00008404, 0x0000a404, ++ 0x00008000, 0x0000a000, 0x00008004, 0x0000a004, 0x00008400, 0x0000a400, ++ 0x00008404, 0x0000a404, 0x00408000, 0x0040a000, 0x00408004, 0x0040a004, ++ 0x00408400, 0x0040a400, 0x00408404, 0x0040a404, 0x00408000, 0x0040a000, ++ 0x00408004, 0x0040a004, 0x00408400, 0x0040a400, 0x00408404, 0x0040a404, ++ 0x00008020, 0x0000a020, 0x00008024, 0x0000a024, 0x00008420, 0x0000a420, ++ 0x00008424, 0x0000a424, 0x00008020, 0x0000a020, 0x00008024, 0x0000a024, ++ 0x00008420, 0x0000a420, 0x00008424, 0x0000a424, 0x00408020, 0x0040a020, ++ 0x00408024, 0x0040a024, 0x00408420, 0x0040a420, 0x00408424, 0x0040a424, ++ 0x00408020, 0x0040a020, 0x00408024, 0x0040a024, 0x00408420, 0x0040a420, ++ 0x00408424, 0x0040a424, ++ }, ++ { ++ 0x00000000, 0x00010000, 0x00000008, 0x00010008, 0x00000080, 0x00010080, ++ 0x00000088, 0x00010088, 0x00000000, 0x00010000, 0x00000008, 0x00010008, ++ 0x00000080, 0x00010080, 0x00000088, 0x00010088, 0x00100000, 0x00110000, ++ 0x00100008, 0x00110008, 0x00100080, 0x00110080, 0x00100088, 0x00110088, ++ 0x00100000, 0x00110000, 0x00100008, 0x00110008, 0x00100080, 0x00110080, ++ 0x00100088, 0x00110088, 0x00000800, 0x00010800, 0x00000808, 0x00010808, ++ 0x00000880, 0x00010880, 0x00000888, 0x00010888, 0x00000800, 0x00010800, ++ 0x00000808, 0x00010808, 0x00000880, 0x00010880, 0x00000888, 0x00010888, ++ 0x00100800, 0x00110800, 0x00100808, 0x00110808, 0x00100880, 0x00110880, ++ 0x00100888, 0x00110888, 0x00100800, 0x00110800, 0x00100808, 0x00110808, ++ 0x00100880, 0x00110880, 0x00100888, 0x00110888, 0x00000000, 0x00010000, ++ 0x00000008, 0x00010008, 0x00000080, 0x00010080, 0x00000088, 0x00010088, ++ 0x00000000, 0x00010000, 0x00000008, 0x00010008, 0x00000080, 0x00010080, ++ 0x00000088, 0x00010088, 0x00100000, 0x00110000, 0x00100008, 0x00110008, ++ 0x00100080, 0x00110080, 0x00100088, 0x00110088, 0x00100000, 0x00110000, ++ 0x00100008, 0x00110008, 0x00100080, 0x00110080, 0x00100088, 0x00110088, ++ 0x00000800, 0x00010800, 0x00000808, 0x00010808, 0x00000880, 0x00010880, ++ 0x00000888, 0x00010888, 0x00000800, 0x00010800, 0x00000808, 0x00010808, ++ 0x00000880, 0x00010880, 0x00000888, 0x00010888, 0x00100800, 0x00110800, ++ 0x00100808, 0x00110808, 0x00100880, 0x00110880, 0x00100888, 0x00110888, ++ 0x00100800, 0x00110800, 0x00100808, 0x00110808, 0x00100880, 0x00110880, ++ 0x00100888, 0x00110888, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++}; ++ ++const uint32_t comp_maskr[8][128] = { ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, ++ 0x00000000, 0x00000000, ++ }, ++ { ++ 0x00000000, 0x00000000, 0x00000080, 0x00000080, 0x00002000, 0x00002000, ++ 0x00002080, 0x00002080, 0x00000001, 0x00000001, 0x00000081, 0x00000081, ++ 0x00002001, 0x00002001, 0x00002081, 0x00002081, 0x00200000, 0x00200000, ++ 0x00200080, 0x00200080, 0x00202000, 0x00202000, 0x00202080, 0x00202080, ++ 0x00200001, 0x00200001, 0x00200081, 0x00200081, 0x00202001, 0x00202001, ++ 0x00202081, 0x00202081, 0x00020000, 0x00020000, 0x00020080, 0x00020080, ++ 0x00022000, 0x00022000, 0x00022080, 0x00022080, 0x00020001, 0x00020001, ++ 0x00020081, 0x00020081, 0x00022001, 0x00022001, 0x00022081, 0x00022081, ++ 0x00220000, 0x00220000, 0x00220080, 0x00220080, 0x00222000, 0x00222000, ++ 0x00222080, 0x00222080, 0x00220001, 0x00220001, 0x00220081, 0x00220081, ++ 0x00222001, 0x00222001, 0x00222081, 0x00222081, 0x00000002, 0x00000002, ++ 0x00000082, 0x00000082, 0x00002002, 0x00002002, 0x00002082, 0x00002082, ++ 0x00000003, 0x00000003, 0x00000083, 0x00000083, 0x00002003, 0x00002003, ++ 0x00002083, 0x00002083, 0x00200002, 0x00200002, 0x00200082, 0x00200082, ++ 0x00202002, 0x00202002, 0x00202082, 0x00202082, 0x00200003, 0x00200003, ++ 0x00200083, 0x00200083, 0x00202003, 0x00202003, 0x00202083, 0x00202083, ++ 0x00020002, 0x00020002, 0x00020082, 0x00020082, 0x00022002, 0x00022002, ++ 0x00022082, 0x00022082, 0x00020003, 0x00020003, 0x00020083, 0x00020083, ++ 0x00022003, 0x00022003, 0x00022083, 0x00022083, 0x00220002, 0x00220002, ++ 0x00220082, 0x00220082, 0x00222002, 0x00222002, 0x00222082, 0x00222082, ++ 0x00220003, 0x00220003, 0x00220083, 0x00220083, 0x00222003, 0x00222003, ++ 0x00222083, 0x00222083, ++ }, ++ { ++ 0x00000000, 0x00000010, 0x00800000, 0x00800010, 0x00010000, 0x00010010, ++ 0x00810000, 0x00810010, 0x00000200, 0x00000210, 0x00800200, 0x00800210, ++ 0x00010200, 0x00010210, 0x00810200, 0x00810210, 0x00000000, 0x00000010, ++ 0x00800000, 0x00800010, 0x00010000, 0x00010010, 0x00810000, 0x00810010, ++ 0x00000200, 0x00000210, 0x00800200, 0x00800210, 0x00010200, 0x00010210, ++ 0x00810200, 0x00810210, 0x00100000, 0x00100010, 0x00900000, 0x00900010, ++ 0x00110000, 0x00110010, 0x00910000, 0x00910010, 0x00100200, 0x00100210, ++ 0x00900200, 0x00900210, 0x00110200, 0x00110210, 0x00910200, 0x00910210, ++ 0x00100000, 0x00100010, 0x00900000, 0x00900010, 0x00110000, 0x00110010, ++ 0x00910000, 0x00910010, 0x00100200, 0x00100210, 0x00900200, 0x00900210, ++ 0x00110200, 0x00110210, 0x00910200, 0x00910210, 0x00000004, 0x00000014, ++ 0x00800004, 0x00800014, 0x00010004, 0x00010014, 0x00810004, 0x00810014, ++ 0x00000204, 0x00000214, 0x00800204, 0x00800214, 0x00010204, 0x00010214, ++ 0x00810204, 0x00810214, 0x00000004, 0x00000014, 0x00800004, 0x00800014, ++ 0x00010004, 0x00010014, 0x00810004, 0x00810014, 0x00000204, 0x00000214, ++ 0x00800204, 0x00800214, 0x00010204, 0x00010214, 0x00810204, 0x00810214, ++ 0x00100004, 0x00100014, 0x00900004, 0x00900014, 0x00110004, 0x00110014, ++ 0x00910004, 0x00910014, 0x00100204, 0x00100214, 0x00900204, 0x00900214, ++ 0x00110204, 0x00110214, 0x00910204, 0x00910214, 0x00100004, 0x00100014, ++ 0x00900004, 0x00900014, 0x00110004, 0x00110014, 0x00910004, 0x00910014, ++ 0x00100204, 0x00100214, 0x00900204, 0x00900214, 0x00110204, 0x00110214, ++ 0x00910204, 0x00910214, ++ }, ++ { ++ 0x00000000, 0x00000400, 0x00001000, 0x00001400, 0x00080000, 0x00080400, ++ 0x00081000, 0x00081400, 0x00000020, 0x00000420, 0x00001020, 0x00001420, ++ 0x00080020, 0x00080420, 0x00081020, 0x00081420, 0x00004000, 0x00004400, ++ 0x00005000, 0x00005400, 0x00084000, 0x00084400, 0x00085000, 0x00085400, ++ 0x00004020, 0x00004420, 0x00005020, 0x00005420, 0x00084020, 0x00084420, ++ 0x00085020, 0x00085420, 0x00000800, 0x00000c00, 0x00001800, 0x00001c00, ++ 0x00080800, 0x00080c00, 0x00081800, 0x00081c00, 0x00000820, 0x00000c20, ++ 0x00001820, 0x00001c20, 0x00080820, 0x00080c20, 0x00081820, 0x00081c20, ++ 0x00004800, 0x00004c00, 0x00005800, 0x00005c00, 0x00084800, 0x00084c00, ++ 0x00085800, 0x00085c00, 0x00004820, 0x00004c20, 0x00005820, 0x00005c20, ++ 0x00084820, 0x00084c20, 0x00085820, 0x00085c20, 0x00000000, 0x00000400, ++ 0x00001000, 0x00001400, 0x00080000, 0x00080400, 0x00081000, 0x00081400, ++ 0x00000020, 0x00000420, 0x00001020, 0x00001420, 0x00080020, 0x00080420, ++ 0x00081020, 0x00081420, 0x00004000, 0x00004400, 0x00005000, 0x00005400, ++ 0x00084000, 0x00084400, 0x00085000, 0x00085400, 0x00004020, 0x00004420, ++ 0x00005020, 0x00005420, 0x00084020, 0x00084420, 0x00085020, 0x00085420, ++ 0x00000800, 0x00000c00, 0x00001800, 0x00001c00, 0x00080800, 0x00080c00, ++ 0x00081800, 0x00081c00, 0x00000820, 0x00000c20, 0x00001820, 0x00001c20, ++ 0x00080820, 0x00080c20, 0x00081820, 0x00081c20, 0x00004800, 0x00004c00, ++ 0x00005800, 0x00005c00, 0x00084800, 0x00084c00, 0x00085800, 0x00085c00, ++ 0x00004820, 0x00004c20, 0x00005820, 0x00005c20, 0x00084820, 0x00084c20, ++ 0x00085820, 0x00085c20, ++ }, ++ { ++ 0x00000000, 0x00000100, 0x00040000, 0x00040100, 0x00000000, 0x00000100, ++ 0x00040000, 0x00040100, 0x00000040, 0x00000140, 0x00040040, 0x00040140, ++ 0x00000040, 0x00000140, 0x00040040, 0x00040140, 0x00400000, 0x00400100, ++ 0x00440000, 0x00440100, 0x00400000, 0x00400100, 0x00440000, 0x00440100, ++ 0x00400040, 0x00400140, 0x00440040, 0x00440140, 0x00400040, 0x00400140, ++ 0x00440040, 0x00440140, 0x00008000, 0x00008100, 0x00048000, 0x00048100, ++ 0x00008000, 0x00008100, 0x00048000, 0x00048100, 0x00008040, 0x00008140, ++ 0x00048040, 0x00048140, 0x00008040, 0x00008140, 0x00048040, 0x00048140, ++ 0x00408000, 0x00408100, 0x00448000, 0x00448100, 0x00408000, 0x00408100, ++ 0x00448000, 0x00448100, 0x00408040, 0x00408140, 0x00448040, 0x00448140, ++ 0x00408040, 0x00408140, 0x00448040, 0x00448140, 0x00000008, 0x00000108, ++ 0x00040008, 0x00040108, 0x00000008, 0x00000108, 0x00040008, 0x00040108, ++ 0x00000048, 0x00000148, 0x00040048, 0x00040148, 0x00000048, 0x00000148, ++ 0x00040048, 0x00040148, 0x00400008, 0x00400108, 0x00440008, 0x00440108, ++ 0x00400008, 0x00400108, 0x00440008, 0x00440108, 0x00400048, 0x00400148, ++ 0x00440048, 0x00440148, 0x00400048, 0x00400148, 0x00440048, 0x00440148, ++ 0x00008008, 0x00008108, 0x00048008, 0x00048108, 0x00008008, 0x00008108, ++ 0x00048008, 0x00048108, 0x00008048, 0x00008148, 0x00048048, 0x00048148, ++ 0x00008048, 0x00008148, 0x00048048, 0x00048148, 0x00408008, 0x00408108, ++ 0x00448008, 0x00448108, 0x00408008, 0x00408108, 0x00448008, 0x00448108, ++ 0x00408048, 0x00408148, 0x00448048, 0x00448148, 0x00408048, 0x00408148, ++ 0x00448048, 0x00448148, ++ }, ++}; ++ ++const uint32_t psbox[4][256] = { ++ { ++ 0x00000000, 0x00004000, 0x40000000, 0x40004000, 0x00000010, 0x00004010, ++ 0x40000010, 0x40004010, 0x00080000, 0x00084000, 0x40080000, 0x40084000, ++ 0x00080010, 0x00084010, 0x40080010, 0x40084010, 0x00000002, 0x00004002, ++ 0x40000002, 0x40004002, 0x00000012, 0x00004012, 0x40000012, 0x40004012, ++ 0x00080002, 0x00084002, 0x40080002, 0x40084002, 0x00080012, 0x00084012, ++ 0x40080012, 0x40084012, 0x00000200, 0x00004200, 0x40000200, 0x40004200, ++ 0x00000210, 0x00004210, 0x40000210, 0x40004210, 0x00080200, 0x00084200, ++ 0x40080200, 0x40084200, 0x00080210, 0x00084210, 0x40080210, 0x40084210, ++ 0x00000202, 0x00004202, 0x40000202, 0x40004202, 0x00000212, 0x00004212, ++ 0x40000212, 0x40004212, 0x00080202, 0x00084202, 0x40080202, 0x40084202, ++ 0x00080212, 0x00084212, 0x40080212, 0x40084212, 0x00008000, 0x0000c000, ++ 0x40008000, 0x4000c000, 0x00008010, 0x0000c010, 0x40008010, 0x4000c010, ++ 0x00088000, 0x0008c000, 0x40088000, 0x4008c000, 0x00088010, 0x0008c010, ++ 0x40088010, 0x4008c010, 0x00008002, 0x0000c002, 0x40008002, 0x4000c002, ++ 0x00008012, 0x0000c012, 0x40008012, 0x4000c012, 0x00088002, 0x0008c002, ++ 0x40088002, 0x4008c002, 0x00088012, 0x0008c012, 0x40088012, 0x4008c012, ++ 0x00008200, 0x0000c200, 0x40008200, 0x4000c200, 0x00008210, 0x0000c210, ++ 0x40008210, 0x4000c210, 0x00088200, 0x0008c200, 0x40088200, 0x4008c200, ++ 0x00088210, 0x0008c210, 0x40088210, 0x4008c210, 0x00008202, 0x0000c202, ++ 0x40008202, 0x4000c202, 0x00008212, 0x0000c212, 0x40008212, 0x4000c212, ++ 0x00088202, 0x0008c202, 0x40088202, 0x4008c202, 0x00088212, 0x0008c212, ++ 0x40088212, 0x4008c212, 0x00800000, 0x00804000, 0x40800000, 0x40804000, ++ 0x00800010, 0x00804010, 0x40800010, 0x40804010, 0x00880000, 0x00884000, ++ 0x40880000, 0x40884000, 0x00880010, 0x00884010, 0x40880010, 0x40884010, ++ 0x00800002, 0x00804002, 0x40800002, 0x40804002, 0x00800012, 0x00804012, ++ 0x40800012, 0x40804012, 0x00880002, 0x00884002, 0x40880002, 0x40884002, ++ 0x00880012, 0x00884012, 0x40880012, 0x40884012, 0x00800200, 0x00804200, ++ 0x40800200, 0x40804200, 0x00800210, 0x00804210, 0x40800210, 0x40804210, ++ 0x00880200, 0x00884200, 0x40880200, 0x40884200, 0x00880210, 0x00884210, ++ 0x40880210, 0x40884210, 0x00800202, 0x00804202, 0x40800202, 0x40804202, ++ 0x00800212, 0x00804212, 0x40800212, 0x40804212, 0x00880202, 0x00884202, ++ 0x40880202, 0x40884202, 0x00880212, 0x00884212, 0x40880212, 0x40884212, ++ 0x00808000, 0x0080c000, 0x40808000, 0x4080c000, 0x00808010, 0x0080c010, ++ 0x40808010, 0x4080c010, 0x00888000, 0x0088c000, 0x40888000, 0x4088c000, ++ 0x00888010, 0x0088c010, 0x40888010, 0x4088c010, 0x00808002, 0x0080c002, ++ 0x40808002, 0x4080c002, 0x00808012, 0x0080c012, 0x40808012, 0x4080c012, ++ 0x00888002, 0x0088c002, 0x40888002, 0x4088c002, 0x00888012, 0x0088c012, ++ 0x40888012, 0x4088c012, 0x00808200, 0x0080c200, 0x40808200, 0x4080c200, ++ 0x00808210, 0x0080c210, 0x40808210, 0x4080c210, 0x00888200, 0x0088c200, ++ 0x40888200, 0x4088c200, 0x00888210, 0x0088c210, 0x40888210, 0x4088c210, ++ 0x00808202, 0x0080c202, 0x40808202, 0x4080c202, 0x00808212, 0x0080c212, ++ 0x40808212, 0x4080c212, 0x00888202, 0x0088c202, 0x40888202, 0x4088c202, ++ 0x00888212, 0x0088c212, 0x40888212, 0x4088c212, ++ }, ++ { ++ 0x00000000, 0x80000000, 0x00400000, 0x80400000, 0x00001000, 0x80001000, ++ 0x00401000, 0x80401000, 0x00000040, 0x80000040, 0x00400040, 0x80400040, ++ 0x00001040, 0x80001040, 0x00401040, 0x80401040, 0x04000000, 0x84000000, ++ 0x04400000, 0x84400000, 0x04001000, 0x84001000, 0x04401000, 0x84401000, ++ 0x04000040, 0x84000040, 0x04400040, 0x84400040, 0x04001040, 0x84001040, ++ 0x04401040, 0x84401040, 0x00000004, 0x80000004, 0x00400004, 0x80400004, ++ 0x00001004, 0x80001004, 0x00401004, 0x80401004, 0x00000044, 0x80000044, ++ 0x00400044, 0x80400044, 0x00001044, 0x80001044, 0x00401044, 0x80401044, ++ 0x04000004, 0x84000004, 0x04400004, 0x84400004, 0x04001004, 0x84001004, ++ 0x04401004, 0x84401004, 0x04000044, 0x84000044, 0x04400044, 0x84400044, ++ 0x04001044, 0x84001044, 0x04401044, 0x84401044, 0x00010000, 0x80010000, ++ 0x00410000, 0x80410000, 0x00011000, 0x80011000, 0x00411000, 0x80411000, ++ 0x00010040, 0x80010040, 0x00410040, 0x80410040, 0x00011040, 0x80011040, ++ 0x00411040, 0x80411040, 0x04010000, 0x84010000, 0x04410000, 0x84410000, ++ 0x04011000, 0x84011000, 0x04411000, 0x84411000, 0x04010040, 0x84010040, ++ 0x04410040, 0x84410040, 0x04011040, 0x84011040, 0x04411040, 0x84411040, ++ 0x00010004, 0x80010004, 0x00410004, 0x80410004, 0x00011004, 0x80011004, ++ 0x00411004, 0x80411004, 0x00010044, 0x80010044, 0x00410044, 0x80410044, ++ 0x00011044, 0x80011044, 0x00411044, 0x80411044, 0x04010004, 0x84010004, ++ 0x04410004, 0x84410004, 0x04011004, 0x84011004, 0x04411004, 0x84411004, ++ 0x04010044, 0x84010044, 0x04410044, 0x84410044, 0x04011044, 0x84011044, ++ 0x04411044, 0x84411044, 0x00000100, 0x80000100, 0x00400100, 0x80400100, ++ 0x00001100, 0x80001100, 0x00401100, 0x80401100, 0x00000140, 0x80000140, ++ 0x00400140, 0x80400140, 0x00001140, 0x80001140, 0x00401140, 0x80401140, ++ 0x04000100, 0x84000100, 0x04400100, 0x84400100, 0x04001100, 0x84001100, ++ 0x04401100, 0x84401100, 0x04000140, 0x84000140, 0x04400140, 0x84400140, ++ 0x04001140, 0x84001140, 0x04401140, 0x84401140, 0x00000104, 0x80000104, ++ 0x00400104, 0x80400104, 0x00001104, 0x80001104, 0x00401104, 0x80401104, ++ 0x00000144, 0x80000144, 0x00400144, 0x80400144, 0x00001144, 0x80001144, ++ 0x00401144, 0x80401144, 0x04000104, 0x84000104, 0x04400104, 0x84400104, ++ 0x04001104, 0x84001104, 0x04401104, 0x84401104, 0x04000144, 0x84000144, ++ 0x04400144, 0x84400144, 0x04001144, 0x84001144, 0x04401144, 0x84401144, ++ 0x00010100, 0x80010100, 0x00410100, 0x80410100, 0x00011100, 0x80011100, ++ 0x00411100, 0x80411100, 0x00010140, 0x80010140, 0x00410140, 0x80410140, ++ 0x00011140, 0x80011140, 0x00411140, 0x80411140, 0x04010100, 0x84010100, ++ 0x04410100, 0x84410100, 0x04011100, 0x84011100, 0x04411100, 0x84411100, ++ 0x04010140, 0x84010140, 0x04410140, 0x84410140, 0x04011140, 0x84011140, ++ 0x04411140, 0x84411140, 0x00010104, 0x80010104, 0x00410104, 0x80410104, ++ 0x00011104, 0x80011104, 0x00411104, 0x80411104, 0x00010144, 0x80010144, ++ 0x00410144, 0x80410144, 0x00011144, 0x80011144, 0x00411144, 0x80411144, ++ 0x04010104, 0x84010104, 0x04410104, 0x84410104, 0x04011104, 0x84011104, ++ 0x04411104, 0x84411104, 0x04010144, 0x84010144, 0x04410144, 0x84410144, ++ 0x04011144, 0x84011144, 0x04411144, 0x84411144, ++ }, ++ { ++ 0x00000000, 0x00002000, 0x00200000, 0x00202000, 0x00000008, 0x00002008, ++ 0x00200008, 0x00202008, 0x10000000, 0x10002000, 0x10200000, 0x10202000, ++ 0x10000008, 0x10002008, 0x10200008, 0x10202008, 0x20000000, 0x20002000, ++ 0x20200000, 0x20202000, 0x20000008, 0x20002008, 0x20200008, 0x20202008, ++ 0x30000000, 0x30002000, 0x30200000, 0x30202000, 0x30000008, 0x30002008, ++ 0x30200008, 0x30202008, 0x00000080, 0x00002080, 0x00200080, 0x00202080, ++ 0x00000088, 0x00002088, 0x00200088, 0x00202088, 0x10000080, 0x10002080, ++ 0x10200080, 0x10202080, 0x10000088, 0x10002088, 0x10200088, 0x10202088, ++ 0x20000080, 0x20002080, 0x20200080, 0x20202080, 0x20000088, 0x20002088, ++ 0x20200088, 0x20202088, 0x30000080, 0x30002080, 0x30200080, 0x30202080, ++ 0x30000088, 0x30002088, 0x30200088, 0x30202088, 0x00040000, 0x00042000, ++ 0x00240000, 0x00242000, 0x00040008, 0x00042008, 0x00240008, 0x00242008, ++ 0x10040000, 0x10042000, 0x10240000, 0x10242000, 0x10040008, 0x10042008, ++ 0x10240008, 0x10242008, 0x20040000, 0x20042000, 0x20240000, 0x20242000, ++ 0x20040008, 0x20042008, 0x20240008, 0x20242008, 0x30040000, 0x30042000, ++ 0x30240000, 0x30242000, 0x30040008, 0x30042008, 0x30240008, 0x30242008, ++ 0x00040080, 0x00042080, 0x00240080, 0x00242080, 0x00040088, 0x00042088, ++ 0x00240088, 0x00242088, 0x10040080, 0x10042080, 0x10240080, 0x10242080, ++ 0x10040088, 0x10042088, 0x10240088, 0x10242088, 0x20040080, 0x20042080, ++ 0x20240080, 0x20242080, 0x20040088, 0x20042088, 0x20240088, 0x20242088, ++ 0x30040080, 0x30042080, 0x30240080, 0x30242080, 0x30040088, 0x30042088, ++ 0x30240088, 0x30242088, 0x01000000, 0x01002000, 0x01200000, 0x01202000, ++ 0x01000008, 0x01002008, 0x01200008, 0x01202008, 0x11000000, 0x11002000, ++ 0x11200000, 0x11202000, 0x11000008, 0x11002008, 0x11200008, 0x11202008, ++ 0x21000000, 0x21002000, 0x21200000, 0x21202000, 0x21000008, 0x21002008, ++ 0x21200008, 0x21202008, 0x31000000, 0x31002000, 0x31200000, 0x31202000, ++ 0x31000008, 0x31002008, 0x31200008, 0x31202008, 0x01000080, 0x01002080, ++ 0x01200080, 0x01202080, 0x01000088, 0x01002088, 0x01200088, 0x01202088, ++ 0x11000080, 0x11002080, 0x11200080, 0x11202080, 0x11000088, 0x11002088, ++ 0x11200088, 0x11202088, 0x21000080, 0x21002080, 0x21200080, 0x21202080, ++ 0x21000088, 0x21002088, 0x21200088, 0x21202088, 0x31000080, 0x31002080, ++ 0x31200080, 0x31202080, 0x31000088, 0x31002088, 0x31200088, 0x31202088, ++ 0x01040000, 0x01042000, 0x01240000, 0x01242000, 0x01040008, 0x01042008, ++ 0x01240008, 0x01242008, 0x11040000, 0x11042000, 0x11240000, 0x11242000, ++ 0x11040008, 0x11042008, 0x11240008, 0x11242008, 0x21040000, 0x21042000, ++ 0x21240000, 0x21242000, 0x21040008, 0x21042008, 0x21240008, 0x21242008, ++ 0x31040000, 0x31042000, 0x31240000, 0x31242000, 0x31040008, 0x31042008, ++ 0x31240008, 0x31242008, 0x01040080, 0x01042080, 0x01240080, 0x01242080, ++ 0x01040088, 0x01042088, 0x01240088, 0x01242088, 0x11040080, 0x11042080, ++ 0x11240080, 0x11242080, 0x11040088, 0x11042088, 0x11240088, 0x11242088, ++ 0x21040080, 0x21042080, 0x21240080, 0x21242080, 0x21040088, 0x21042088, ++ 0x21240088, 0x21242088, 0x31040080, 0x31042080, 0x31240080, 0x31242080, ++ 0x31040088, 0x31042088, 0x31240088, 0x31242088, ++ }, ++ { ++ 0x00000000, 0x00000800, 0x00020000, 0x00020800, 0x00000020, 0x00000820, ++ 0x00020020, 0x00020820, 0x08000000, 0x08000800, 0x08020000, 0x08020800, ++ 0x08000020, 0x08000820, 0x08020020, 0x08020820, 0x02000000, 0x02000800, ++ 0x02020000, 0x02020800, 0x02000020, 0x02000820, 0x02020020, 0x02020820, ++ 0x0a000000, 0x0a000800, 0x0a020000, 0x0a020800, 0x0a000020, 0x0a000820, ++ 0x0a020020, 0x0a020820, 0x00000400, 0x00000c00, 0x00020400, 0x00020c00, ++ 0x00000420, 0x00000c20, 0x00020420, 0x00020c20, 0x08000400, 0x08000c00, ++ 0x08020400, 0x08020c00, 0x08000420, 0x08000c20, 0x08020420, 0x08020c20, ++ 0x02000400, 0x02000c00, 0x02020400, 0x02020c00, 0x02000420, 0x02000c20, ++ 0x02020420, 0x02020c20, 0x0a000400, 0x0a000c00, 0x0a020400, 0x0a020c00, ++ 0x0a000420, 0x0a000c20, 0x0a020420, 0x0a020c20, 0x00100000, 0x00100800, ++ 0x00120000, 0x00120800, 0x00100020, 0x00100820, 0x00120020, 0x00120820, ++ 0x08100000, 0x08100800, 0x08120000, 0x08120800, 0x08100020, 0x08100820, ++ 0x08120020, 0x08120820, 0x02100000, 0x02100800, 0x02120000, 0x02120800, ++ 0x02100020, 0x02100820, 0x02120020, 0x02120820, 0x0a100000, 0x0a100800, ++ 0x0a120000, 0x0a120800, 0x0a100020, 0x0a100820, 0x0a120020, 0x0a120820, ++ 0x00100400, 0x00100c00, 0x00120400, 0x00120c00, 0x00100420, 0x00100c20, ++ 0x00120420, 0x00120c20, 0x08100400, 0x08100c00, 0x08120400, 0x08120c00, ++ 0x08100420, 0x08100c20, 0x08120420, 0x08120c20, 0x02100400, 0x02100c00, ++ 0x02120400, 0x02120c00, 0x02100420, 0x02100c20, 0x02120420, 0x02120c20, ++ 0x0a100400, 0x0a100c00, 0x0a120400, 0x0a120c00, 0x0a100420, 0x0a100c20, ++ 0x0a120420, 0x0a120c20, 0x00000001, 0x00000801, 0x00020001, 0x00020801, ++ 0x00000021, 0x00000821, 0x00020021, 0x00020821, 0x08000001, 0x08000801, ++ 0x08020001, 0x08020801, 0x08000021, 0x08000821, 0x08020021, 0x08020821, ++ 0x02000001, 0x02000801, 0x02020001, 0x02020801, 0x02000021, 0x02000821, ++ 0x02020021, 0x02020821, 0x0a000001, 0x0a000801, 0x0a020001, 0x0a020801, ++ 0x0a000021, 0x0a000821, 0x0a020021, 0x0a020821, 0x00000401, 0x00000c01, ++ 0x00020401, 0x00020c01, 0x00000421, 0x00000c21, 0x00020421, 0x00020c21, ++ 0x08000401, 0x08000c01, 0x08020401, 0x08020c01, 0x08000421, 0x08000c21, ++ 0x08020421, 0x08020c21, 0x02000401, 0x02000c01, 0x02020401, 0x02020c01, ++ 0x02000421, 0x02000c21, 0x02020421, 0x02020c21, 0x0a000401, 0x0a000c01, ++ 0x0a020401, 0x0a020c01, 0x0a000421, 0x0a000c21, 0x0a020421, 0x0a020c21, ++ 0x00100001, 0x00100801, 0x00120001, 0x00120801, 0x00100021, 0x00100821, ++ 0x00120021, 0x00120821, 0x08100001, 0x08100801, 0x08120001, 0x08120801, ++ 0x08100021, 0x08100821, 0x08120021, 0x08120821, 0x02100001, 0x02100801, ++ 0x02120001, 0x02120801, 0x02100021, 0x02100821, 0x02120021, 0x02120821, ++ 0x0a100001, 0x0a100801, 0x0a120001, 0x0a120801, 0x0a100021, 0x0a100821, ++ 0x0a120021, 0x0a120821, 0x00100401, 0x00100c01, 0x00120401, 0x00120c01, ++ 0x00100421, 0x00100c21, 0x00120421, 0x00120c21, 0x08100401, 0x08100c01, ++ 0x08120401, 0x08120c01, 0x08100421, 0x08100c21, 0x08120421, 0x08120c21, ++ 0x02100401, 0x02100c01, 0x02120401, 0x02120c01, 0x02100421, 0x02100c21, ++ 0x02120421, 0x02120c21, 0x0a100401, 0x0a100c01, 0x0a120401, 0x0a120c01, ++ 0x0a100421, 0x0a100c21, 0x0a120421, 0x0a120c21, ++ }, ++}; +diff --git a/configure.ac b/configure.ac +index 9846e3f..f843b51 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -24,7 +24,6 @@ AH_BOTTOM( + # Checks for programs. + AC_CANONICAL_HOST + AC_PROG_CC +-AX_PROG_CC_FOR_BUILD + + # Dependencies + PKG_PROG_PKG_CONFIG +diff --git a/gen-des-tables.c b/gen-des-tables.c +index cf2b76f..ee18cd4 100644 +--- a/gen-des-tables.c ++++ b/gen-des-tables.c +@@ -40,6 +40,12 @@ + * by David Burren . + */ + ++/* ++ * This program can regenerate the tables in alg-des-tables.c. ++ * It is preserved as documentation, but it should no longer be ++ * necessary to run it. ++ */ ++ + #include "crypt-port.h" + + #include +@@ -341,11 +347,6 @@ main(void) + { + des_init(); + +- puts("/* Generated by gen-des-tables. DO NOT EDIT. */\n" +- "\n" +- "#include \"crypt-port.h\"\n" +- "#include \"alg-des.h\""); +- + write_table_u8(4, 4096, &m_sbox_[0][0], "m_sbox"); + + write_table_u32(8, 256, &ip_maskl_[0][0], "ip_maskl"); +diff --git a/m4/ax_prog_cc_for_build.m4 b/m4/ax_prog_cc_for_build.m4 +deleted file mode 100644 +index ac6043a..0000000 +--- a/m4/ax_prog_cc_for_build.m4 ++++ /dev/null +@@ -1,158 +0,0 @@ +-# =========================================================================== +-# https://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +-# =========================================================================== +-# +-# SYNOPSIS +-# +-# AX_PROG_CC_FOR_BUILD +-# +-# DESCRIPTION +-# +-# This macro searches for a C compiler that generates native executables, +-# that is a C compiler that surely is not a cross-compiler. This can be +-# useful if you have to generate source code at compile-time like for +-# example GCC does. +-# +-# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +-# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +-# The value of these variables can be overridden by the user by specifying +-# a compiler with an environment variable (like you do for standard CC). +-# +-# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +-# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +-# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +-# substituted in the Makefile. +-# +-# LICENSE +-# +-# Copyright (c) 2008 Paolo Bonzini +-# +-# Copying and distribution of this file, with or without modification, are +-# permitted in any medium without royalty provided the copyright notice +-# and this notice are preserved. This file is offered as-is, without any +-# warranty. +- +-#serial 9 +- +-AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +-AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +-AC_REQUIRE([AC_PROG_CC])dnl +-AC_REQUIRE([AC_PROG_CPP])dnl +-AC_REQUIRE([AC_EXEEXT])dnl +-AC_REQUIRE([AC_CANONICAL_HOST])dnl +- +-dnl Use the standard macros, but make them use other variable names +-dnl +-pushdef([_AC_LANG_ABBREV], [build_c])dnl +-pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +-pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +-pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +-pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +-pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +-pushdef([ac_cv_prog_cc_stdc], ac_cv_build_prog_cc_stdc)dnl +-pushdef([ac_cv_prog_cc_c11], ac_cv_build_prog_cc_c11)dnl +-pushdef([ac_cv_prog_cc_c99], ac_cv_build_prog_cc_c99)dnl +-pushdef([ac_prog_cc_stdc], ac_build_prog_cc_stdc)dnl +-pushdef([am_cv_CC_dependencies_compiler_type], +- am_cv_build_CC_depencies_compiler_type)dnl +-pushdef([am_cv_prog_cc_c_o], am_cv_build_prog_cc_c_o)dnl +-pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +-pushdef([ac_cv_objext], ac_cv_build_objext)dnl +-pushdef([ac_exeext], ac_build_exeext)dnl +-pushdef([ac_objext], ac_build_objext)dnl +-pushdef([CC], CC_FOR_BUILD)dnl +-pushdef([CPP], CPP_FOR_BUILD)dnl +-pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +-pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +-pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +-pushdef([host], build)dnl +-pushdef([host_alias], build_alias)dnl +-pushdef([host_cpu], build_cpu)dnl +-pushdef([host_vendor], build_vendor)dnl +-pushdef([host_os], build_os)dnl +-pushdef([ac_cv_host], ac_cv_build)dnl +-pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +-pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +-pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +-pushdef([ac_cv_host_os], ac_cv_build_os)dnl +-pushdef([ac_cpp], ac_build_cpp)dnl +-pushdef([ac_compile], ac_build_compile)dnl +-pushdef([ac_link], ac_build_link)dnl +- +-dnl Shim the shell functions used by AC_COMPILE_IFELSE etc. +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_try_cpp], +- [# Forward ac_fn_build_c_* to ac_fn_c_*.], +- [ac_fn_c_try_cpp "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_try_compile],,[ac_fn_c_try_compile "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_try_link],,[ac_fn_c_try_link "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_try_run],,[ac_fn_c_try_run "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_decl],,[ac_fn_c_check_decl "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_func],,[ac_fn_c_check_func "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_header_mongrel],,[ac_fn_c_check_header_mongrel "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_header_compile],,[ac_fn_c_check_header_compile "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_header_preproc],,[ac_fn_c_check_header_preproc "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_member],,[ac_fn_c_check_member "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_check_type],,[ac_fn_c_check_type "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_compute_int],,[ac_fn_c_compute_int "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_find_intX_t],,[ac_fn_c_find_intX_t "$][@"]) +-AC_REQUIRE_SHELL_FN([ac_fn_build_c_find_uintX_t],,[ac_fn_c_find_uintX_t "$][@"]) +- +-save_cross_compiling=$cross_compiling +-save_ac_tool_prefix=$ac_tool_prefix +-cross_compiling=no +-ac_tool_prefix= +- +-AC_PROG_CC +-AC_PROG_CPP +-AC_EXEEXT +- +-ac_tool_prefix=$save_ac_tool_prefix +-cross_compiling=$save_cross_compiling +- +-dnl Restore the old definitions +-dnl +-popdef([ac_link])dnl +-popdef([ac_compile])dnl +-popdef([ac_cpp])dnl +-popdef([ac_cv_host_os])dnl +-popdef([ac_cv_host_vendor])dnl +-popdef([ac_cv_host_cpu])dnl +-popdef([ac_cv_host_alias])dnl +-popdef([ac_cv_host])dnl +-popdef([host_os])dnl +-popdef([host_vendor])dnl +-popdef([host_cpu])dnl +-popdef([host_alias])dnl +-popdef([host])dnl +-popdef([LDFLAGS])dnl +-popdef([CPPFLAGS])dnl +-popdef([CFLAGS])dnl +-popdef([CPP])dnl +-popdef([CC])dnl +-popdef([ac_objext])dnl +-popdef([ac_exeext])dnl +-popdef([ac_cv_objext])dnl +-popdef([ac_cv_exeext])dnl +-popdef([am_cv_prog_cc_c_o])dnl +-popdef([am_cv_CC_dependencies_compiler_type])dnl +-popdef([ac_prog_cc_stdc])dnl +-popdef([ac_cv_prog_cc_c99])dnl +-popdef([ac_cv_prog_cc_c11])dnl +-popdef([ac_cv_prog_cc_stdc])dnl +-popdef([ac_cv_prog_cc_g])dnl +-popdef([ac_cv_prog_cc_cross])dnl +-popdef([ac_cv_prog_cc_works])dnl +-popdef([ac_cv_prog_gcc])dnl +-popdef([ac_cv_prog_CPP])dnl +-popdef([_AC_LANG_ABBREV])dnl +- +-dnl Finally, set Makefile variables +-dnl +-BUILD_EXEEXT=$ac_build_exeext +-BUILD_OBJEXT=$ac_build_objext +-AC_SUBST(BUILD_EXEEXT)dnl +-AC_SUBST(BUILD_OBJEXT)dnl +-AC_SUBST([CFLAGS_FOR_BUILD])dnl +-AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +-AC_SUBST([LDFLAGS_FOR_BUILD])dnl +-]) + +From ed4be6afa7b34fe0d827cc3f7f9608de0d9325cd Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Wed, 4 Jul 2018 21:42:36 -0400 +Subject: [PATCH 15/38] Make it possible to disable individual hashes at + configure time. + +The table of supported hash algorithms now lives in hashes.lst. +The configure script accepts an option --enable-hashes which takes a +comma-separated list of hash algorithms to include. We generate a +header that defines INCLUDE_ macros for each hash that is enabled, +and all of the code is conditionalized appropriately. + +The default is --enable-hashes=all. --enable-hashes=strong is the +equivalent of the old --disable-weak-hashes. You could even do +--enable-hashes=bcrypt,des to get a binary-compatible libcrypt.so.1 +that still supports almost nothing other than bcrypt. +--- + .gitignore | 1 + + Makefile.am | 63 +++++++++---------- + README.md | 12 ++-- + alg-des-tables.c | 4 ++ + alg-des.c | 5 ++ + alg-hmac-sha1.c | 4 ++ + alg-md4.c | 4 ++ + alg-md5.c | 3 + + alg-sha1.c | 3 + + alg-sha256.c | 3 + + alg-sha512.c | 3 + + configure.ac | 59 ++++++++--------- + crypt-bcrypt.c | 4 ++ + crypt-des.c | 61 ++++++++++-------- + crypt-gensalt.c | 4 ++ + crypt-md5.c | 3 + + crypt-nthash.c | 4 ++ + crypt-pbkdf1-sha1.c | 4 ++ + crypt-port.h | 74 +++++++++++----------- + crypt-private.h | 82 ------------------------ + crypt-sha256.c | 3 + + crypt-sha512.c | 3 + + crypt-sunmd5.c | 5 ++ + crypt.c | 94 +++++++++------------------- + gen-hashes.awk | 160 +++++++++++++++++++++++++++++++++++++++++++++++ + hashes.lst | 40 ++++++++++++ + sel-hashes.awk | 89 ++++++++++++++++++++++++++ + test-alg-des.c | 12 ++++ + test-alg-hmac-sha1.c | 12 ++++ + test-alg-md4.c | 12 ++++ + test-alg-md5.c | 12 ++++ + test-alg-sha1.c | 12 ++++ + test-alg-sha256.c | 12 ++++ + test-alg-sha512.c | 12 ++++ + test-crypt-badsalt.c | 2 + + test-crypt-bcrypt.c | 12 ++++ + test-crypt-des.c | 18 +++++- + test-crypt-md5.c | 12 ++++ + test-crypt-nthash.c | 12 ++++ + test-crypt-pbkdf1-sha1.c | 12 ++++ + test-crypt-sha256.c | 12 ++++ + test-crypt-sha512.c | 12 ++++ + test-crypt-sunmd5.c | 12 ++++ + test-gensalt.c | 61 +++++++++++++----- + 44 files changed, 745 insertions(+), 298 deletions(-) + create mode 100644 gen-hashes.awk + create mode 100644 hashes.lst + create mode 100644 sel-hashes.awk + +diff --git a/.gitignore b/.gitignore +index 5e998dd..9f443bd 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -43,6 +43,7 @@ + *.so + *.trs + /crypt.h ++/crypt-hashes.h + /crypt-symbol-vers.h + /libcrypt.map + /test-alg-des +diff --git a/Makefile.am b/Makefile.am +index 71fbd62..040d719 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -12,12 +12,14 @@ AM_CFLAGS = $(WARN_CFLAGS) + EXTRA_DIST = \ + LICENSING THANKS \ + libcrypt.map.in libcrypt.minver \ +- gen-map.awk gen-vers.awk gen-crypt-h.awk ++ gen-map.awk gen-vers.awk gen-crypt-h.awk \ ++ gen-hashes.awk sel-hashes.awk hashes.lst + + notrans_dist_man3_MANS = crypt_rn.3 crypt_gensalt.3 + notrans_dist_man5_MANS = crypt.5 + + nodist_include_HEADERS = crypt.h ++nodist_noinst_HEADERS = crypt-hashes.h + noinst_HEADERS = \ + alg-des.h alg-hmac-sha1.h alg-md4.h alg-md5.h \ + alg-sha1.h alg-sha256.h alg-sha512.h byteorder.h \ +@@ -26,9 +28,12 @@ noinst_HEADERS = \ + + lib_LTLIBRARIES = libcrypt.la + libcrypt_la_SOURCES = \ +- crypt.c crypt-static.c crypt-gensalt.c crypt-gensalt-static.c \ +- crypt-bcrypt.c crypt-sha512.c crypt-sha256.c \ +- alg-sha512.c alg-sha256.c randombytes.c ++ alg-des.c alg-des-tables.c alg-hmac-sha1.c alg-md4.c alg-md5.c \ ++ alg-sha1.c alg-sha256.c alg-sha512.c \ ++ crypt.c crypt-bcrypt.c crypt-des.c crypt-gensalt-static.c \ ++ crypt-gensalt.c crypt-md5.c crypt-nthash.c crypt-pbkdf1-sha1.c \ ++ crypt-sha256.c crypt-sha512.c crypt-static.c crypt-sunmd5.c \ ++ randombytes.c + + pkgconfig_DATA = libxcrypt.pc + +@@ -49,6 +54,7 @@ CONFIG_STATUS_DEPENDENCIES = libcrypt.minver + EXTRA_libcrypt_la_DEPENDENCIES = libcrypt.map + CLEANFILES = libcrypt.map libcrypt.map.T \ + crypt-symbol-vers.h crypt-symbol-vers.h.T \ ++ crypt-hashes.h crypt-hashes.h.T \ + crypt.h crypt.h.T + + libcrypt.map: libcrypt.map.in gen-map.awk Makefile +@@ -70,6 +76,12 @@ crypt.h: crypt-base.h gen-crypt-h.awk config.h + > crypt.h.T + $(AM_V_at)mv -f crypt.h.T crypt.h + ++crypt-hashes.h: hashes.lst gen-hashes.awk Makefile ++ $(AM_V_GEN)LC_ALL=C $(AWK) -f $(srcdir)/gen-hashes.awk \ ++ -v ENABLED_HASHES=$(hashes_enabled) \ ++ $(srcdir)/hashes.lst > crypt-hashes.h.T ++ $(AM_V_at)mv -f crypt-hashes.h.T crypt-hashes.h ++ + # When we are being binary compatible, also install symbolic links to + # mimic SUSE's libowcrypt; any program that uses -lowcrypt in its + # build, or already has a NEEDED entry for libowcrypt.so.1, will be +@@ -108,30 +120,13 @@ endif + endif + + check_PROGRAMS = \ +- test-alg-sha256 test-alg-sha512 \ +- test-crypt-sha256 test-crypt-sha512 test-crypt-bcrypt \ +- test-crypt-nonnull test-byteorder test-gensalt +- +-if ENABLE_WEAK_HASHES +-libcrypt_la_SOURCES += \ +- crypt-des.c crypt-md5.c alg-des.c alg-des-tables.c alg-md5.c +- +-if ENABLE_WEAK_NON_GLIBC_HASHES +-libcrypt_la_SOURCES += \ +- crypt-nthash.c crypt-pbkdf1-sha1.c crypt-sunmd5.c \ +- alg-hmac-sha1.c alg-md4.c alg-sha1.c +-endif +- +-check_PROGRAMS += \ +- test-alg-des test-alg-md5 test-crypt-des test-crypt-md5 \ +- test-crypt-badsalt +- +-if ENABLE_WEAK_NON_GLIBC_HASHES +-check_PROGRAMS += \ +- test-alg-hmac-sha1 test-alg-md4 test-alg-sha1 \ +- test-crypt-nthash test-crypt-sunmd5 test-crypt-pbkdf1-sha1 +-endif +-endif ++ test-alg-des test-alg-hmac-sha1 test-alg-md4 test-alg-md5 \ ++ test-alg-sha1 test-alg-sha256 test-alg-sha512 \ ++ test-crypt-badsalt test-crypt-bcrypt test-crypt-des \ ++ test-crypt-md5 test-crypt-nonnull test-crypt-nthash \ ++ test-crypt-pbkdf1-sha1 test-crypt-sha256 test-crypt-sha512 \ ++ test-crypt-sunmd5 \ ++ test-byteorder test-gensalt + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +@@ -187,7 +182,11 @@ test_alg_sha256_LDADD = alg-sha256.lo + test_alg_sha512_LDADD = alg-sha512.lo + + +-# Every object file in the library depends on crypt-symbol-vers.h, +-# which is a generated file, so automatic dependency generation will +-# not detect it. +-$(libcrypt_la_OBJECTS): crypt-symbol-vers.h ++# Every object file depends on crypt-symbol-vers.h and crypt-hashes.h, ++# which are generated files, so automatic dependency generation is not ++# sufficient. Most of the test programs depend on either libcrypt.la ++# or one of its components, so they do not need an explicit dependency ++# (after the first *successful* build, automatic dependency generation ++# will reveal the direct dependency) but a few don't. ++$(libcrypt_la_OBJECTS): crypt-symbol-vers.h crypt-hashes.h ++$(test_byteorder_OBJECTS): crypt-symbol-vers.h crypt-hashes.h +diff --git a/README.md b/README.md +index 869d46f..9211a33 100644 +--- a/README.md ++++ b/README.md +@@ -92,11 +92,13 @@ Linux. We are willing to consider adding binary backward + compatibility for other operating systems' existing libcrypts, but we + don't currently plan to do that work ourselves. + +-It is also possible to remove support for DES, MD5, NTHASH and SUNMD5 +-password hashes, by supplying the `--disable-weak-hashes` switch to +-`configure`. This option implies `--disable-obsolete-api`. It should +-only be used in contexts where there are definitely no user accounts +-that are old enough to have stored their password with an old hash. ++Individual hash functions may be enabled or disabled by use of the ++`--enable-hashes` switch to `configure`. The default is to enable all ++supported hashes. Disabling the traditional 'des' hash algorithm ++implies `--disable-obsolete-api`. Security-conscious environments ++without backward compatibility constraints are encouraged to use ++`--enable-hashes=strong`, which enables only the hash functions that ++are strong enough to be safe for newly hashed passwords. + + The original implementation of the SUNMD5 hashing algorithm has a bug, + which is mimicked by libxcrypt to be fully compatible with hashes +diff --git a/alg-des-tables.c b/alg-des-tables.c +index 0bf9c88..c46d1c4 100644 +--- a/alg-des-tables.c ++++ b/alg-des-tables.c +@@ -49,6 +49,8 @@ + #include "crypt-port.h" + #include "alg-des.h" + ++#if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big ++ + const uint8_t m_sbox[4][4096] = { + { + 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, 0xe6, 0xef, 0xeb, 0xe2, +@@ -3842,3 +3844,5 @@ const uint32_t psbox[4][256] = { + 0x0a100421, 0x0a100c21, 0x0a120421, 0x0a120c21, + }, + }; ++ ++#endif +diff --git a/alg-des.c b/alg-des.c +index 3e62fe2..959d0f7 100644 +--- a/alg-des.c ++++ b/alg-des.c +@@ -59,6 +59,9 @@ + */ + + #include "crypt-port.h" ++ ++#if INCLUDE_des || INCLUDE_des_big || INCLUDE_des_xbsd ++ + #include "alg-des.h" + #include "byteorder.h" + +@@ -261,3 +264,5 @@ des_crypt_block (struct des_ctx *restrict ctx, + cpu_to_be32 (out, l_out); + cpu_to_be32 (out + 4, r_out); + } ++ ++#endif +diff --git a/alg-hmac-sha1.c b/alg-hmac-sha1.c +index 2940774..0b22163 100644 +--- a/alg-hmac-sha1.c ++++ b/alg-hmac-sha1.c +@@ -37,6 +37,8 @@ + + #include + ++#if INCLUDE_sha1 ++ + /* Don't change these */ + #define HMAC_IPAD 0x36 + #define HMAC_OPAD 0x5c +@@ -125,3 +127,5 @@ hmac_sha1_process_data (const uint8_t *text, size_t text_len, + sha1_process_bytes (resbuf, &ctx, HASH_LENGTH); + sha1_finish_ctx(&ctx, resbuf); + } ++ ++#endif +diff --git a/alg-md4.c b/alg-md4.c +index 56367df..ce62490 100644 +--- a/alg-md4.c ++++ b/alg-md4.c +@@ -19,6 +19,8 @@ + #include "alg-md4.h" + #include "byteorder.h" + ++#if INCLUDE_nthash ++ + /* + * The basic MD4 functions. + */ +@@ -250,3 +252,5 @@ md4_finish_ctx (struct md4_ctx *ctx, void *resbuf) + + return md4_read_ctx (ctx, resbuf); + } ++ ++#endif +diff --git a/alg-md5.c b/alg-md5.c +index e9b3412..df49fc6 100644 +--- a/alg-md5.c ++++ b/alg-md5.c +@@ -23,6 +23,7 @@ + #include "alg-md5.h" + #include "byteorder.h" + ++#if INCLUDE_md5 || INCLUDE_sunmd5 + + static void md5_process_block (const void *buffer, size_t len, + struct md5_ctx *ctx); +@@ -303,3 +304,5 @@ md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) + ctx->C = C; + ctx->D = D; + } ++ ++#endif +diff --git a/alg-sha1.c b/alg-sha1.c +index 13ff75a..421ffbd 100644 +--- a/alg-sha1.c ++++ b/alg-sha1.c +@@ -72,6 +72,7 @@ modified for use with libxcrypt + #include "crypt-port.h" + #include "alg-sha1.h" + ++#if INCLUDE_sha1 + + #define SHA1_DIGEST_SIZE 20 + +@@ -278,3 +279,5 @@ sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) + + return resbuf; + } ++ ++#endif +diff --git a/alg-sha256.c b/alg-sha256.c +index d4921a5..713385d 100644 +--- a/alg-sha256.c ++++ b/alg-sha256.c +@@ -22,6 +22,7 @@ + #include "alg-sha256.h" + #include "byteorder.h" + ++#if INCLUDE_sha256 + + /* Constants for SHA256 from FIPS 180-2:4.2.2. */ + static const uint32_t K[64] = +@@ -251,3 +252,5 @@ sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) + ctx->buflen = (uint32_t)left_over; + } + } ++ ++#endif +diff --git a/alg-sha512.c b/alg-sha512.c +index 5010bc4..6a6aab2 100644 +--- a/alg-sha512.c ++++ b/alg-sha512.c +@@ -22,6 +22,7 @@ + #include "alg-sha512.h" + #include "byteorder.h" + ++#if INCLUDE_sha512 + + /* Constants for SHA512 from FIPS 180-2:4.2.3. */ + static const uint64_t K[80] = +@@ -284,3 +285,5 @@ sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) + ctx->buflen = (uint32_t)left_over; + } + } ++ ++#endif +diff --git a/configure.ac b/configure.ac +index f843b51..119f171 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -201,35 +201,35 @@ AC_ARG_ENABLE([obsolete-api], + [enable_obsolete_api=1] + ) + +-AC_ARG_ENABLE([weak-hashes], ++AC_ARG_ENABLE([hashes], + AS_HELP_STRING( +- [--enable-weak-hashes[=ARG]], +- [When set to "yes", all of the hashing methods documented in crypt(5) +- are supported for authenticating existing password hashes, including +- several that are too weak to use for new passwords. +- +- When set to "glibc", only the weak hashes supported by historic +- versions of GNU libc are supported: traditional DES and FreeBSD-style +- MD5, but not bigcrypt-DES, BSDi extended DES, SHA1, SUNMD5, or NTHASH. +- +- When set to "no", only bcrypt, SHA512, and SHA256 are supported. +- This mode implies --disable-obsolete-api and breaks binary +- compatibility with glibc's libcrypt. +- +- [default=yes]] ++ [--enable-hashes=HASHES], ++ [Select hash algorithms to support. Acceptable values are ++ 'all' or a comma-separated list of names from the file ++ 'hashes.lst' and/or the keywords 'strong' and 'glibc', which ++ select groups of hashes as described in that file. The ++ default is 'all'. Note: if binary compatibility with glibc's ++ libcrypt is desired, the 'des' hash must be enabled.] + ), +- [case "${enableval}" in +- yes) enable_weak_hashes=1; enable_weak_non_glibc_hashes=1 ;; +- glibc) enable_weak_hashes=1; enable_weak_non_glibc_hashes=0 ;; +- no) enable_weak_hashes=0; enable_weak_non_glibc_hashes=0 ;; +- *) AC_MSG_ERROR([bad value ${enableval} for --enable-weak-hashes]) ;; +- esac], +- [enable_weak_hashes=1; enable_weak_non_glibc_hashes=1] ++ [hashes_selected=$enableval], ++ [hashes_selected=all] + ) ++# This code must run after AC_PROG_AWK. ++hashes_enabled=$( ++ $AWK -f ${srcdir}/sel-hashes.awk -v SELECTED_HASHES="$hashes_selected" \ ++ ${srcdir}/hashes.lst ++) ++if test x"$hashes_enabled" = x || test x"$hashes_enabled" = x,; then ++ AC_MSG_ERROR([bad value '${hashes_selected}' for --enable-hashes]) ++fi ++AC_SUBST([hashes_enabled]) + +-# If weak hashes are disabled, then the obsolete APIs won't work anyway +-# (they're all DES-specific). +-if test $enable_weak_hashes = 0; then enable_obsolete_api=0; fi ++# If the traditional DES hash is disabled, then the obsolete APIs are ++# implicitly disabled. ++case "$hashes_enabled" in ++ *,des,*) ;; ++ *) enable_obsolete_api=0 ;; ++esac + + # The obsolete APIs are unconditionally excluded from the static library, + # so if we are not building the shared library, we are effectively not +@@ -298,15 +298,6 @@ AC_DEFINE_UNQUOTED([ENABLE_OBSOLETE_API], [$enable_obsolete_api], + should be included, 0 otherwise.]) + AM_CONDITIONAL([ENABLE_OBSOLETE_API], [test $enable_obsolete_api = 1]) + +-AC_DEFINE_UNQUOTED([ENABLE_WEAK_HASHES], [$enable_weak_hashes], +- [Define as 1 if weak hashes (DES, MD5) should be included, 0 otherwise. +- If this is 0, ENABLE_OBSOLETE_API must also be 0.]) +-AM_CONDITIONAL([ENABLE_WEAK_HASHES], [test $enable_weak_hashes = 1]) +- +-AC_DEFINE_UNQUOTED([ENABLE_WEAK_NON_GLIBC_HASHES], [$enable_weak_non_glibc_hashes], +- [Define as 1 if weak hashes not supported by glibc should be included, 0 otherwise.]) +-AM_CONDITIONAL([ENABLE_WEAK_NON_GLIBC_HASHES], [test $enable_weak_non_glibc_hashes = 1]) +- + # The Makefile needs to know which versions of the library we are building. + AM_CONDITIONAL([ENABLE_STATIC], [test $enable_static = yes]) + AM_CONDITIONAL([ENABLE_SHARED], [test $enable_shared = yes]) +diff --git a/crypt-bcrypt.c b/crypt-bcrypt.c +index f41a893..d468399 100644 +--- a/crypt-bcrypt.c ++++ b/crypt-bcrypt.c +@@ -50,6 +50,8 @@ + #include + #include + ++#if INCLUDE_bcrypt ++ + #if defined(__i386__) || defined(__x86_64__) || \ + defined(__alpha__) || defined(__hppa__) + #define BF_SCALE 1 +@@ -1007,3 +1009,5 @@ gensalt_bcrypt_y_rn (unsigned long count, + { + BF_gensalt ('y', count, rbytes, nrbytes, output, o_size); + } ++ ++#endif +diff --git a/crypt-des.c b/crypt-des.c +index 79b3144..3d8bc2e 100644 +--- a/crypt-des.c ++++ b/crypt-des.c +@@ -49,6 +49,8 @@ + + #include + ++#if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big ++ + #define DES_TRD_OUTPUT_LEN 14 /* SShhhhhhhhhhh0 */ + #define DES_EXT_OUTPUT_LEN 21 /* _CCCCSSSShhhhhhhhhhh0 */ + #define DES_BIG_OUTPUT_LEN ((16*11) + 2 + 1) /* SS (hhhhhhhhhhh){1,16} 0 */ +@@ -142,15 +144,14 @@ des_gen_hash (struct des_ctx *ctx, uint32_t count, uint8_t *output, + while (sptr < end); + *output = '\0'; + } ++#endif + ++#if INCLUDE_des + /* The original UNIX DES-based password hash, no extensions. */ +-#if ENABLE_WEAK_NON_GLIBC_HASHES +-static +-#endif + void +-crypt_des_trd_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size) ++crypt_des_rn (const char *phrase, const char *setting, ++ uint8_t *output, size_t o_size, ++ void *scratch, size_t s_size) + { + /* This shouldn't ever happen, but... */ + if (o_size < DES_TRD_OUTPUT_LEN || s_size < sizeof (struct des_buffer)) +@@ -194,8 +195,9 @@ crypt_des_trd_rn (const char *phrase, const char *setting, + des_set_salt (ctx, salt); + des_gen_hash (ctx, 25, cp, pkbuf); + } ++#endif + +-#if ENABLE_WEAK_NON_GLIBC_HASHES ++#if INCLUDE_des_big + /* This algorithm is algorithm 0 (default) shipped with the C2 secure + implementation of Digital UNIX. + +@@ -212,11 +214,23 @@ crypt_des_trd_rn (const char *phrase, const char *setting, + (that is, the password can be no more than 128 characters long). + + Andy Phillips */ +-static void ++void + crypt_des_big_rn (const char *phrase, const char *setting, + uint8_t *output, size_t o_size, + void *scratch, size_t s_size) + { ++#if INCLUDE_des ++ /* For backward compatibility, if the setting string is short enough ++ to have been generated by the traditional DES algorithm, forward ++ to traditional DES (which means that only the first 8 characters ++ of 'phrase' are significant). */ ++ if (strlen (setting) <= 13) ++ { ++ crypt_des_rn (phrase, setting, output, o_size, scratch, s_size); ++ return; ++ } ++#endif ++ + /* This shouldn't ever happen, but... */ + if (o_size < DES_BIG_OUTPUT_LEN || s_size < sizeof (struct des_buffer)) + { +@@ -264,19 +278,9 @@ crypt_des_big_rn (const char *phrase, const char *setting, + cp += 11; + } + } ++#endif + +-/* crypt_rn() entry point for both the original UNIX password hash, +- with its 8-character length limit, and the Digital UNIX "bigcrypt" +- extension to permit longer passwords. */ +-void +-crypt_des_trd_or_big_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size) +-{ +- (strlen (setting) > 13 ? crypt_des_big_rn : crypt_des_trd_rn) +- (phrase, setting, output, o_size, scratch, s_size); +-} +- ++#if INCLUDE_des_xbsd + /* crypt_rn() entry point for BSD-style extended DES hashes. These + permit long passwords and have more salt and a controllable iteration + count, but are still unacceptably weak by modern standards. */ +@@ -346,12 +350,13 @@ crypt_des_xbsd_rn (const char *phrase, const char *setting, + des_set_salt (ctx, salt); + des_gen_hash (ctx, count, cp, pkbuf); + } +-#endif /* ENABLE_WEAK_NON_GLIBC_HASHES */ ++#endif + ++#if INCLUDE_des || INCLUDE_des_big + void +-gensalt_des_trd_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t output_size) ++gensalt_des_rn (unsigned long count, ++ const uint8_t *rbytes, size_t nrbytes, ++ uint8_t *output, size_t output_size) + { + if (output_size < 3) + { +@@ -369,8 +374,12 @@ gensalt_des_trd_rn (unsigned long count, + output[1] = ascii64[(unsigned int) rbytes[1] & 0x3f]; + output[2] = '\0'; + } ++#if INCLUDE_des_big ++strong_alias (gensalt_des_rn, gensalt_des_big_rn); ++#endif ++#endif + +-#if ENABLE_WEAK_NON_GLIBC_HASHES ++#if INCLUDE_des_xbsd + void + gensalt_des_xbsd_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, +@@ -412,4 +421,4 @@ gensalt_des_xbsd_rn (unsigned long count, + + output[9] = '\0'; + } +-#endif /* ENABLE_WEAK_NON_GLIBC_HASHES */ ++#endif +diff --git a/crypt-gensalt.c b/crypt-gensalt.c +index cfd596c..fb5b12c 100644 +--- a/crypt-gensalt.c ++++ b/crypt-gensalt.c +@@ -14,6 +14,8 @@ + #include + #include + ++#if INCLUDE_sha256 || INCLUDE_sha512 ++ + static const unsigned char _xcrypt_itoa64[64 + 1] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -90,3 +92,5 @@ gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount, + + output[written] = '\0'; + } ++ ++#endif +diff --git a/crypt-md5.c b/crypt-md5.c +index 9ae22da..1a9139a 100644 +--- a/crypt-md5.c ++++ b/crypt-md5.c +@@ -23,6 +23,7 @@ + + #include + ++#if INCLUDE_md5 + + /* Define our magic string to mark salt for MD5 "encryption" + replacement. This is meant to be the same as for other MD5 based +@@ -216,3 +217,5 @@ gensalt_md5_rn (unsigned long count, + gensalt_sha_rn ('1', 8, 1000, 1000, 1000, + count, rbytes, nrbytes, output, output_size); + } ++ ++#endif +diff --git a/crypt-nthash.c b/crypt-nthash.c +index 9d43232..f9fee7b 100644 +--- a/crypt-nthash.c ++++ b/crypt-nthash.c +@@ -42,6 +42,8 @@ + #include + #include + ++#if INCLUDE_nthash ++ + /* + * NT HASH = md4(str2unicode(phrase)) + */ +@@ -145,3 +147,5 @@ gensalt_nthash_rn (unsigned long count, + memcpy (output, salt, 15); + memcpy (output + 15, hashstr, 14); + } ++ ++#endif +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index b55d233..544d890 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -35,6 +35,8 @@ + #include + #include + ++#if INCLUDE_sha1 ++ + /* + * The default iterations - should take >0s on a fast CPU + * but not be insane for a slow CPU. +@@ -258,3 +260,5 @@ gensalt_sha1_rn (unsigned long count, + output[n + (c * enclen)] = '$'; + output[n + (c * enclen) + 1] = '\0'; + } ++ ++#endif +diff --git a/crypt-port.h b/crypt-port.h +index 8b21f56..6d94b09 100644 +--- a/crypt-port.h ++++ b/crypt-port.h +@@ -191,69 +191,67 @@ void _xcrypt_secure_memset (void *s, size_t len) + #define symver_ref(extname, intname, version) \ + symver_set(extname, intname, version, "@") + ++/* Get the set of hash algorithms to be included and some related ++ definitions. */ ++#include "crypt-hashes.h" ++ ++ + /* Rename all of the internal-but-global symbols with a _crypt_ prefix + so that they do not interfere with other people's code when linking + statically. This list cannot be autogenerated, but is validated by + test-symbols.sh. */ + +-#define crypt_bcrypt_rn _crypt_crypt_bcrypt_rn +-#define gensalt_bcrypt_a_rn _crypt_gensalt_bcrypt_a_rn +-#define gensalt_bcrypt_b_rn _crypt_gensalt_bcrypt_b_rn +-#define gensalt_bcrypt_x_rn _crypt_gensalt_bcrypt_x_rn +-#define gensalt_bcrypt_y_rn _crypt_gensalt_bcrypt_y_rn +-#define gensalt_sha_rn _crypt_gensalt_sha_rn +-#define gensalt_sha256_rn _crypt_gensalt_sha256_rn +-#define gensalt_sha512_rn _crypt_gensalt_sha512_rn + #define get_random_bytes _crypt_get_random_bytes +-#define crypt_sha256_rn _crypt_crypt_sha256_rn +-#define crypt_sha512_rn _crypt_crypt_sha512_rn +-#define sha256_finish_ctx _crypt_sha256_finish_ctx +-#define sha256_init_ctx _crypt_sha256_init_ctx +-#define sha256_process_bytes _crypt_sha256_process_bytes +-#define sha512_finish_ctx _crypt_sha512_finish_ctx +-#define sha512_init_ctx _crypt_sha512_init_ctx +-#define sha512_process_bytes _crypt_sha512_process_bytes + +-#if ENABLE_WEAK_HASHES +-#define comp_maskl _crypt_comp_maskl +-#define comp_maskr _crypt_comp_maskr +-#if ENABLE_WEAK_NON_GLIBC_HASHES +-#define crypt_des_trd_or_big_rn _crypt_crypt_des_trd_or_big_rn +-#else +-#define crypt_des_trd_rn _crypt_crypt_des_trd_rn +-#endif +-#define crypt_des_xbsd_rn _crypt_crypt_des_xbsd_rn +-#define crypt_md5_rn _crypt_crypt_md5_rn +-#define crypt_nthash_rn _crypt_crypt_nthash_rn +-#define crypt_sha1_rn _crypt_crypt_sha1_rn +-#define crypt_sunmd5_rn _crypt_crypt_sunmd5_rn ++#if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big + #define des_crypt_block _crypt_des_crypt_block + #define des_set_key _crypt_des_set_key + #define des_set_salt _crypt_des_set_salt ++#define comp_maskl _crypt_comp_maskl ++#define comp_maskr _crypt_comp_maskr + #define fp_maskl _crypt_fp_maskl + #define fp_maskr _crypt_fp_maskr +-#define gensalt_des_trd_rn _crypt_gensalt_des_trd_rn +-#define gensalt_des_xbsd_rn _crypt_gensalt_des_xbsd_rn +-#define gensalt_md5_rn _crypt_gensalt_md5_rn +-#define gensalt_nthash_rn _crypt_gensalt_nthash_rn +-#define gensalt_sha1_rn _crypt_gensalt_sha1_rn +-#define gensalt_sunmd5_rn _crypt_gensalt_sunmd5_rn + #define ip_maskl _crypt_ip_maskl + #define ip_maskr _crypt_ip_maskr + #define key_perm_maskl _crypt_key_perm_maskl + #define key_perm_maskr _crypt_key_perm_maskr +-#define hmac_sha1_process_data _crypt_hmac_sha1_process_data ++#define m_sbox _crypt_m_sbox ++#define psbox _crypt_psbox ++#endif ++ ++#if INCLUDE_nthash + #define md4_finish_ctx _crypt_md4_finish_ctx + #define md4_init_ctx _crypt_md4_init_ctx + #define md4_process_bytes _crypt_md4_process_bytes ++#endif ++ ++#if INCLUDE_md5 || INCLUDE_sunmd5 + #define md5_finish_ctx _crypt_md5_finish_ctx + #define md5_init_ctx _crypt_md5_init_ctx + #define md5_process_bytes _crypt_md5_process_bytes +-#define m_sbox _crypt_m_sbox +-#define psbox _crypt_psbox ++#endif ++ ++#if INCLUDE_sha1 ++#define hmac_sha1_process_data _crypt_hmac_sha1_process_data + #define sha1_finish_ctx _crypt_sha1_finish_ctx + #define sha1_init_ctx _crypt_sha1_init_ctx + #define sha1_process_bytes _crypt_sha1_process_bytes + #endif + ++#if INCLUDE_sha256 ++#define sha256_finish_ctx _crypt_sha256_finish_ctx ++#define sha256_init_ctx _crypt_sha256_init_ctx ++#define sha256_process_bytes _crypt_sha256_process_bytes ++#endif ++ ++#if INCLUDE_sha512 ++#define sha512_finish_ctx _crypt_sha512_finish_ctx ++#define sha512_init_ctx _crypt_sha512_init_ctx ++#define sha512_process_bytes _crypt_sha512_process_bytes ++#endif ++ ++#if INCLUDE_sha256 || INCLUDE_sha512 ++#define gensalt_sha_rn _crypt_gensalt_sha_rn ++#endif ++ + #endif /* crypt-port.h */ +diff --git a/crypt-private.h b/crypt-private.h +index c5db3bd..7b2b232 100644 +--- a/crypt-private.h ++++ b/crypt-private.h +@@ -36,86 +36,4 @@ extern void gensalt_sha_rn (char tag, size_t maxsalt, unsigned long defcount, + this big. */ + #define ALG_SPECIFIC_SIZE 8192 + +-/* Individual hash functions */ +- +-#if ENABLE_WEAK_HASHES +-extern void crypt_md5_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-#if ENABLE_WEAK_NON_GLIBC_HASHES +-extern void crypt_des_trd_or_big_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_des_xbsd_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_nthash_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_sha1_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_sunmd5_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-#else +-extern void crypt_des_trd_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-#endif +-#endif +- +-extern void crypt_sha256_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_sha512_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +-extern void crypt_bcrypt_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size); +- +-#if ENABLE_WEAK_HASHES +-extern void gensalt_des_trd_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_md5_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-#if ENABLE_WEAK_NON_GLIBC_HASHES +-extern void gensalt_des_xbsd_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_nthash_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_sha1_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_sunmd5_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-#endif +-#endif +- +-extern void gensalt_sha256_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_sha512_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +- +-extern void gensalt_bcrypt_a_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_bcrypt_b_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_bcrypt_x_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +-extern void gensalt_bcrypt_y_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size); +- + #endif /* crypt-private.h */ +diff --git a/crypt-sha256.c b/crypt-sha256.c +index 9fc70e1..8b4ba67 100644 +--- a/crypt-sha256.c ++++ b/crypt-sha256.c +@@ -24,6 +24,7 @@ + #include + #include + ++#if INCLUDE_sha256 + + /* Define our magic string to mark salt for SHA256 "encryption" + replacement. */ +@@ -283,3 +284,5 @@ gensalt_sha256_rn (unsigned long count, + gensalt_sha_rn ('5', SALT_LEN_MAX, ROUNDS_DEFAULT, ROUNDS_MIN, ROUNDS_MAX, + count, rbytes, nrbytes, output, output_size); + } ++ ++#endif +diff --git a/crypt-sha512.c b/crypt-sha512.c +index b4473da..28e4f1c 100644 +--- a/crypt-sha512.c ++++ b/crypt-sha512.c +@@ -24,6 +24,7 @@ + #include + #include + ++#if INCLUDE_sha512 + + /* Define our magic string to mark salt for SHA512 "encryption" + replacement. */ +@@ -297,3 +298,5 @@ gensalt_sha512_rn (unsigned long count, + gensalt_sha_rn ('6', SALT_LEN_MAX, ROUNDS_DEFAULT, ROUNDS_MIN, ROUNDS_MAX, + count, rbytes, nrbytes, output, output_size); + } ++ ++#endif +diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c +index 43054b9..fcd3984 100644 +--- a/crypt-sunmd5.c ++++ b/crypt-sunmd5.c +@@ -32,6 +32,9 @@ + #include + #include + ++#if INCLUDE_sunmd5 ++ ++ + #define CRYPT_ALGNAME "md5" + + /* minimum number of rounds we do, not including the per-user ones */ +@@ -419,3 +422,5 @@ crypt_sunmd5_rn (const char *phrase, const char *setting, + p += 2; + *p = '\0'; + } ++ ++#endif +diff --git a/crypt.c b/crypt.c +index 12d50fd..e1bfc5b 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -70,6 +70,7 @@ typedef void (*gensalt_fn) (unsigned long count, + struct hashfn + { + const char *prefix; ++ size_t plen; + crypt_fn crypt; + gensalt_fn gensalt; + /* The type of this field is unsigned char to ensure that it cannot +@@ -77,54 +78,12 @@ struct hashfn + unsigned char nrbytes; + }; + +-/* This table should always begin with the algorithm that should be used +- for new encryptions. */ +-static const struct hashfn tagged_hashes[] = ++static const struct hashfn hash_algorithms[] = + { +- /* bcrypt */ +- { "$2b$", crypt_bcrypt_rn, gensalt_bcrypt_b_rn, 16 }, +- { "$2a$", crypt_bcrypt_rn, gensalt_bcrypt_a_rn, 16 }, +- { "$2x$", crypt_bcrypt_rn, gensalt_bcrypt_x_rn, 16 }, +- { "$2y$", crypt_bcrypt_rn, gensalt_bcrypt_y_rn, 16 }, +- +- /* legacy hashes */ +-#if ENABLE_WEAK_HASHES +- { "$1$", crypt_md5_rn, gensalt_md5_rn, 9 }, +-#if ENABLE_WEAK_NON_GLIBC_HASHES +- { "$3$", crypt_nthash_rn, gensalt_nthash_rn, 16 }, +- { "$md5", crypt_sunmd5_rn, gensalt_sunmd5_rn, 8 }, +- { "$sha1", crypt_sha1_rn, gensalt_sha1_rn, 48 }, +-#endif +-#endif +- { "$5$", crypt_sha256_rn, gensalt_sha256_rn, 15 }, +- { "$6$", crypt_sha512_rn, gensalt_sha512_rn, 15 }, +- { 0, 0, 0, 0 } +-}; +- +-#if ENABLE_WEAK_HASHES +-#if ENABLE_WEAK_NON_GLIBC_HASHES +-/* BSD-style extended DES */ +-static const struct hashfn bsdi_extended_hash = +-{ +- "_", crypt_des_xbsd_rn, gensalt_des_xbsd_rn, 3 +-}; +- +-/* Traditional DES or bigcrypt-style extended DES */ +-static const struct hashfn traditional_hash = +-{ +- "", crypt_des_trd_or_big_rn, gensalt_des_trd_rn, 2 ++ HASH_ALGORITHM_TABLE_ENTRIES + }; + +-#else +- +-/* Traditional DES */ +-static const struct hashfn traditional_hash = +-{ +- "", crypt_des_trd_rn, gensalt_des_trd_rn, 2 +-}; +- +-#endif +- ++#if INCLUDE_des || INCLUDE_des_big + static int + is_des_salt_char (char c) + { +@@ -133,30 +92,29 @@ is_des_salt_char (char c) + (c >= '0' && c <= '9') || + c == '.' || c == '/'); + } +-#endif /* ENABLE_WEAK_HASHES */ ++#endif + + static const struct hashfn * + get_hashfn (const char *setting) + { +- if (setting[0] == '$') ++ const struct hashfn *h; ++ for (h = hash_algorithms; h->prefix; h++) + { +- const struct hashfn *h; +- for (h = tagged_hashes; h->prefix; h++) +- if (!strncmp (setting, h->prefix, strlen (h->prefix))) +- return h; +- return 0; +- } +-#if ENABLE_WEAK_HASHES +-#if ENABLE_WEAK_NON_GLIBC_HASHES +- else if (setting[0] == '_') +- return &bsdi_extended_hash; +-#endif +- else if (setting[0] == '\0' || +- (is_des_salt_char (setting[0]) && is_des_salt_char (setting[1]))) +- return &traditional_hash; ++ if (h->plen > 0) ++ { ++ if (!strncmp (setting, h->prefix, h->plen)) ++ return h; ++ } ++#if INCLUDE_des || INCLUDE_des_big ++ else ++ { ++ if (setting[0] == '\0' || ++ (is_des_salt_char (setting[0]) && is_des_salt_char (setting[1]))) ++ return h; ++ } + #endif +- else +- return 0; ++ } ++ return 0; + } + + /* For historical reasons, crypt and crypt_r are not expected ever to +@@ -392,9 +350,15 @@ crypt_gensalt_rn (const char *prefix, unsigned long count, + + /* If the prefix is 0, that means to use the current best default. + Note that this is different from the behavior when the prefix is +- "", which selects DES. */ ++ "", which selects DES. HASH_ALGORITHM_DEFAULT is null when the ++ current default algorithm was disabled at configure time. */ + if (!prefix) +- prefix = tagged_hashes[0].prefix; ++ prefix = HASH_ALGORITHM_DEFAULT; ++ if (!prefix) ++ { ++ errno = EINVAL; ++ return 0; ++ } + + const struct hashfn *h = get_hashfn (prefix); + if (!h) +diff --git a/gen-hashes.awk b/gen-hashes.awk +new file mode 100644 +index 0000000..39faf8e +--- /dev/null ++++ b/gen-hashes.awk +@@ -0,0 +1,160 @@ ++# Generate crypt-hashes.h from hashes.lst and configure settings. ++# ++# Copyright 2018 Zack Weinberg ++# ++# This library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public License ++# as published by the Free Software Foundation; either version 2.1 of ++# the License, or (at your option) any later version. ++# ++# This library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with this library; if not, see ++# . ++ ++BEGIN { ++ default_prefix = ":" ++ next_output = 0 ++ error = 0 ++} ++ ++/^#/ { ++ next ++} ++ ++{ ++ if (!($1 in hash_enabled)) { ++ output_order[next_output++] = $1 ++ hash_enabled[$1] = 0 ++ } ++ if ($1 == ":") { ++ printf("%s:%d: name cannot be blank\n", FILENAME, NR) ++ error = 1 ++ } ++ if ($4 !~ /^[0-9]+$/ || $4 == 0) { ++ printf("%s:%d: nrbytes must be a positive integer\n", FILENAME, NR) ++ error = 1 ++ } ++ if ($2 == ":") $2 = "" ++ if ($3 == ":") $3 = "" ++ if ($5 == ":") $5 = "" ++ ++ crypt_fn = "crypt_" $1 "_rn" ++ gensalt_fn = "gensalt_" $1 $2 "_rn" ++ ++ if (!(crypt_fn in prototyped)) { ++ prototyped[crypt_fn] = 1 ++ renames[$1] = renames[$1] \ ++ "#define " crypt_fn " _crypt_" crypt_fn "\n" ++ prototypes[$1] = prototypes[$1] \ ++ "extern void " crypt_fn "\n " \ ++ "(const char *, const char *, uint8_t *, size_t, void *, size_t);\n" ++ } ++ if (!(gensalt_fn in prototyped)) { ++ prototyped[gensalt_fn] = 1 ++ renames[$1] = renames[$1] \ ++ "#define " gensalt_fn " _crypt_" gensalt_fn "\n" ++ prototypes[$1] = prototypes[$1] \ ++ "extern void " gensalt_fn "\n " \ ++ "(unsigned long, const uint8_t *, size_t, uint8_t *, size_t);\n" ++ } ++ ++ entry = sprintf(" { \"%s\", %d, %s, %s, %d }, \\\n", ++ $3, length($3), crypt_fn, gensalt_fn, $4) ++ table_entries[$1] = table_entries[$1] entry ++ ++ split($5, flags, ",") ++ for (i in flags) { ++ flag = flags[i] ++ if (flag == "DEFAULT") { ++ if (default_prefix == ":") { ++ default_hash = $1 ++ default_prefix = $3 ++ default_prefix_line = NR ++ } else { ++ printf("%s:%d: error: 'DEFAULT' specified twice\n", ++ FILENAME, NR) > "/dev/stderr" ++ printf("%s:%d: note: previous 'DEFAULT' was here\n", ++ FILENAME, default_prefix_line) > "/dev/stderr" ++ error = 1 ++ } ++ } else if (flag == "STRONG" || flag == "GLIBC") { ++ # handled in sel-hashes.awk ++ } else { ++ printf("%s:%d: unrecognized flag %s\n", FILENAME, NR, flag) \ ++ > "/dev/stderr" ++ error = 1 ++ } ++ } ++} ++ ++ ++END { ++ if (error) { ++ exit 1 ++ } ++ ++ # ENABLED_HASHES is set on the command line. ++ split(ENABLED_HASHES, enabled_hashes_list, ",") ++ for (i in enabled_hashes_list) { ++ h = enabled_hashes_list[i] ++ if (h != "") { ++ hash_enabled[h] = 1 ++ } ++ } ++ ++ if (default_prefix == ":") { ++ print "error: no default hash selected" > "/dev/stderr" ++ exit 1 ++ } ++ ++ print "/* Generated by genhashes.awk from hashes.lst. DO NOT EDIT. */" ++ print "" ++ print "#ifndef _CRYPT_HASHES_H" ++ print "#define _CRYPT_HASHES_H 1" ++ ++ print "" ++ for (i in output_order) { ++ hash = output_order[i] ++ printf("#define INCLUDE_%-8s %d\n", hash, hash_enabled[hash]) ++ } ++ ++ print "" ++ print "/* Internal symbol renames for static linkage, see crypt-port.h. */" ++ for (i in output_order) { ++ hash = output_order[i] ++ if (hash_enabled[hash]) { ++ print renames[hash] ++ } ++ } ++ ++ print "/* Prototypes for hash algorithm entry points. */" ++ for (i in output_order) { ++ hash = output_order[i] ++ if (hash_enabled[hash]) { ++ print prototypes[hash] ++ } ++ } ++ ++ print "#define HASH_ALGORITHM_TABLE_ENTRIES \\" ++ for (i in output_order) { ++ hash = output_order[i] ++ if (hash_enabled[hash]) { ++ printf("%s", table_entries[hash]) ++ } ++ } ++ print " { 0, 0, 0, 0, 0 }" ++ ++ print "" ++ if (hash_enabled[default_hash]) { ++ print "#define HASH_ALGORITHM_DEFAULT \"" default_prefix "\"" ++ } else { ++ print "#define HASH_ALGORITHM_DEFAULT 0" ++ } ++ print "" ++ print "#endif /* crypt-hashes.h */" ++} +diff --git a/hashes.lst b/hashes.lst +new file mode 100644 +index 0000000..488768f +--- /dev/null ++++ b/hashes.lst +@@ -0,0 +1,40 @@ ++# This file is read by genhashes.awk and by the configure script. ++# ++# It lists, for each supported hash algorithm, the name to be used to ++# enable or disable it at configure time, which is also part of the ++# name used for the 'crypt_fn' and 'gensalt_fn' entry points to the ++# relevant algorithm module; an optional suffix on the name of the ++# 'gensalt_fn'; the prefix used to identify the algorithm in hash ++# strings; the number of bytes of random data required to generate a ++# salt; and a set of flags. Currently there are three flags: DEFAULT ++# means this is the hash to use when no prefix was supplied to ++# crypt_gensalt, STRONG means the hash is still considered strong ++# enough to use for newly hashed passwords, and GLIBC means the hash ++# was historically supported by GNU libc's libcrypt. ++# ++# Fields are separated by whitespace. Lines beginning with # are ++# ignored; # is not otherwise significant. Multiple flags are ++# separated by commas. A field whose contents are a single colon (:) ++# is actually understood as an empty string; colon is used for this ++# purpose because it cannot be part of a hash prefix or a C identifier. ++# ++# Note: All entries with the same name should be consecutive. ++# ++# Note: crypt() checks prefixes in the order they appear in this file, ++# and the first match wins. Therefore, the empty prefix (traditional ++# DES) must be last. ++# ++#name gs_suffix h_prefix nrbytes flags ++bcrypt _b $2b$ 16 STRONG,DEFAULT ++bcrypt _a $2a$ 16 STRONG ++bcrypt _x $2x$ 16 STRONG ++bcrypt _y $2y$ 16 STRONG ++sha512 : $6$ 15 STRONG,GLIBC ++sha256 : $5$ 15 STRONG,GLIBC ++md5 : $1$ 9 GLIBC ++sunmd5 : $md5 8 : ++sha1 : $sha1 48 : ++nthash : $3$ 16 : ++des_xbsd : _ 3 : ++des_big : : 2 : ++des : : 2 GLIBC +diff --git a/sel-hashes.awk b/sel-hashes.awk +new file mode 100644 +index 0000000..c4edcbb +--- /dev/null ++++ b/sel-hashes.awk +@@ -0,0 +1,89 @@ ++# Expand a list of selected hashes to a list of enabled hashes, using ++# the information in hashes.lst. ++# ++# Copyright 2018 Zack Weinberg ++# ++# This library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public License ++# as published by the Free Software Foundation; either version 2.1 of ++# the License, or (at your option) any later version. ++# ++# This library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with this library; if not, see ++# . ++ ++BEGIN { ++ enable_all = 0 ++ enable_strong = 0 ++ enable_glibc = 0 ++ enable_some = 0 ++ error = 0 ++ split(SELECTED_HASHES, selected_hashes_list, ",") ++ for (i in selected_hashes_list) { ++ h = selected_hashes_list[i] ++ if (h == "all") { ++ enable_all = 1 ++ } else if (h == "strong") { ++ enable_strong = 1 ++ } else if (h == "glibc") { ++ enable_glibc = 1 ++ } else { ++ enable_some = 1 ++ selected_hashes[h] = 1 ++ } ++ } ++ if (enable_all && (enable_strong || enable_glibc || enable_some)) { ++ error = 1 ++ exit 1 ++ } ++} ++ ++/^#/ { ++ next ++} ++ ++{ ++ if (enable_all || $1 in selected_hashes) { ++ enabled_hashes[$1] = 1 ++ } else { ++ enabled_hashes[$1] = 0 ++ ++ split($5, flags, ",") ++ for (i in flags) { ++ flag = flags[i] ++ if (flag == "STRONG" && enable_strong) { ++ enabled_hashes[$1] = 1 ++ } else if (flag == "GLIBC" && enable_glibc) { ++ enabled_hashes[$1] = 1 ++ } ++ } ++ } ++} ++ ++ ++END { ++ if (error) { ++ exit 1 ++ } ++ ++ # Check for individual selected hashes that didn't appear in ++ # hashes.lst. ++ for (h in selected_hashes) { ++ if (!(h in enabled_hashes)) { ++ exit 1 ++ } ++ } ++ ++ enabled_hash_list = "," ++ for (i in enabled_hashes) { ++ if (enabled_hashes[i]) { ++ enabled_hash_list = enabled_hash_list i "," ++ } ++ } ++ print enabled_hash_list ++} +diff --git a/test-alg-des.c b/test-alg-des.c +index 2f42870..d00fdb5 100644 +--- a/test-alg-des.c ++++ b/test-alg-des.c +@@ -11,6 +11,8 @@ + + #include + ++#if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big ++ + static void + v_print (const unsigned char v[8]) + { +@@ -66,3 +68,13 @@ main (void) + + return status; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-hmac-sha1.c b/test-alg-hmac-sha1.c +index 777ac86..21ef281 100644 +--- a/test-alg-hmac-sha1.c ++++ b/test-alg-hmac-sha1.c +@@ -33,6 +33,8 @@ + #include + #include + ++#if INCLUDE_sha1 ++ + #define HASH_LENGTH 20 + + static char * +@@ -166,3 +168,13 @@ main (void) + } + return n; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-md4.c b/test-alg-md4.c +index ab6ad87..1b1b828 100644 +--- a/test-alg-md4.c ++++ b/test-alg-md4.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_nthash ++ + static const struct + { + const char *input; +@@ -97,3 +99,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-md5.c b/test-alg-md5.c +index 9908ab8..dabc6ba 100644 +--- a/test-alg-md5.c ++++ b/test-alg-md5.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_md5 || INCLUDE_sunmd5 ++ + static const struct + { + const char *input; +@@ -120,3 +122,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-sha1.c b/test-alg-sha1.c +index 04ce456..594d192 100644 +--- a/test-alg-sha1.c ++++ b/test-alg-sha1.c +@@ -9,6 +9,8 @@ + + #include + ++#if INCLUDE_sha1 ++ + /* Test Vectors (from FIPS PUB 180-1) */ + const char *test_data[3] = + { +@@ -80,3 +82,13 @@ main (void) + /* success */ + return retval; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-sha256.c b/test-alg-sha256.c +index 45345e2..06354ac 100644 +--- a/test-alg-sha256.c ++++ b/test-alg-sha256.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_sha256 ++ + static const struct + { + const char *input; +@@ -129,3 +131,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-alg-sha512.c b/test-alg-sha512.c +index 0e24ad5..b6d4fc6 100644 +--- a/test-alg-sha512.c ++++ b/test-alg-sha512.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_sha512 ++ + static const struct + { + const char *input; +@@ -159,3 +161,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-badsalt.c b/test-crypt-badsalt.c +index a5e0e01..8ce7401 100644 +--- a/test-crypt-badsalt.c ++++ b/test-crypt-badsalt.c +@@ -25,7 +25,9 @@ + + static const char *tests[][3] = + { ++#if INCLUDE_des || INCLUDE_des_big + { "no salt", "", "..ogcgXxFhnjI" /* valid setting */ }, ++#endif + { "single char", "/", "*0" /* invalid setting */ }, + { "first char bad", "!x", "*0" /* invalid setting */ }, + { "second char bad", "Z%", "*0" /* invalid setting */ }, +diff --git a/test-crypt-bcrypt.c b/test-crypt-bcrypt.c +index 02a2f07..c984e4d 100644 +--- a/test-crypt-bcrypt.c ++++ b/test-crypt-bcrypt.c +@@ -21,6 +21,8 @@ + #include + #include + ++#if INCLUDE_bcrypt ++ + static const char *tests[][3] = + { + { +@@ -259,3 +261,13 @@ main (void) + free (data); + return status; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-des.c b/test-crypt-des.c +index e541885..1b5463e 100644 +--- a/test-crypt-des.c ++++ b/test-crypt-des.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big ++ + static const struct + { + const char *salt; +@@ -10,6 +12,7 @@ static const struct + const char *input; + } tests[] = + { ++#if INCLUDE_des + /* traditional-DES test vectors from John the Ripper */ + { "CC", "CCNf8Sbh3HDfQ", "U*U*U*U*" }, + { "CC", "CCNf8Sbh3HDfQ", "U*U*U*U*ignored" }, +@@ -19,8 +22,9 @@ static const struct + { "CC", "CC4rMpbg9AMZ.", "\xd5\xaa\xd5\xaa\xaa\xaa\xd5\xaa" }, + { "XX", "XXxzOu6maQKqQ", "*U*U*U*U" }, + { "SD", "SDbsugeBiC58A", "" }, ++#endif + +-#if ENABLE_WEAK_NON_GLIBC_HASHES ++#if INCLUDE_des_xbsd + /* BSDI-extended-DES, ditto */ + { "_J9..CCCC", "_J9..CCCCXBrJUJV154M", "U*U*U*U*" }, + { "_J9..CCCC", "_J9..CCCCXUhOBTXzaiE", "U*U***U" }, +@@ -38,7 +42,9 @@ static const struct + { "_J9..SDiz", "_J9..SDizxmRI1GjnQuE", "zxyDPWgydbQjgq" }, + { "_K9..Salt", "_K9..SaltNrQgIYUAeoY", "726 even" }, + { "_J9..SDSD", "_J9..SDSD5YGyRCr4W4c", "" }, ++#endif + ++#if INCLUDE_des_big + /* 10 bigcrypt test vectors from pw-fake-unix.gz from the openwall + wiki. All have two blocks. The salt is padded with dots because + crypt_r will only use bigcrypt if the setting string begins with +@@ -100,3 +106,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-md5.c b/test-crypt-md5.c +index 235c250..3035c39 100644 +--- a/test-crypt-md5.c ++++ b/test-crypt-md5.c +@@ -1,6 +1,8 @@ + #include "crypt-port.h" + #include "crypt-base.h" + ++#if INCLUDE_md5 ++ + int + main (void) + { +@@ -17,3 +19,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-nthash.c b/test-crypt-nthash.c +index 6f897fe..9bf7d28 100644 +--- a/test-crypt-nthash.c ++++ b/test-crypt-nthash.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_nthash ++ + static const struct + { + const char *input; +@@ -160,3 +162,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-pbkdf1-sha1.c b/test-crypt-pbkdf1-sha1.c +index aadc0fe..677e5bf 100644 +--- a/test-crypt-pbkdf1-sha1.c ++++ b/test-crypt-pbkdf1-sha1.c +@@ -5,6 +5,8 @@ + #include + #include + ++#if INCLUDE_sha1 ++ + const char *password = "zyxwvuts"; + const char *tests[][2] = + { +@@ -92,3 +94,13 @@ main (void) + free (previous); + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-sha256.c b/test-crypt-sha256.c +index 23da81c..7c42398 100644 +--- a/test-crypt-sha256.c ++++ b/test-crypt-sha256.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_sha256 ++ + static const struct + { + const char *salt; +@@ -73,3 +75,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-sha512.c b/test-crypt-sha512.c +index 1aa0b71..c2a1973 100644 +--- a/test-crypt-sha512.c ++++ b/test-crypt-sha512.c +@@ -3,6 +3,8 @@ + + #include + ++#if INCLUDE_sha512 ++ + static const struct + { + const char *salt; +@@ -73,3 +75,13 @@ main (void) + + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-crypt-sunmd5.c b/test-crypt-sunmd5.c +index d67781b..2c9731a 100644 +--- a/test-crypt-sunmd5.c ++++ b/test-crypt-sunmd5.c +@@ -4,6 +4,8 @@ + #include + #include + ++#if INCLUDE_sunmd5 ++ + const char *password = "abcdefg"; + const char *tests[][3] = + { +@@ -128,3 +130,13 @@ main (void) + free (previous); + return result; + } ++ ++#else ++ ++int ++main (void) ++{ ++ return 77; /* UNSUPPORTED */ ++} ++ ++#endif +diff --git a/test-gensalt.c b/test-gensalt.c +index 2705671..b81fcf0 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -14,43 +14,56 @@ static const char *const entropy[] = + 0 + }; + +-#if ENABLE_WEAK_HASHES ++#if INCLUDE_des || INCLUDE_des_big + static const char *const des_expected_output[] = { "Mp", "Pp", "ZH", "Uh"}; +-static const char *const md5_expected_output[] = { +- "$1$MJHnaAke", +- "$1$PKXc3hCO", +- "$1$ZAFlICwY", +- "$1$UqGBkVu0" +-}; +-#if ENABLE_WEAK_NON_GLIBC_HASHES ++#endif ++#if INCLUDE_des_xbsd + static const char *const bsdi_expected_output[] = { + "_J9..MJHn", + "_J9..PKXc", + "_J9..ZAFl", + "_J9..UqGB" + }; ++#endif ++#if INCLUDE_md5 ++static const char *const md5_expected_output[] = { ++ "$1$MJHnaAke", ++ "$1$PKXc3hCO", ++ "$1$ZAFlICwY", ++ "$1$UqGBkVu0" ++}; ++#endif ++#if INCLUDE_nthash + static const char *const nthash_expected_output[] = { + "$3$__not_used__c809a450df09a3", + "$3$__not_used__30d0d6f834c0c3", + "$3$__not_used__0eeeebb83d6fe4", + "$3$__not_used__1c690d6a9ef88c" + }; ++#endif ++#if INCLUDE_sunmd5 + #define sunmd5_expected_output 0 /* output is not deterministic */ +-#define pbkdf_expected_output 0 /* output is not deterministic */ + #endif ++#if INCLUDE_sha1 ++#define pbkdf_expected_output 0 /* output is not deterministic */ + #endif ++#if INCLUDE_sha256 + static const char *const sha256_expected_output[] = { + "$5$MJHnaAkegEVYHsFK", + "$5$PKXc3hCOSyMqdaEQ", + "$5$ZAFlICwYRETzIzIj", + "$5$UqGBkVu01rurVZqg" + }; ++#endif ++#if INCLUDE_sha512 + static const char *const sha512_expected_output[] = { + "$6$MJHnaAkegEVYHsFK", + "$6$PKXc3hCOSyMqdaEQ", + "$6$ZAFlICwYRETzIzIj", + "$6$UqGBkVu01rurVZqg" + }; ++#endif ++#if INCLUDE_bcrypt + static const char *const bcrypt_a_expected_output[] = { + "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO", + "$2a$05$kxUgPcrmlm9XoOjvxCyfP.", +@@ -75,6 +88,7 @@ static const char *const bcrypt_y_expected_output[] = { + "$2y$05$HPNDjKMRFdR7zC87CMSmA.", + "$2y$05$mAyzaIeJu41dWUkxEbn8hO" + }; ++#endif + + struct testcase + { +@@ -86,22 +100,36 @@ struct testcase + + static const struct testcase testcases[] = + { +-#if ENABLE_WEAK_HASHES ++#if INCLUDE_des || INCLUDE_des_big + { "", des_expected_output, 2, 0 }, // DES +- { "$1$", md5_expected_output, 11, 0 }, // MD5 +-#if ENABLE_WEAK_NON_GLIBC_HASHES ++#endif ++#if INCLUDE_des_xbsd + { "_", bsdi_expected_output, 9, 0 }, // BSDi extended DES ++#endif ++#if INCLUDE_md5 ++ { "$1$", md5_expected_output, 11, 0 }, // MD5 ++#endif ++#if INCLUDE_nthash + { "$3$", nthash_expected_output, 29, 0 }, // NTHASH ++#endif ++#if INCLUDE_sunmd5 + { "$md5", sunmd5_expected_output, 27, 0 }, // SUNMD5 +- { "$sha1", pbkdf_expected_output, 34, 74 }, // PBKDF with SHA1 + #endif ++#if INCLUDE_sha1 ++ { "$sha1", pbkdf_expected_output, 34, 74 }, // PBKDF with SHA1 + #endif ++#if INCLUDE_sha256 + { "$5$", sha256_expected_output, 19, 0 }, // SHA-2-256 ++#endif ++#if INCLUDE_sha512 + { "$6$", sha512_expected_output, 19, 0 }, // SHA-2-512 ++#endif ++#if INCLUDE_bcrypt + { "$2a$", bcrypt_a_expected_output, 29, 0 }, // bcrypt mode A + { "$2b$", bcrypt_b_expected_output, 29, 0 }, // bcrypt mode B + { "$2x$", bcrypt_x_expected_output, 29, 0 }, // bcrypt mode X + { "$2y$", bcrypt_y_expected_output, 29, 0 }, // bcrypt mode Y ++#endif + { 0, 0, 0, 0 } + }; + +@@ -184,7 +212,9 @@ main (void) + char *setting1, *setting2; + setting1 = crypt_gensalt_ra ("$2b$", 0, entropy[0], 16); + setting2 = crypt_gensalt_ra (0, 0, entropy[0], 16); +- if (strcmp (setting1, setting2)) ++ if ((setting1 == 0 && setting2 != 0) || ++ (setting1 != 0 && setting2 == 0) || ++ (setting1 != 0 && setting2 != 0 && strcmp (setting1, setting2))) + { + printf ("FAILED: crypt_gensalt defaulting to $2b$\n" + " $2b$ -> %s\n" +@@ -196,6 +226,7 @@ main (void) + free (setting2); + } + ++#if INCLUDE_bcrypt + /* FIXME: This test is a little too specific. It used to be in + test-bcrypt.c and I'm not sure what it's meant to be testing. */ + { +@@ -225,6 +256,6 @@ main (void) + free (setting1); + free (setting2); + } +- ++#endif + return status; + } + +From 15b30b6d7da6d5470de65f9a2a4d676f82423ceb Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Wed, 4 Jul 2018 22:31:02 -0400 +Subject: [PATCH 16/38] .travis.yml: Use --enable-hashes instead of + --enable-weak-hashes. + +--- + .travis.yml | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/.travis.yml b/.travis.yml +index 7e892b2..ffca408 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -19,80 +19,80 @@ matrix: + os: linux + services: docker + env: +- - CONF="--enable-obsolete-api --enable-weak-hashes" ++ - CONF="--enable-obsolete-api --enable-hashes=all" + - FCVER="rawhide" + - CODECOV=1 + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--enable-obsolete-api --enable-weak-hashes" ++ - CONF="--enable-obsolete-api --enable-hashes=all" + - FCVER="rawhide" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--enable-obsolete-api --enable-weak-hashes" ++ - CONF="--enable-obsolete-api --enable-hashes=all" + - FCVER="rawhide" + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--enable-obsolete-api --enable-weak-hashes" ++ - CONF="--enable-obsolete-api --enable-hashes=all" + - FCVER="latest" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--enable-obsolete-api --enable-weak-hashes" ++ - CONF="--enable-obsolete-api --enable-hashes=all" + - FCVER="latest" + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --enable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=all" + - FCVER="rawhide" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --enable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=all" + - FCVER="rawhide" + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --enable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=all" + - FCVER="latest" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --enable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=all" + - FCVER="latest" + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --disable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=strong" + - FCVER="rawhide" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --disable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=strong" + - FCVER="rawhide" + - compiler: gcc + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --disable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=strong" + - FCVER="latest" + - compiler: clang + os: linux + services: docker + env: +- - CONF="--disable-obsolete-api --disable-weak-hashes" ++ - CONF="--disable-obsolete-api --enable-hashes=strong" + - FCVER="latest" + + before_install: + +From a33d95ea613256c46f0b05fa2345080d47193c9e Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Wed, 4 Jul 2018 15:59:40 +0000 +Subject: [PATCH 17/38] .travis.yml: add --enable-hashes=glibc to the test + matrix + +--- + .travis.yml | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/.travis.yml b/.travis.yml +index ffca408..b8a7ecf 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -94,6 +94,30 @@ matrix: + env: + - CONF="--disable-obsolete-api --enable-hashes=strong" + - FCVER="latest" ++ - compiler: gcc ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api --enable-hashes=glibc" ++ - FCVER="rawhide" ++ - compiler: clang ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api --enable-hashes=glibc" ++ - FCVER="rawhide" ++ - compiler: gcc ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api --enable-hashes=glibc" ++ - FCVER="latest" ++ - compiler: clang ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api --enable-hashes=glibc" ++ - FCVER="latest" + + before_install: + - for i in `seq 0 99`; do docker pull fedora:$FCVER && i= && break || sleep 1; done; [ -z "$i" ] + +From a7f9df50cecec46bb8176382faa685ce35ca72be Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Thu, 5 Jul 2018 15:20:05 -0400 +Subject: [PATCH 18/38] Make salt validation pickier. + +This started out as a patch to fold together test-crypt-badsalt.c and +test-crypt-nonnull.c (which were almost the same program) and extend +their testing from DES to all of the supported hashes. That revealed +that many of the supported hash functions do not validate the contents +of their salt strings very carefully. + +This patch has a low but nonzero backward compatibility risk, because +now we reject certain calls to crypt*() that we would previously have +accepted. In particular, setting strings of the form + + $5$xxxxxxx*xxxxxxxx$ + +where x stands for any "itoa64" character and * for any non-"itoa64" +character, would formerly be accepted but are now rejected. Some of +the hash algorithms that were lenient about the contents of the salt +would echo back the salt verbatim, and others would convert it to the +base64 alphabet somehow. I think it's unlikely that this occurs in +real password files but I don't have a lot of data to base that on. +--- + .gitignore | 3 +- + .travis.yml | 2 +- + Makefile.am | 9 +- + alg-des-tables.c | 30 +++-- + crypt-des.c | 80 ++++++++--- + crypt-md5.c | 9 +- + crypt-pbkdf1-sha1.c | 37 +++--- + crypt-sha256.c | 11 +- + crypt-sha512.c | 11 +- + crypt-sunmd5.c | 72 +++++----- + crypt.c | 17 +-- + test-badsalt.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++ + test-crypt-badsalt.c | 139 ------------------- + test-crypt-nonnull.c | 97 -------------- + test-gensalt.c | 31 +++-- + 15 files changed, 558 insertions(+), 357 deletions(-) + create mode 100644 test-badsalt.c + delete mode 100644 test-crypt-badsalt.c + delete mode 100644 test-crypt-nonnull.c + +diff --git a/.gitignore b/.gitignore +index 9f443bd..bb7f15c 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -53,13 +53,12 @@ + /test-alg-sha1 + /test-alg-sha256 + /test-alg-sha512 ++/test-badsalt + /test-bigcrypt + /test-byteorder +-/test-crypt-badsalt + /test-crypt-bcrypt + /test-crypt-des + /test-crypt-md5 +-/test-crypt-nonnull + /test-crypt-nthash + /test-crypt-pbkdf1-sha1 + /test-crypt-sha256 +diff --git a/.travis.yml b/.travis.yml +index b8a7ecf..31c50fa 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -156,4 +156,4 @@ script: + - docker exec -t buildenv /bin/sh -c "(make -C /opt/libxcrypt -j$((`nproc --all` * 2)) check || (cat /opt/libxcrypt/test-suite.log && exit 1))" + + after_success: +- - if [[ "$CODECOV" == "1" ]] ; then docker exec -t buildenv /bin/sh -c "cd /opt/libxcrypt ; lcov --directory . --capture --output-file all_coverage.info ; lcov --remove all_coverage.info '/usr/*' '*test*' > coverage.info ; rm -f all_coverage.info ; codecov -X gcov" ; fi ++ - if [[ "$CODECOV" == "1" ]] ; then docker exec -t buildenv /bin/sh -c "make -C /opt/libxcrypt check && cd /opt/libxcrypt && lcov --directory . --capture --output-file all_coverage.info && lcov --remove all_coverage.info '/usr/*' '*test*' > coverage.info && rm all_coverage.info && codecov -X gcov" ; fi +diff --git a/Makefile.am b/Makefile.am +index 040d719..79d59d7 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -122,11 +122,11 @@ endif + check_PROGRAMS = \ + test-alg-des test-alg-hmac-sha1 test-alg-md4 test-alg-md5 \ + test-alg-sha1 test-alg-sha256 test-alg-sha512 \ +- test-crypt-badsalt test-crypt-bcrypt test-crypt-des \ +- test-crypt-md5 test-crypt-nonnull test-crypt-nthash \ ++ test-crypt-bcrypt test-crypt-des \ ++ test-crypt-md5 test-crypt-nthash \ + test-crypt-pbkdf1-sha1 test-crypt-sha256 test-crypt-sha512 \ + test-crypt-sunmd5 \ +- test-byteorder test-gensalt ++ test-byteorder test-badsalt test-gensalt + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +@@ -157,16 +157,15 @@ LOG_COMPILER = m4/skip-if-exec-format-error + endif + EXTRA_DIST += m4/skip-if-exec-format-error + +-test_crypt_badsalt_LDADD = libcrypt.la + test_crypt_bcrypt_LDADD = libcrypt.la + test_crypt_des_LDADD = libcrypt.la + test_crypt_md5_LDADD = libcrypt.la +-test_crypt_nonnull_LDADD = libcrypt.la + test_crypt_nthash_LDADD = libcrypt.la + test_crypt_pbkdf1_sha1_LDADD = libcrypt.la + test_crypt_sha256_LDADD = libcrypt.la + test_crypt_sha512_LDADD = libcrypt.la + test_crypt_sunmd5_LDADD = libcrypt.la ++test_badsalt_LDADD = libcrypt.la + test_gensalt_LDADD = libcrypt.la + test_des_obsolete_LDADD = libcrypt.la + test_des_obsolete_r_LDADD = libcrypt.la +diff --git a/alg-des-tables.c b/alg-des-tables.c +index c46d1c4..4204a37 100644 +--- a/alg-des-tables.c ++++ b/alg-des-tables.c +@@ -51,7 +51,8 @@ + + #if INCLUDE_des || INCLUDE_des_xbsd || INCLUDE_des_big + +-const uint8_t m_sbox[4][4096] = { ++const uint8_t m_sbox[4][4096] = ++{ + { + 0xef, 0xe3, 0xe1, 0xed, 0xe8, 0xe4, 0xee, 0xe7, 0xe6, 0xef, 0xeb, 0xe2, + 0xe3, 0xe8, 0xe4, 0xee, 0xe9, 0xec, 0xe7, 0xe0, 0xe2, 0xe1, 0xed, 0xea, +@@ -1430,7 +1431,8 @@ const uint8_t m_sbox[4][4096] = { + }, + }; + +-const uint32_t ip_maskl[8][256] = { ++const uint32_t ip_maskl[8][256] = ++{ + { + 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00000100, 0x00000101, 0x00000000, 0x00000001, 0x00000000, 0x00000001, +@@ -1793,7 +1795,8 @@ const uint32_t ip_maskl[8][256] = { + }, + }; + +-const uint32_t ip_maskr[8][256] = { ++const uint32_t ip_maskr[8][256] = ++{ + { + 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, 0x00000000, + 0x00000001, 0x00000001, 0x00000100, 0x00000100, 0x00000101, 0x00000101, +@@ -2156,7 +2159,8 @@ const uint32_t ip_maskr[8][256] = { + }, + }; + +-const uint32_t fp_maskl[8][256] = { ++const uint32_t fp_maskl[8][256] = ++{ + { + 0x00000000, 0x40000000, 0x00400000, 0x40400000, 0x00004000, 0x40004000, + 0x00404000, 0x40404000, 0x00000040, 0x40000040, 0x00400040, 0x40400040, +@@ -2519,7 +2523,8 @@ const uint32_t fp_maskl[8][256] = { + }, + }; + +-const uint32_t fp_maskr[8][256] = { ++const uint32_t fp_maskr[8][256] = ++{ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +@@ -2882,7 +2887,8 @@ const uint32_t fp_maskr[8][256] = { + }, + }; + +-const uint32_t key_perm_maskl[8][128] = { ++const uint32_t key_perm_maskl[8][128] = ++{ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +@@ -3077,7 +3083,8 @@ const uint32_t key_perm_maskl[8][128] = { + }, + }; + +-const uint32_t key_perm_maskr[8][128] = { ++const uint32_t key_perm_maskr[8][128] = ++{ + { + 0x00000000, 0x00100000, 0x00001000, 0x00101000, 0x00000010, 0x00100010, + 0x00001010, 0x00101010, 0x00000001, 0x00100001, 0x00001001, 0x00101001, +@@ -3272,7 +3279,8 @@ const uint32_t key_perm_maskr[8][128] = { + }, + }; + +-const uint32_t comp_maskl[8][128] = { ++const uint32_t comp_maskl[8][128] = ++{ + { + 0x00000000, 0x00000010, 0x00004000, 0x00004010, 0x00040000, 0x00040010, + 0x00044000, 0x00044010, 0x00000100, 0x00000110, 0x00004100, 0x00004110, +@@ -3467,7 +3475,8 @@ const uint32_t comp_maskl[8][128] = { + }, + }; + +-const uint32_t comp_maskr[8][128] = { ++const uint32_t comp_maskr[8][128] = ++{ + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, +@@ -3662,7 +3671,8 @@ const uint32_t comp_maskr[8][128] = { + }, + }; + +-const uint32_t psbox[4][256] = { ++const uint32_t psbox[4][256] = ++{ + { + 0x00000000, 0x00004000, 0x40000000, 0x40004000, 0x00000010, 0x00004010, + 0x40000010, 0x40004010, 0x00080000, 0x00084000, 0x40080000, 0x40084000, +diff --git a/crypt-des.c b/crypt-des.c +index 3d8bc2e..b197dcd 100644 +--- a/crypt-des.c ++++ b/crypt-des.c +@@ -80,22 +80,22 @@ static const uint8_t ascii64[] = + /* 0000000000111111111122222222223333333333444444444455555555556666 */ + /* 0123456789012345678901234567890123456789012345678901234567890123 */ + +-static inline unsigned int ++static inline int + ascii_to_bin(char ch) + { + if (ch > 'z') +- return 0; ++ return -1; + if (ch >= 'a') +- return (unsigned int)(ch - 'a' + 38); ++ return ch - 'a' + 38; + if (ch > 'Z') +- return 0; ++ return -1; + if (ch >= 'A') +- return (unsigned int)(ch - 'A' + 12); ++ return ch - 'A' + 12; + if (ch > '9') +- return 0; ++ return -1; + if (ch >= '.') +- return (unsigned int)(ch - '.'); +- return 0; ++ return ch - '.'; ++ return -1; + } + + /* Generate an 11-character DES password hash into the buffer at +@@ -169,10 +169,21 @@ crypt_des_rn (const char *phrase, const char *setting, + + /* "old"-style: setting - 2 bytes of salt, phrase - up to 8 characters. + Note: ascii_to_bin maps all byte values outside the ascii64 +- alphabet to zero. Do not read past the end of the string. */ +- salt = ascii_to_bin (setting[0]); +- if (setting[0]) +- salt |= ascii_to_bin (setting[1]) << 6; ++ alphabet to -1. Do not read past the end of the string. */ ++ i = ascii_to_bin (setting[0]); ++ if (i < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt = (unsigned int)i; ++ i = ascii_to_bin (setting[1]); ++ if (i < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt |= ((unsigned int)i << 6); + + /* Write the canonical form of the salt to the output buffer. We do + this instead of copying from the setting because the setting +@@ -247,9 +258,20 @@ crypt_des_big_rn (const char *phrase, const char *setting, + + /* The setting string is exactly the same as for a traditional DES + hash. */ +- salt = ascii_to_bin (setting[0]); +- if (setting[0]) +- salt |= ascii_to_bin (setting[1]) << 6; ++ i = ascii_to_bin (setting[0]); ++ if (i < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt = (unsigned int)i; ++ i = ascii_to_bin (setting[1]); ++ if (i < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt |= ((unsigned int)i << 6); + + *cp++ = ascii64[salt & 0x3f]; + *cp++ = ascii64[(salt >> 6) & 0x3f]; +@@ -272,9 +294,9 @@ crypt_des_big_rn (const char *phrase, const char *setting, + break; + + /* change the salt (1st 2 chars of previous block) - this was found +- by dowsing */ +- salt = ascii_to_bin ((char)cp[0]); +- salt |= ascii_to_bin ((char)cp[1]) << 6; ++ by dowsing - no need to check for invalid characters here */ ++ salt = (unsigned int)ascii_to_bin ((char)cp[0]); ++ salt |= (unsigned int)ascii_to_bin ((char)cp[1]) << 6; + cp += 11; + } + } +@@ -309,17 +331,33 @@ crypt_des_xbsd_rn (const char *phrase, const char *setting, + uint32_t count = 0, salt = 0; + uint8_t *keybuf = buf->keybuf, *pkbuf = buf->pkbuf; + uint8_t *cp = output; +- int i; ++ int i, x; + + /* "new"-style DES hash: + setting - underscore, 4 bytes of count, 4 bytes of salt + phrase - unlimited characters + */ + for (i = 1; i < 5; i++) +- count |= ascii_to_bin(setting[i]) << ((i - 1) * 6); ++ { ++ x = ascii_to_bin(setting[i]); ++ if (x < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ count |= (unsigned int)x << ((i - 1) * 6); ++ } + + for (i = 5; i < 9; i++) +- salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6); ++ { ++ x = ascii_to_bin(setting[i]); ++ if (x < 0) ++ { ++ errno = EINVAL; ++ return; ++ } ++ salt |= (unsigned int)x << ((i - 5) * 6); ++ } + + memcpy (cp, setting, 9); + cp += 9; +diff --git a/crypt-md5.c b/crypt-md5.c +index 1a9139a..f051794 100644 +--- a/crypt-md5.c ++++ b/crypt-md5.c +@@ -31,7 +31,7 @@ + static const char md5_salt_prefix[] = "$1$"; + + /* Table with characters for base64 transformation. */ +-static const char b64t[64] = ++static const char b64t[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + /* The maximum length of an MD5 salt string (just the actual salt, not +@@ -88,7 +88,12 @@ crypt_md5_rn (const char *phrase, const char *setting, + /* Skip salt prefix. */ + salt += sizeof (md5_salt_prefix) - 1; + +- salt_len = strcspn (salt, "$"); ++ salt_len = strspn (salt, b64t); ++ if (salt[salt_len] && salt[salt_len] != '$') ++ { ++ errno = EINVAL; ++ return; ++ } + if (salt_len > SALT_LEN_MAX) + salt_len = SALT_LEN_MAX; + phrase_len = strlen (phrase); +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index 544d890..6bacc21 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -148,30 +148,33 @@ crypt_sha1_rn (const char *phrase, const char *setting, + /* + * Salt format is + * $$$salt[$] +- * If it does not start with $ we use our default iterations. + */ + +- /* If it starts with the magic string, then skip that */ +- if (!strncmp (setting, magic, strlen (magic))) ++ /* If the string doesn't starts with the magic prefix, we shouldn't have been called */ ++ if (strncmp (setting, magic, strlen (magic))) + { +- setting += strlen (magic); +- /* and get the iteration count */ +- iterations = (unsigned long)strtoul (setting, (char **)&ep, 10); +- if (*ep != '$') +- { +- errno = EINVAL; +- return; /* invalid input */ +- } +- setting = (char *)ep + 1; /* skip over the '$' */ ++ errno = EINVAL; ++ return; + } +- else ++ ++ setting += strlen (magic); ++ /* get the iteration count */ ++ iterations = (unsigned long)strtoul (setting, (char **)&ep, 10); ++ if (*ep != '$') + { +- iterations = (unsigned long)crypt_sha1_iterations (0); ++ errno = EINVAL; ++ return; /* invalid input */ + } ++ setting = (char *)ep + 1; /* skip over the '$' */ + +- /* It stops at the next '$', max CRYPT_SHA1_ITERATIONS chars */ +- for (sp = setting; *sp && *sp != '$' && sp < (setting + CRYPT_SHA1_ITERATIONS); sp++) +- continue; ++ /* The next 1..CRYPT_SHA1_SALT_LENGTH bytes should be itoa64 characters, ++ followed by another '$' (or end of string). */ ++ sp = setting + strspn (setting, (const char *)itoa64); ++ if (sp == setting || (*sp && *sp != '$')) ++ { ++ errno = EINVAL; ++ return; ++ } + + /* Get the length of the actual salt */ + sl = (size_t)(sp - setting); +diff --git a/crypt-sha256.c b/crypt-sha256.c +index 8b4ba67..b8640b8 100644 +--- a/crypt-sha256.c ++++ b/crypt-sha256.c +@@ -70,7 +70,7 @@ static_assert (sizeof (struct sha256_buffer) <= ALG_SPECIFIC_SIZE, + + + /* Table with characters for base64 transformation. */ +-static const char b64t[64] = ++static const char b64t[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + /* Subroutine of _xcrypt_crypt_sha256_rn: Feed CTX with LEN bytes of a +@@ -133,7 +133,14 @@ crypt_sha256_rn (const char *phrase, const char *setting, + } + } + +- salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); ++ salt_len = strspn (salt, b64t); ++ if (salt[salt_len] && salt[salt_len] != '$') ++ { ++ errno = EINVAL; ++ return; ++ } ++ if (salt_len > SALT_LEN_MAX) ++ salt_len = SALT_LEN_MAX; + phrase_len = strlen (phrase); + + /* Compute alternate SHA256 sum with input PHRASE, SALT, and PHRASE. The +diff --git a/crypt-sha512.c b/crypt-sha512.c +index 28e4f1c..1a651e0 100644 +--- a/crypt-sha512.c ++++ b/crypt-sha512.c +@@ -70,7 +70,7 @@ static_assert (sizeof (struct sha512_buffer) <= ALG_SPECIFIC_SIZE, + + + /* Table with characters for base64 transformation. */ +-static const char b64t[64] = ++static const char b64t[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + /* Subroutine of _xcrypt_crypt_sha512_rn: Feed CTX with LEN bytes of a +@@ -133,7 +133,14 @@ crypt_sha512_rn (const char *phrase, const char *setting, + } + } + +- salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); ++ salt_len = strspn (salt, b64t); ++ if (salt[salt_len] && salt[salt_len] != '$') ++ { ++ errno = EINVAL; ++ return; ++ } ++ if (salt_len > SALT_LEN_MAX) ++ salt_len = SALT_LEN_MAX; + phrase_len = strlen (phrase); + + /* Compute alternate SHA512 sum with input PHRASE, SALT, and PHRASE. The +diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c +index fcd3984..f3c84a8 100644 +--- a/crypt-sunmd5.c ++++ b/crypt-sunmd5.c +@@ -115,41 +115,51 @@ to64 (char *s, uint64_t v, int n) + } + } + +-#define ROUNDS "rounds=" ++#define ROUNDS ",rounds=" + #define ROUNDSLEN (sizeof (ROUNDS) - 1) + + /* +- * get the integer value after rounds= where ever it occurs in the string. +- * if the last char after the int is a , or $ that is fine anything else is an +- * error. ++ * get the integer value after ,rounds= if present ++ * s should point immediately after $md5 ++ * set *puresalt one character after the dollar sign after ++ * the number of rounds (if present) or to NULL if the syntax ++ * is invalid + */ + static uint32_t +-getrounds (const char *s) ++getrounds (const char *s, const char **puresalt) + { +- char *r, *p, *e; ++ const char *p; ++ char *e; + long val; + ++ *puresalt = 0; ++ + if (s == NULL) + return (0); + +- if ((r = strstr (s, ROUNDS)) == NULL) +- return (0); ++ if (*s == '$') ++ { ++ *puresalt = s + 1; ++ return (0); ++ } + +- if (strncmp (r, ROUNDS, ROUNDSLEN) != 0) ++ if (strncmp (s, ROUNDS, ROUNDSLEN) != 0) + return (0); + +- p = r + ROUNDSLEN; ++ p = s + ROUNDSLEN; + errno = 0; + val = strtol (p, &e, 10); + /* + * An error occured or there is non-numeric stuff at the end + * which isn't one of the crypt(3c) special chars ',' or '$' + */ +- if (errno != 0 || val < 0 || +- !(*e == '\0' || *e == ',' || *e == '$')) +- { +- return (0); +- } ++ if (errno != 0 || val < 0 || p == e || (*e != '\0' && *e != '$')) ++ return (0); ++ ++ if (*e == '$') ++ *puresalt = e + 1; ++ else ++ *puresalt = e; + + return ((uint32_t)val); + } +@@ -189,7 +199,7 @@ gensalt_sunmd5_rn (unsigned long count, + /* Generated salt is at least 27 bytes + and a maximum of 32 bytes long. */ + snprintf ((char *)output, o_size, +- "$" CRYPT_ALGNAME "," ROUNDS "%u$%s$", ++ "$" CRYPT_ALGNAME ROUNDS "%u$%s$", + (unsigned int)count, rndstr); + } + +@@ -245,22 +255,27 @@ crypt_sunmd5_rn (const char *phrase, const char *setting, + int round; + uint32_t maxrounds = BASIC_ROUND_COUNT; + uint32_t l; +- char *puresalt; +- char *saltend; +- char *p; ++ const char *ps = 0; ++ const char *saltend = 0; ++ char *p, *puresalt; + struct sunmd5_ctx *data = scratch; + + /* +- * Extract the puresalt (if it exists) from the existing salt string ++ * Extract the rounds (if it exists) and puresalt from the salt string + * $md5[,rounds=%d]$$ + */ +- saltend = strrchr (setting, '$'); +- +- if (saltend == NULL || saltend == setting) ++ maxrounds += getrounds (setting + sizeof ("$" CRYPT_ALGNAME) - 1, &ps); ++ if (ps) ++ saltend = ps + strspn (ps, (char *)itoa64); ++ if (!saltend || saltend == ps || saltend[0] != '$') + { + errno = EINVAL; + return; + } ++ /* For bug-compatibility with the original implementation, if saltend ++ points at "$$", advance it to point at the second dollar sign. */ ++ if (saltend[0] == '$' && saltend[1] == '$') ++ saltend += 1; + + if (saltend[1] != '\0') + { +@@ -289,17 +304,6 @@ crypt_sunmd5_rn (const char *phrase, const char *setting, + } + } + +- /* There must not be any dollar sign '$', but +- the last character before the terminating +- '\0' in the string containing the salt. */ +- if (puresalt[strlen (puresalt) - 2] == '$') +- { +- errno = EINVAL; +- return; +- } +- +- maxrounds += getrounds (setting); +- + /* initialise the context */ + md5_init_ctx (&(data->context)); + +diff --git a/crypt.c b/crypt.c +index e1bfc5b..387b69a 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -83,17 +83,6 @@ static const struct hashfn hash_algorithms[] = + HASH_ALGORITHM_TABLE_ENTRIES + }; + +-#if INCLUDE_des || INCLUDE_des_big +-static int +-is_des_salt_char (char c) +-{ +- return ((c >= 'a' && c <= 'z') || +- (c >= 'A' && c <= 'Z') || +- (c >= '0' && c <= '9') || +- c == '.' || c == '/'); +-} +-#endif +- + static const struct hashfn * + get_hashfn (const char *setting) + { +@@ -109,7 +98,7 @@ get_hashfn (const char *setting) + else + { + if (setting[0] == '\0' || +- (is_des_salt_char (setting[0]) && is_des_salt_char (setting[1]))) ++ (setting[0] != '$' && setting[0] != '*')) + return h; + } + #endif +@@ -265,8 +254,8 @@ do_crypt (const char *phrase, const char *setting, struct crypt_data *data) + } + #else + h->crypt (phrase, setting, +- (unsigned char *)data->output, sizeof data->output, +- cint->alg_specific, sizeof cint->alg_specific); ++ (unsigned char *)data->output, sizeof data->output, ++ cint->alg_specific, sizeof cint->alg_specific); + #endif + } + +diff --git a/test-badsalt.c b/test-badsalt.c +new file mode 100644 +index 0000000..41d164a +--- /dev/null ++++ b/test-badsalt.c +@@ -0,0 +1,367 @@ ++/* Test rejection of ill-formed password hashes. ++ Copyright (C) 2012-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "crypt-port.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char phrase[] = "values of β will give rise to dom!"; ++ ++struct testcase ++{ ++ const char *label; ++ size_t plen; ++ const char *setting; ++}; ++static const struct testcase testcases[] = ++{ ++ /* These strings are invalid regardless of the algorithm. */ ++ { "*too short", 1, "/" }, ++ { "*invalid char :", 1, ":" }, ++ { "*invalid char ;", 1, ";" }, ++ { "*invalid char *", 1, "*" }, ++ { "*invalid char !", 1, "!" }, ++ { "*invalid char \\", 1, "\\" }, ++ { "*invalid white 1", 1, " " }, ++ { "*invalid white 2", 1, "\t" }, ++ { "*invalid white 3", 1, "\r" }, ++ { "*invalid white 4", 1, "\n" }, ++ { "*invalid white 5", 1, "\f" }, ++ { "*invalid ctrl 1", 1, "\1" }, ++ { "*invalid ctrl 2", 1, "\177" }, ++ { "*failure token 1", 2, "*0" }, ++ { "*failure token 2", 2, "*1" }, ++ ++ /* Each of these is a valid setting string for some algorithm, ++ from which we will derive many invalid setting strings. ++ This is an expensive test, so where possible, the number of ++ "rounds" of the hash function has been set abnormally low. */ ++#if INCLUDE_des ++ { "DES (trad.)", 2, "Mp" }, ++ { "*DES (trad.), 1st char invalid -", 2, "-p" }, ++ { "*DES (trad.), 2nd char invalid -", 2, "M-" }, ++ { "*DES (trad.), 1st char invalid :", 2, ":p" }, ++ { "*DES (trad.), 2nd char invalid :", 2, "M:" }, ++ { "*DES (trad.), 1st char invalid [", 2, "[p" }, ++ { "*DES (trad.), 2nd char invalid [", 2, "M[" }, ++ { "*DES (trad.), 1st char invalid {", 2, "{p" }, ++ { "*DES (trad.), 2nd char invalid {", 2, "M{" }, ++#endif ++#if INCLUDE_des_big ++ { "DES (bigcrypt)", 2, "Mp............" }, ++ { "*DES (bigcrypt), 1st char invalid -", 2, "-p............" }, ++ { "*DES (bigcrypt), 2nd char invalid -", 2, "M-............" }, ++ { "*DES (bigcrypt), 1st char invalid :", 2, ":p............" }, ++ { "*DES (bigcrypt), 2nd char invalid :", 2, "M:............" }, ++ { "*DES (bigcrypt), 1st char invalid [", 2, "[p............" }, ++ { "*DES (bigcrypt), 2nd char invalid [", 2, "M[............" }, ++ { "*DES (bigcrypt), 1st char invalid {", 2, "{p............" }, ++ { "*DES (bigcrypt), 2nd char invalid {", 2, "M{............" }, ++#endif ++#if INCLUDE_des_xbsd ++ { "DES (BSDi)", 9, "_J9..MJHn" }, ++ { "*DES (BSDi), 1st char invalid -", 9, "_-9..MJHn" }, ++ { "*DES (BSDi), 2nd char invalid -", 9, "_J-..MJHn" }, ++ { "*DES (BSDi), 3rd char invalid -", 9, "_J9-.MJHn" }, ++ { "*DES (BSDi), 4th char invalid -", 9, "_J9.-MJHn" }, ++ { "*DES (BSDi), 5th char invalid -", 9, "_J9..-JHn" }, ++ { "*DES (BSDi), 6th char invalid -", 9, "_J9..M-Hn" }, ++ { "*DES (BSDi), 7th char invalid -", 9, "_J9..MJ-n" }, ++ { "*DES (BSDi), 8th char invalid -", 9, "_J9..MJH-" }, ++ { "*DES (BSDi), 1st char invalid :", 9, "_:9..MJHn" }, ++ { "*DES (BSDi), 2nd char invalid :", 9, "_J:..MJHn" }, ++ { "*DES (BSDi), 3rd char invalid :", 9, "_J9:.MJHn" }, ++ { "*DES (BSDi), 4th char invalid :", 9, "_J9.:MJHn" }, ++ { "*DES (BSDi), 5th char invalid :", 9, "_J9..:JHn" }, ++ { "*DES (BSDi), 6th char invalid :", 9, "_J9..M:Hn" }, ++ { "*DES (BSDi), 7th char invalid :", 9, "_J9..MJ:n" }, ++ { "*DES (BSDi), 8th char invalid :", 9, "_J9..MJH:" }, ++ { "*DES (BSDi), 1st char invalid [", 9, "_[9..MJHn" }, ++ { "*DES (BSDi), 2nd char invalid [", 9, "_J[..MJHn" }, ++ { "*DES (BSDi), 3rd char invalid [", 9, "_J9[.MJHn" }, ++ { "*DES (BSDi), 4th char invalid [", 9, "_J9.[MJHn" }, ++ { "*DES (BSDi), 5th char invalid [", 9, "_J9..[JHn" }, ++ { "*DES (BSDi), 6th char invalid [", 9, "_J9..M[Hn" }, ++ { "*DES (BSDi), 7th char invalid [", 9, "_J9..MJ[n" }, ++ { "*DES (BSDi), 8th char invalid [", 9, "_J9..MJH[" }, ++ { "*DES (BSDi), 1st char invalid {", 9, "_{9..MJHn" }, ++ { "*DES (BSDi), 2nd char invalid {", 9, "_J{..MJHn" }, ++ { "*DES (BSDi), 3rd char invalid {", 9, "_J9{.MJHn" }, ++ { "*DES (BSDi), 4th char invalid {", 9, "_J9.{MJHn" }, ++ { "*DES (BSDi), 5th char invalid {", 9, "_J9..{JHn" }, ++ { "*DES (BSDi), 6th char invalid {", 9, "_J9..M{Hn" }, ++ { "*DES (BSDi), 7th char invalid {", 9, "_J9..MJ{n" }, ++ { "*DES (BSDi), 8th char invalid {", 9, "_J9..MJH{" }, ++#endif ++#if INCLUDE_md5 ++ { "MD5 (FreeBSD)", 12, "$1$MJHnaAke$" }, ++#endif ++#if INCLUDE_sunmd5 ++ { "MD5 (Sun, plain)", 14, "$md5$1xMeE.at$" }, ++ { "MD5 (Sun, rounds)", 25, "$md5,rounds=123$1xMeE.at$" }, ++#endif ++#if INCLUDE_nthash ++ { "NTHASH (bare)", 3, "$3$" }, ++ { "NTHASH (fake salt)", 3, "$3$__not_used__c809a450df09a3" }, ++#endif ++#if INCLUDE_sha1 ++ { "HMAC-SHA1", 27, "$sha1$123$GGXpNqoJvglVTkGU$" }, ++#endif ++#if INCLUDE_sha256 ++ { "SHA-256 (plain)", 20, "$5$MJHnaAkegEVYHsFK$" }, ++ { "SHA-256 (rounds)", 32, "$5$rounds=1000$MJHnaAkegEVYHsFK$" }, ++#endif ++#if INCLUDE_sha512 ++ { "SHA-512 (plain)", 20, "$6$MJHnaAkegEVYHsFK$" }, ++ { "SHA-512 (rounds)", 32, "$6$rounds=1000$MJHnaAkegEVYHsFK$" }, ++#endif ++#if INCLUDE_bcrypt ++ { "bcrypt (a04)", 29, "$2a$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "bcrypt (b04)", 29, "$2b$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "bcrypt (x04)", 29, "$2x$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "bcrypt (y04)", 29, "$2y$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++#endif ++}; ++ ++static bool ++check_results (const char *label, const char *fn, ++ const char *retval, const char *setting, ++ bool expected_to_succeed) ++{ ++ size_t l_setting = strlen (setting); ++ if (expected_to_succeed) ++ { ++ if (retval[0] == '*' || ++ strncmp (retval, setting, ++ (setting[l_setting - 1] == '*') ? l_setting - 1 : l_setting)) ++ { ++ printf ("FAIL: %s/%s/%s: expected success, got non-matching %s\n", ++ label, setting, fn, retval); ++ return false; ++ } ++ } ++ else ++ { ++ if (retval[0] != '*' || ++ (l_setting >= 2 && !strncmp (retval, setting, l_setting))) ++ { ++ printf ("FAIL: %s/%s/%s: expected failure, got %s\n", ++ label, setting, fn, retval); ++ return false; ++ } ++ } ++ return true; ++} ++ ++static bool ++check_crypt (const char *label, const char *fn, ++ const char *retval, const char *setting, ++ bool expected_to_succeed) ++{ ++ /* crypt/crypt_r should never return null */ ++ if (!retval) ++ { ++ printf ("FAIL: %s/%s/%s: returned NULL\n", label, setting, fn); ++ return false; ++ } ++ if (!check_results (label, fn, retval, setting, ++ expected_to_succeed)) ++ return false; ++ return true; ++} ++ ++static bool ++check_crypt_rn (const char *label, const char *fn, ++ const char *retval, const char *output, ++ const char *setting, bool expected_to_succeed) ++{ ++ bool ok = true; ++ if (expected_to_succeed) ++ { ++ if (!retval) ++ { ++ printf ("FAIL: %s/%s/%s: returned NULL\n", label, setting, fn); ++ ok = false; ++ } ++ else if (retval != output) ++ { ++ printf ("FAIL: %s/%s/%s: returned %p but output is %p\n", ++ label, setting, fn, ++ (const void *)retval, (const void *)output); ++ ok = false; ++ } ++ } ++ else ++ { ++ if (retval) ++ { ++ printf ("FAIL: %s/%s/%s: returned %p (output is %p), " ++ "should be NULL\n", ++ label, setting, fn, ++ (const void *)retval, (const void *)output); ++ ok = false; ++ } ++ } ++ if (!check_results (label, fn, output, setting, ++ expected_to_succeed)) ++ ok = false; ++ return ok; ++} ++ ++static bool ++test_one_setting (const char *label, const char *setting, ++ struct crypt_data *cd, bool expected_to_succeed) ++{ ++ bool ok = true; ++ const char *retval; ++ int cdsize = (int) sizeof (struct crypt_data); ++#ifdef VERBOSE ++ printf ("%s: testing %s (expect: %s)\n", label, setting, ++ expected_to_succeed ? "succeed" : "fail"); ++#endif ++ retval = crypt (phrase, setting); ++ if (!check_crypt (label, "crypt", retval, setting, expected_to_succeed)) ++ ok = false; ++ ++ retval = crypt_r (phrase, setting, cd); ++ if (!check_crypt (label, "crypt_r", retval, setting, expected_to_succeed)) ++ ok = false; ++ ++ retval = crypt_rn (phrase, setting, cd, cdsize); ++ if (!check_crypt_rn (label, "crypt_rn", retval, cd->output, ++ setting, expected_to_succeed)) ++ ok = false; ++ ++ retval = crypt_ra (phrase, setting, (void **)&cd, &cdsize); ++ if (!check_crypt_rn (label, "crypt_ra", retval, cd->output, ++ setting, expected_to_succeed)) ++ ok = false; ++ return ok; ++} ++ ++static bool ++test_one_case (const struct testcase *t, ++ char *page, size_t pagesize, ++ struct crypt_data *cd) ++{ ++ memset (page, 'a', pagesize); ++ ++ size_t l_setting = strlen (t->setting); ++ assert (l_setting <= pagesize); ++ if (t->label[0] == '*') ++ { ++ /* Hashing with this setting is expected to fail already. ++ We still want to verify that we do not read past the end of ++ the string. */ ++ char *p = page + pagesize - (l_setting + 1); ++ memcpy (p, t->setting, l_setting + 1); ++ if (!test_one_setting (t->label + 1, p, cd, false)) ++ return false; ++ printf ("PASS: %s\n", t->label + 1); ++ return true; ++ } ++ else ++ { ++ /* Hashing with this setting is expected to succeed. */ ++ char goodhash[CRYPT_OUTPUT_SIZE]; ++ char *result = crypt_rn (phrase, t->setting, cd, ++ sizeof (struct crypt_data)); ++ if (!result) ++ { ++ printf ("FAIL: %s: initial hash returned NULL/%s (%s)\n", ++ t->label, cd->output, strerror (errno)); ++ return 1; ++ } ++ ++ size_t l_hash = strlen (result); ++ assert (l_hash + 1 <= CRYPT_OUTPUT_SIZE); ++ ++ memcpy (goodhash, result, l_hash + 1); ++ ++ char *p = page + pagesize - (l_hash + 1); ++ memcpy (p, goodhash, l_hash + 1); ++ ++ /* Rechecking the hash with the full output should succeed. */ ++ if (!test_one_setting (t->label, p, cd, true)) ++ return false; ++ ++ /* Recomputing the hash with its own prefix should produce a ++ hash with the same prefix. */ ++ p = page + pagesize - (t->plen + 1); ++ memcpy (p, goodhash, t->plen); ++ p[t->plen] = '\0'; ++ if (!test_one_setting (t->label, p, cd, true)) ++ return false; ++ ++ /* An invalid character after the prefix should not affect the ++ result of the hash computation. */ ++ p = page + pagesize - (t->plen + 2); ++ memcpy (p, goodhash, t->plen); ++ p[t->plen] = '*'; ++ p[t->plen+1] = '\0'; ++ if (!test_one_setting (t->label, p, cd, true)) ++ return false; ++ ++ /* However, an invalid character anywhere within the prefix should ++ cause hashing to fail. */ ++ for (size_t i = 1; i < t->plen; i++) ++ { ++ p = page + pagesize - (t->plen + 2 - i); ++ memcpy (p, goodhash, t->plen - i); ++ if (!test_one_setting (t->label, p, cd, false)) ++ return false; ++ } ++ printf ("PASS: %s\n", t->label); ++ return true; ++ } ++} ++ ++int ++main (void) ++{ ++ /* Set up a two-page region whose first page is read-write and ++ whose second page is inaccessible. */ ++ size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); ++ char *page = mmap (0, pagesize * 2, PROT_READ|PROT_WRITE, ++ MAP_PRIVATE|MAP_ANON, -1, 0); ++ if (page == MAP_FAILED) ++ { ++ perror ("mmap"); ++ return 1; ++ } ++ memset (page, 'x', pagesize * 2); ++ if (mprotect (page + pagesize, pagesize, PROT_NONE)) ++ { ++ perror ("mprotect"); ++ return 1; ++ } ++ ++ struct crypt_data cd; ++ memset (&cd, 0, sizeof cd); ++ ++ bool ok = true; ++ for (size_t i = 0; i < ARRAY_SIZE (testcases); i++) ++ if (!test_one_case (&testcases[i], page, pagesize, &cd)) ++ ok = false; ++ ++ return ok ? 0 : 1; ++} +diff --git a/test-crypt-badsalt.c b/test-crypt-badsalt.c +deleted file mode 100644 +index 8ce7401..0000000 +--- a/test-crypt-badsalt.c ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* Test program for bad DES salt detection in crypt. +- Copyright (C) 2012-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include "crypt-port.h" +-#include +-#include +-#include +-#include +-#include +- +-static const char *tests[][3] = +-{ +-#if INCLUDE_des || INCLUDE_des_big +- { "no salt", "", "..ogcgXxFhnjI" /* valid setting */ }, +-#endif +- { "single char", "/", "*0" /* invalid setting */ }, +- { "first char bad", "!x", "*0" /* invalid setting */ }, +- { "second char bad", "Z%", "*0" /* invalid setting */ }, +- { "both chars bad", ":@", "*0" /* invalid setting */ }, +- { "un$upported algorithm", "$2$", "*0" /* invalid setting */ }, +- { "un$upported $etting", "$2a$", "*0" /* invalid setting */ }, +- { "un$upported $etting", "$2b$", "*0" /* invalid setting */ }, +- { "un$upported $etting", "$2x$", "*0" /* invalid setting */ }, +- { "bad salt for BSDi", "_1", "*0" /* invalid setting */ }, +- { "end of page", NULL, "*0" /* invalid setting */ } +-}; +- +-int +-main (void) +-{ +- int cdsize = sizeof (struct crypt_data); +- int result = 0; +- struct crypt_data cd; +- struct crypt_data *cdptr = &cd; +- size_t n = ARRAY_SIZE (tests); +- size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); +- char *page, *retval; +- const char *saltstr, *special = "%"; +- +- /* Check that crypt won't look at the second character if the first +- one is invalid. */ +- page = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE, +- MAP_PRIVATE | MAP_ANON, -1, 0); +- if (page == MAP_FAILED) +- { +- perror ("mmap"); +- n--; +- } +- else +- { +- if (mmap (page + pagesize, pagesize, 0, +- MAP_PRIVATE | MAP_ANON | MAP_FIXED, +- -1, 0) != page + pagesize) +- perror ("mmap 2"); +- page[pagesize - 1] = special[0]; +- tests[n - 1][1] = &page[pagesize - 1]; +- } +- +- /* Mark cd as initialized before first call to crypt_r. */ +- cd.initialized = 0; +- +- for (size_t i = 0; i < n; i++) +- { +- retval = crypt (tests[i][0], tests[i][1]); +- if (strcmp (tests[i][2], retval)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt returned wrong magic value with salt \"%s\".\n", +- tests[i][0], saltstr); +- printf (" expected: \"%s\"\n got: \"%s\"\n\n", +- tests[i][2], retval); +- } +- +- retval = crypt_r (tests[i][0], tests[i][1], &cd); +- if (strcmp (tests[i][2], retval)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt_r returned wrong magic value with salt \"%s\".\n", +- tests[i][0], saltstr); +- printf (" expected: \"%s\"\n got: \"%s\"\n\n", +- tests[i][2], retval); +- } +- +- crypt_rn (tests[i][0], tests[i][1], cdptr, cdsize); +- retval = cd.output; +- if (strcmp (tests[i][2], retval)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt_rn returned wrong magic value with salt \"%s\".\n", +- tests[i][0], saltstr); +- printf (" expected: \"%s\"\n got: \"%s\"\n\n", +- tests[i][2], retval); +- } +- +- crypt_ra (tests[i][0], tests[i][1], (void **)&cdptr, &cdsize); +- retval = cd.output; +- if (strcmp (tests[i][2], retval)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt_ra returned wrong magic value with salt \"%s\".\n", +- tests[i][0], saltstr); +- printf (" expected: \"%s\"\n got: \"%s\"\n\n", +- tests[i][2], retval); +- } +- } +- +- return result; +-} +diff --git a/test-crypt-nonnull.c b/test-crypt-nonnull.c +deleted file mode 100644 +index e4738ff..0000000 +--- a/test-crypt-nonnull.c ++++ /dev/null +@@ -1,97 +0,0 @@ +-/* Test program for bad DES salt detection in crypt. +- Copyright (C) 2012-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include "crypt-port.h" +-#include +-#include +-#include +-#include +-#include +- +-static const char *tests[][3] = +-{ +- { "single char", "/" }, +- { "first char bad", "!x" }, +- { "second char bad", "Z%" }, +- { "both chars bad", ":@" }, +- { "un$upported algorithm", "$2$" }, +- { "un$upported $etting", "$2a$" }, +- { "un$upported $etting", "$2b$" }, +- { "un$upported $etting", "$2x$" }, +- { "bad salt for BSDi", "_1" }, +- { "end of page", NULL } +-}; +- +-int +-main (void) +-{ +- int cdsize = sizeof (struct crypt_data); +- int result = 0; +- struct crypt_data cd; +- struct crypt_data *cdptr = &cd; +- size_t n = ARRAY_SIZE (tests); +- size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); +- char *page; +- const char *saltstr, *special = "%"; +- +- /* Check that crypt won't look at the second character if the first +- one is invalid. */ +- page = mmap (NULL, pagesize * 2, PROT_READ | PROT_WRITE, +- MAP_PRIVATE | MAP_ANON, -1, 0); +- if (page == MAP_FAILED) +- { +- perror ("mmap"); +- n--; +- } +- else +- { +- if (mmap (page + pagesize, pagesize, 0, +- MAP_PRIVATE | MAP_ANON | MAP_FIXED, +- -1, 0) != page + pagesize) +- perror ("mmap 2"); +- page[pagesize - 1] = special[0]; +- tests[n - 1][1] = &page[pagesize - 1]; +- } +- +- for (size_t i = 0; i < n; i++) +- { +- if (crypt_rn (tests[i][0], tests[i][1], cdptr, cdsize)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt_rn returned non-NULL with salt \"%s\"\n", +- tests[i][0], saltstr); +- } +- +- if (crypt_ra (tests[i][0], tests[i][1], (void **)&cdptr, &cdsize)) +- { +- result++; +- if (memcmp (&page[pagesize - 1], tests[i][1], 1) != 0) +- saltstr = tests[i][1]; +- else +- saltstr = special; +- printf ("%s: crypt_ra returned non-NULL with salt \"%s\"\n", +- tests[i][0], saltstr); +- } +- } +- +- return result; +-} +diff --git a/test-gensalt.c b/test-gensalt.c +index b81fcf0..5b9d64c 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -18,7 +18,8 @@ static const char *const entropy[] = + static const char *const des_expected_output[] = { "Mp", "Pp", "ZH", "Uh"}; + #endif + #if INCLUDE_des_xbsd +-static const char *const bsdi_expected_output[] = { ++static const char *const bsdi_expected_output[] = ++{ + "_J9..MJHn", + "_J9..PKXc", + "_J9..ZAFl", +@@ -26,7 +27,8 @@ static const char *const bsdi_expected_output[] = { + }; + #endif + #if INCLUDE_md5 +-static const char *const md5_expected_output[] = { ++static const char *const md5_expected_output[] = ++{ + "$1$MJHnaAke", + "$1$PKXc3hCO", + "$1$ZAFlICwY", +@@ -34,7 +36,8 @@ static const char *const md5_expected_output[] = { + }; + #endif + #if INCLUDE_nthash +-static const char *const nthash_expected_output[] = { ++static const char *const nthash_expected_output[] = ++{ + "$3$__not_used__c809a450df09a3", + "$3$__not_used__30d0d6f834c0c3", + "$3$__not_used__0eeeebb83d6fe4", +@@ -48,7 +51,8 @@ static const char *const nthash_expected_output[] = { + #define pbkdf_expected_output 0 /* output is not deterministic */ + #endif + #if INCLUDE_sha256 +-static const char *const sha256_expected_output[] = { ++static const char *const sha256_expected_output[] = ++{ + "$5$MJHnaAkegEVYHsFK", + "$5$PKXc3hCOSyMqdaEQ", + "$5$ZAFlICwYRETzIzIj", +@@ -56,7 +60,8 @@ static const char *const sha256_expected_output[] = { + }; + #endif + #if INCLUDE_sha512 +-static const char *const sha512_expected_output[] = { ++static const char *const sha512_expected_output[] = ++{ + "$6$MJHnaAkegEVYHsFK", + "$6$PKXc3hCOSyMqdaEQ", + "$6$ZAFlICwYRETzIzIj", +@@ -64,25 +69,29 @@ static const char *const sha512_expected_output[] = { + }; + #endif + #if INCLUDE_bcrypt +-static const char *const bcrypt_a_expected_output[] = { ++static const char *const bcrypt_a_expected_output[] = ++{ + "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO", + "$2a$05$kxUgPcrmlm9XoOjvxCyfP.", + "$2a$05$HPNDjKMRFdR7zC87CMSmA.", + "$2a$05$mAyzaIeJu41dWUkxEbn8hO" + }; +-static const char *const bcrypt_b_expected_output[] = { ++static const char *const bcrypt_b_expected_output[] = ++{ + "$2b$05$UBVLHeMpJ/QQCv3XqJx8zO", + "$2b$05$kxUgPcrmlm9XoOjvxCyfP.", + "$2b$05$HPNDjKMRFdR7zC87CMSmA.", + "$2b$05$mAyzaIeJu41dWUkxEbn8hO" + }; +-static const char *const bcrypt_x_expected_output[] = { ++static const char *const bcrypt_x_expected_output[] = ++{ + "$2x$05$UBVLHeMpJ/QQCv3XqJx8zO", + "$2x$05$kxUgPcrmlm9XoOjvxCyfP.", + "$2x$05$HPNDjKMRFdR7zC87CMSmA.", + "$2x$05$mAyzaIeJu41dWUkxEbn8hO" + }; +-static const char *const bcrypt_y_expected_output[] = { ++static const char *const bcrypt_y_expected_output[] = ++{ + "$2y$05$UBVLHeMpJ/QQCv3XqJx8zO", + "$2y$05$kxUgPcrmlm9XoOjvxCyfP.", + "$2y$05$HPNDjKMRFdR7zC87CMSmA.", +@@ -167,8 +176,8 @@ main (void) + } + size_t slen = strlen (salt); + unsigned int expected_len = +- (!entropy[ent] && tcase->expected_auto_len) ? +- tcase->expected_auto_len : tcase->expected_len; ++ (!entropy[ent] && tcase->expected_auto_len) ? ++ tcase->expected_auto_len : tcase->expected_len; + if (slen != expected_len) + { + fprintf (stderr, + +From 58ac83090e107aa628a5be252931a2b8b0f286cf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= +Date: Sun, 8 Jul 2018 23:59:53 +0200 +Subject: [PATCH 19/38] Fix Werror=stringop-truncation + +--- + test-gensalt.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/test-gensalt.c b/test-gensalt.c +index 5b9d64c..c08627e 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -208,9 +208,8 @@ main (void) + fprintf (stderr, " ok: %s/%u -> %s\n", + tcase->prefix, ent, salt); + +- /* Note: strncpy's somewhat odd fill-to-size-with-NULs behavior +- is specifically wanted in this case. */ +- strncpy (prev_output, salt, CRYPT_GENSALT_OUTPUT_SIZE); ++ XCRYPT_SECURE_MEMSET (prev_output, CRYPT_GENSALT_OUTPUT_SIZE); ++ strncpy (prev_output, salt, CRYPT_GENSALT_OUTPUT_SIZE -1 ); + } + } + + +From 98043c5be0ed8a09dfd49ad04b179c017ac78677 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= +Date: Mon, 9 Jul 2018 00:49:19 +0200 +Subject: [PATCH 20/38] Fix DNF config for DNF v3.x + +--- + .travis.dnf.conf.rawhide_latest | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/.travis.dnf.conf.rawhide_latest b/.travis.dnf.conf.rawhide_latest +index ee4370a..52b55b0 100644 +--- a/.travis.dnf.conf.rawhide_latest ++++ b/.travis.dnf.conf.rawhide_latest +@@ -1,5 +1,5 @@ +-[latest_$basearch] +-name=Fedora - Rawhide Build - Fresh builds served by Koji - $basearch ++[latest_native] ++name=Fedora - Rawhide Build - Fresh builds served by Koji - native + failovermethod=priority + baseurl=https://kojipkgs.fedoraproject.org/repos/rawhide/latest/$basearch + enabled=1 + +From c14b7ae156e4dfb21c4c2506eb6d44e98eaa6f29 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= +Date: Mon, 9 Jul 2018 11:42:05 +0200 +Subject: [PATCH 21/38] Extend badsalt tests and fix invalid pass + +--- + test-badsalt.c | 53 +++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 37 insertions(+), 16 deletions(-) + +diff --git a/test-badsalt.c b/test-badsalt.c +index 41d164a..6d57b14 100644 +--- a/test-badsalt.c ++++ b/test-badsalt.c +@@ -35,21 +35,24 @@ struct testcase + static const struct testcase testcases[] = + { + /* These strings are invalid regardless of the algorithm. */ +- { "*too short", 1, "/" }, +- { "*invalid char :", 1, ":" }, +- { "*invalid char ;", 1, ";" }, +- { "*invalid char *", 1, "*" }, +- { "*invalid char !", 1, "!" }, +- { "*invalid char \\", 1, "\\" }, +- { "*invalid white 1", 1, " " }, +- { "*invalid white 2", 1, "\t" }, +- { "*invalid white 3", 1, "\r" }, +- { "*invalid white 4", 1, "\n" }, +- { "*invalid white 5", 1, "\f" }, +- { "*invalid ctrl 1", 1, "\1" }, +- { "*invalid ctrl 2", 1, "\177" }, +- { "*failure token 1", 2, "*0" }, +- { "*failure token 2", 2, "*1" }, ++ { "*too short", 1, "/" }, ++ { "*invalid char :", 1, ":" }, ++ { "*invalid char ;", 1, ";" }, ++ { "*invalid char *", 1, "*" }, ++ { "*invalid char !", 1, "!" }, ++ { "*invalid char \\", 1, "\\" }, ++ { "*invalid white 1", 1, " " }, ++ { "*invalid white 2", 1, "\t" }, ++ { "*invalid white 3", 1, "\r" }, ++ { "*invalid white 4", 1, "\n" }, ++ { "*invalid white 5", 1, "\f" }, ++ { "*invalid ctrl 1", 1, "\1" }, ++ { "*invalid ctrl 2", 1, "\177" }, ++ { "*failure token 1", 2, "*0" }, ++ { "*failure token 2", 2, "*1" }, ++ { "*bcrypt invalid salt", 3, "$2$" }, ++ { "*unsupported algorithm", 13, "$un$upp0rt3d$" }, ++ { "*empty string", 1, "\0" }, + + /* Each of these is a valid setting string for some algorithm, + from which we will derive many invalid setting strings. +@@ -114,10 +117,14 @@ static const struct testcase testcases[] = + #endif + #if INCLUDE_md5 + { "MD5 (FreeBSD)", 12, "$1$MJHnaAke$" }, ++ { "*MD5 (FreeBSD) invalid char", 12, "$1$:JHnaAke$" }, + #endif + #if INCLUDE_sunmd5 + { "MD5 (Sun, plain)", 14, "$md5$1xMeE.at$" }, ++ { "*MD5 (Sun, plain) invalid char", 14, "$md5$:xMeE.at$" }, + { "MD5 (Sun, rounds)", 25, "$md5,rounds=123$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid char", 25, "$md5,rounds=123$:xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds", 25, "$md5,rounds=:23$1xMeE.at$" }, + #endif + #if INCLUDE_nthash + { "NTHASH (bare)", 3, "$3$" }, +@@ -125,20 +132,34 @@ static const struct testcase testcases[] = + #endif + #if INCLUDE_sha1 + { "HMAC-SHA1", 27, "$sha1$123$GGXpNqoJvglVTkGU$" }, ++ { "*HMAC-SHA1 invalid char", 27, "$sha1$123$:GXpNqoJvglVTkGU$" }, ++ { "*HMAC-SHA1 invalid rounds", 27, "$sha1$:23$GGXpNqoJvglVTkGU$" }, + #endif + #if INCLUDE_sha256 + { "SHA-256 (plain)", 20, "$5$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (plain) invalid char", 20, "$5$:JHnaAkegEVYHsFK$" }, + { "SHA-256 (rounds)", 32, "$5$rounds=1000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds", 32, "$5$rounds=:000$MJHnaAkegEVYHsFK$" }, + #endif + #if INCLUDE_sha512 + { "SHA-512 (plain)", 20, "$6$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (plain) invalid char", 20, "$6$:JHnaAkegEVYHsFK$" }, + { "SHA-512 (rounds)", 32, "$6$rounds=1000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds", 32, "$6$rounds=:000$MJHnaAkegEVYHsFK$" }, + #endif + #if INCLUDE_bcrypt + { "bcrypt (a04)", 29, "$2a$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (a04) invalid char", 29, "$2a$04$:BVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (a04) invalid rounds", 29, "$2a$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (b04)", 29, "$2b$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (b04) invalid char", 29, "$2b$04$:BVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (b04) invalid rounds", 29, "$2b$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (x04)", 29, "$2x$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (x04) invalid char", 29, "$2x$04$:BVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (x04) invalid rounds", 29, "$2x$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (y04)", 29, "$2y$04$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (y04) invalid char", 29, "$2y$04$:BVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (y04) invalid rounds", 29, "$2y$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, + #endif + }; + +@@ -289,7 +310,7 @@ test_one_case (const struct testcase *t, + { + printf ("FAIL: %s: initial hash returned NULL/%s (%s)\n", + t->label, cd->output, strerror (errno)); +- return 1; ++ return false; + } + + size_t l_hash = strlen (result); + +From 820e5b242e648347e9c9e4110e75842b3d6531e5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= +Date: Mon, 9 Jul 2018 15:25:54 +0200 +Subject: [PATCH 22/38] Add test for short output buffers + +--- + Makefile.am | 3 ++- + test-short-outbuf.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 74 insertions(+), 1 deletion(-) + create mode 100644 test-short-outbuf.c + +diff --git a/Makefile.am b/Makefile.am +index 79d59d7..fec069e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -126,7 +126,7 @@ check_PROGRAMS = \ + test-crypt-md5 test-crypt-nthash \ + test-crypt-pbkdf1-sha1 test-crypt-sha256 test-crypt-sha512 \ + test-crypt-sunmd5 \ +- test-byteorder test-badsalt test-gensalt ++ test-byteorder test-badsalt test-gensalt test-short-outbuf + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +@@ -169,6 +169,7 @@ test_badsalt_LDADD = libcrypt.la + test_gensalt_LDADD = libcrypt.la + test_des_obsolete_LDADD = libcrypt.la + test_des_obsolete_r_LDADD = libcrypt.la ++test_short_outbuf_LDADD = libcrypt.la + + # These tests call internal APIs that may not be accessible from the + # fully linked shared library. +diff --git a/test-short-outbuf.c b/test-short-outbuf.c +new file mode 100644 +index 0000000..7ab9d11 +--- /dev/null ++++ b/test-short-outbuf.c +@@ -0,0 +1,72 @@ ++#include "crypt-port.h" ++#include ++#include ++#include ++#include ++ ++struct testcase ++{ ++ const char *exp_rn; ++ const char *exp_ra; ++}; ++ ++static const struct testcase testcases[] = ++{ ++ { "", "*0" }, ++ { "*", "*0" }, ++ { "*0", "*0" }, ++}; ++ ++int ++main (void) ++{ ++ bool ok = true; ++ char **outbuf = malloc (sizeof (char*)); ++ char result[5]; ++ ++ for (size_t i = 0; i < ARRAY_SIZE (testcases); i++) ++ { ++ size_t *j = malloc (sizeof (size_t)); ++ ++ *j = i + 1; ++ ++ *outbuf = malloc (sizeof (char*) * *j); ++ ++ crypt_rn ("@@", "@@", *outbuf, (int) *j); ++ ++ if (!strncmp (testcases[i].exp_rn, *outbuf, *j)) ++ { ++ strcpy (result, "PASS"); ++ } ++ else ++ { ++ strcpy (result, "FAIL"); ++ ok = false; ++ } ++ ++ printf ("Test %lu.0: %s, expected: \"%-2s\", got: \"%-2s\"\n", ++ i + 1, result, testcases[i].exp_rn, *outbuf); ++ ++ crypt_ra ("@@", "@@", (void **) outbuf, (int *) j); ++ ++ if (!strncmp (testcases[i].exp_ra, *outbuf, strlen(*outbuf))) ++ { ++ strcpy (result, "PASS"); ++ } ++ else ++ { ++ strcpy (result, "FAIL"); ++ ok = false; ++ } ++ ++ printf ("Test %lu.1: %s, expected: \"%-2s\", got: \"%-2s\"\n", ++ i + 1, result, testcases[i].exp_ra, *outbuf); ++ ++ free (j); ++ free (*outbuf); ++ } ++ ++ free (outbuf); ++ ++ return ok ? 0 : 1; ++} + +From 9197a77826124683e39ef123f5e57058e358e225 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 10 Jul 2018 12:06:10 -0400 +Subject: [PATCH 23/38] Replace crypt-sunmd5.c with BSD-licensed cleanroom + reimplementation. + +This eliminates all CDDL-licensed code from the library, as requested +in issue #7 because of GPL incompatibility. + +The new implementation was based exclusively on the prose description +of the algorithm in the Passlib v1.7.1 documentation, which should be +adequately arms-length for copyright purposes. (N.B. the lengthy +quotation from _Hamlet_ is used as input to MD5, so it must remain +byte-for-byte identical to achieve interoperability with the original; +also, the play itself is in the public domain.) + +The new implementation is also fully deterministic (that is, its +gensalt procedure draws randomness only from its rbytes argument) and +does not call malloc. +--- + LICENSING | 2 +- + crypt-sunmd5.c | 543 +++++++++++++++++++++++---------------------------------- + test-gensalt.c | 8 +- + 3 files changed, 225 insertions(+), 328 deletions(-) + +diff --git a/LICENSING b/LICENSING +index b6f5168..b9df920 100644 +--- a/LICENSING ++++ b/LICENSING +@@ -28,7 +28,7 @@ source tree. For specific licensing terms consult the files themselves. + * Copyright Michael Bretterklieber, Björn Esser et al.; 2-clause BSD: + crypt-nthash.c + +- * Copyright Sun Microsystems, Inc., Björn Esser; CDDL-1.0: ++ * Copyright Zack Weinberg; 2-clause BSD: + crypt-sunmd5.c + + * Public domain, written by Steve Reid et al.: +diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c +index f3c84a8..9107052 100644 +--- a/crypt-sunmd5.c ++++ b/crypt-sunmd5.c +@@ -1,27 +1,31 @@ +-/* +- * CDDL HEADER START ++/* Copyright (c) 2018 Zack Weinberg. ++ * All rights reserved. + * +- * The contents of this file are subject to the terms of the +- * Common Development and Distribution License, Version 1.0 only +- * (the "License"). You may not use this file except in compliance +- * with the License. ++ * 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. + * +- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +- * or http://www.opensolaris.org/os/licensing. +- * See the License for the specific language governing permissions +- * and limitations under the License. ++ * 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. + * +- * When distributing Covered Code, include this CDDL HEADER in each +- * file and include the License file at usr/src/OPENSOLARIS.LICENSE. +- * If applicable, add the following below this CDDL HEADER, with the +- * fields enclosed by brackets "[]" replaced with your own identifying +- * information: Portions Copyright [yyyy] [name of copyright owner] +- * +- * CDDL HEADER END +- */ +-/* +- * Copyright 2003 Sun Microsystems, Inc. All rights reserved. +- * Use is subject to license terms. ++ * This is a clean-room reimplementation of the Sun-MD5 password hash, ++ * based on the prose description of the algorithm in the Passlib v1.7.1 ++ * documentation: ++ * https://passlib.readthedocs.io/en/stable/lib/passlib.hash.sun_md5_crypt.html + */ + + #include "crypt-port.h" +@@ -34,21 +38,21 @@ + + #if INCLUDE_sunmd5 + +- +-#define CRYPT_ALGNAME "md5" +- +-/* minimum number of rounds we do, not including the per-user ones */ +-#define BASIC_ROUND_COUNT 4096 /* enough to make things interesting */ +-#define DIGEST_LEN 16 +-#define ROUND_BUFFER_LEN 64 +- +-/* +- * Public domain quotation courtesy of Project Gutenberg. +- * ftp://metalab.unc.edu/pub/docs/books/gutenberg/etext98/2ws2610.txt +- * Hamlet III.ii - 1517 bytes, including trailing NUL +- * ANSI-C string constant concatenation is a requirement here. +- */ +-static const char constant_phrase[] = ++#define SUNMD5_PREFIX "$md5" ++#define SUNMD5_PREFIX_LEN 4 ++#define SUNMD5_SALT_LEN 8 ++#define SUNMD5_MAX_SETTING_LEN 32 /* $md5,rounds=4294963199$12345678$ */ ++#define SUNMD5_BARE_OUTPUT_LEN 22 /* not counting the setting or the NUL */ ++#define SUNMD5_MAX_ROUNDS (0xFFFFFFFF - 4096) ++ ++/* At each round of the algorithm, this string (including the trailing ++ NUL) may or may not be included in the input to MD5, depending on a ++ pseudorandom coin toss. It is Hamlet's famous soliloquy from the ++ play of the same name, which is in the public domain. Text from ++ with double ++ blank lines replaced with `\n`. Note that more recent Project ++ Gutenberg editions of _Hamlet_ are punctuated differently. */ ++static const char hamlet_quotation[] = + "To be, or not to be,--that is the question:--\n" + "Whether 'tis nobler in the mind to suffer\n" + "The slings and arrows of outrageous fortune\n" +@@ -85,346 +89,233 @@ static const char constant_phrase[] = + "The fair Ophelia!--Nymph, in thy orisons\n" + "Be all my sins remember'd.\n"; + +-/* ------------------------------------------------------------------ */ +- +-static int +-md5bit (uint8_t *digest, int bit_num) ++/* Decide, pseudorandomly, whether or not to include the above quotation ++ in the input to MD5. */ ++static inline bool ++get_nth_bit (const uint8_t digest[16], unsigned int n) + { +- int byte_off; +- int bit_off; +- +- bit_num %= 128; /* keep this bounded for convenience */ +- byte_off = bit_num / 8; +- bit_off = bit_num % 8; +- +- /* return the value of bit N from the digest */ +- return ((digest[byte_off] & (0x01 << bit_off)) ? 1 : 0); ++ unsigned int byte = (n % 128) / 8; ++ unsigned int bit = (n % 128) % 8; ++ return !!(digest[byte] & (1 << bit)); + } + +-/* 0 ... 63 => ascii - 64 */ +-static unsigned char itoa64[] = +- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +- +-static void +-to64 (char *s, uint64_t v, int n) ++static bool ++muffet_coin_toss (const uint8_t prev_digest[16], unsigned int round_count) + { +- while (--n >= 0) ++ unsigned int x, y, a, b, r, v, i; ++ for (i = 0, x = 0, y = 0; i < 8; i++) + { +- *s++ = (char)itoa64[v&0x3f]; +- v >>= 6; ++ a = prev_digest[(i + 0) % 16]; ++ b = prev_digest[(i + 3) % 16]; ++ r = a >> (b % 5); ++ v = prev_digest[r % 16]; ++ if (b & (1u << (a % 8))) ++ v /= 2; ++ x |= ((unsigned int) +get_nth_bit (prev_digest, v)) << i; ++ ++ a = prev_digest[(i + 8) % 16]; ++ b = prev_digest[(i + 11) % 16]; ++ r = a >> (b % 5); ++ v = prev_digest[r % 16]; ++ if (b & (1u << (a % 8))) ++ v /= 2; ++ y |= ((unsigned int) +get_nth_bit (prev_digest, v)) << i; + } +-} + +-#define ROUNDS ",rounds=" +-#define ROUNDSLEN (sizeof (ROUNDS) - 1) ++ if (get_nth_bit (prev_digest, round_count)) ++ x /= 2; ++ if (get_nth_bit (prev_digest, round_count + 64)) ++ y /= 2; + +-/* +- * get the integer value after ,rounds= if present +- * s should point immediately after $md5 +- * set *puresalt one character after the dollar sign after +- * the number of rounds (if present) or to NULL if the syntax +- * is invalid +- */ +-static uint32_t +-getrounds (const char *s, const char **puresalt) +-{ +- const char *p; +- char *e; +- long val; +- +- *puresalt = 0; +- +- if (s == NULL) +- return (0); ++ return !!(get_nth_bit (prev_digest, x) ^ get_nth_bit (prev_digest, y)); ++} + +- if (*s == '$') +- { +- *puresalt = s + 1; +- return (0); +- } ++/* itoa64 output utilities. */ ++static const unsigned char itoa64[] = ++ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +- if (strncmp (s, ROUNDS, ROUNDSLEN) != 0) +- return (0); +- +- p = s + ROUNDSLEN; +- errno = 0; +- val = strtol (p, &e, 10); +- /* +- * An error occured or there is non-numeric stuff at the end +- * which isn't one of the crypt(3c) special chars ',' or '$' +- */ +- if (errno != 0 || val < 0 || p == e || (*e != '\0' && *e != '$')) +- return (0); +- +- if (*e == '$') +- *puresalt = e + 1; +- else +- *puresalt = e; +- +- return ((uint32_t)val); ++static inline void ++write_itoa64_4 (uint8_t *output, ++ unsigned int b0, unsigned int b1, unsigned int b2) ++{ ++ unsigned int value = (b0 << 0) | (b1 << 8) | (b2 << 16); ++ output[0] = itoa64[value & 0x3f]; ++ output[1] = itoa64[(value >> 6) & 0x3f]; ++ output[2] = itoa64[(value >> 12) & 0x3f]; ++ output[3] = itoa64[(value >> 18) & 0x3f]; + } + +-void +-gensalt_sunmd5_rn (unsigned long count, +- const uint8_t *rbytes, size_t nrbytes, +- uint8_t *output, size_t o_size) ++/* used only for the last two bytes of crypt_sunmd5_rn output */ ++static inline void ++write_itoa64_2 (uint8_t *output, ++ unsigned int b0, unsigned int b1, unsigned int b2) + { +- /* This should not happen, but. */ +- if ((nrbytes < sizeof (uint64_t)) || (o_size < 33)) +- { +- errno = ERANGE; +- return; +- } +- +- uint64_t rndval; +- char rndstr[sizeof (rndval) + 1]; /* rndval as a base64 string */ +- const uint8_t minrounds = 15; /* Min. number of rounds = 2^X */ +- +- /* Set count to a reasonable random value, +- if count was not set high enough by the +- caller. */ +- if (count < (unsigned long)(1 << minrounds)) +- { +- uint64_t rand1, rand2; +- get_random_bytes(&rand1, sizeof (uint64_t)); +- get_random_bytes(&rand2, sizeof (uint64_t)); +- count = (long unsigned int)(1 << ((rand1 % 2) + minrounds)); +- count += (long unsigned int)(rand2 % (uint64_t)((1 << (minrounds - 1)) + 1)); +- } +- +- memcpy (&rndval, rbytes, sizeof (rndval)); +- to64 ((char *)&rndstr, rndval, sizeof (rndval)); +- rndstr[sizeof (rndstr) - 1] = '\0'; +- +- /* Generated salt is at least 27 bytes +- and a maximum of 32 bytes long. */ +- snprintf ((char *)output, o_size, +- "$" CRYPT_ALGNAME ROUNDS "%u$%s$", +- (unsigned int)count, rndstr); ++ unsigned int value = (b0 << 0) | (b1 << 8) | (b2 << 16); ++ output[0] = itoa64[value & 0x3f]; ++ output[1] = itoa64[(value >> 6) & 0x3f]; + } + ++/* Module entry points. */ ++ + void +-crypt_sunmd5_rn (const char *phrase, const char *setting, +- uint8_t *output, size_t o_size, +- void *scratch, size_t s_size) ++crypt_sunmd5_rn (const char *phrase, ++ const char *setting, ++ uint8_t *output, ++ size_t o_size, ++ void *scratch, ++ size_t s_size) + { +- /* put all the sensitive data in a struct */ +- struct sunmd5_ctx ++ struct crypt_sunmd5_scratch + { +- struct md5_ctx context; /* working buffer for MD5 algorithm */ +- uint8_t digest[DIGEST_LEN]; /* where the MD5 digest is stored */ +- +- int indirect_4[16]; /* extracted array of 4bit values */ +- int shift_4[16]; /* shift schedule, vals 0..4 */ +- +- int s7shift; /* shift for shift_7 creation, vals 0..7 */ +- int indirect_7[16]; /* extracted array of 7bit values */ +- int shift_7[16]; /* shift schedule, vals 0..1 */ +- +- int indirect_a; /* 7bit index into digest */ +- int shift_a; /* shift schedule, vals 0..1 */ +- +- int indirect_b; /* 7bit index into digest */ +- int shift_b; /* shift schedule, vals 0..1 */ +- +- int bit_a; /* single bit for cointoss */ +- int bit_b; /* single bit for cointoss */ +- +- char roundascii[ROUND_BUFFER_LEN]; /* ascii rep of roundcount */ ++ struct md5_ctx ctx; ++ uint8_t dg[16]; ++ char rn[16]; + }; + +- /* Scratch space needs to be large enough +- to fit struct sunmd5_ctx. Output must +- be able to fit up to 32 bytes for the +- setting + '$' + 22 bytes of hash. */ +- if (s_size < sizeof (struct sunmd5_ctx) || (o_size < 32 + 1 + 22)) ++ /* If 'setting' doesn't start with the prefix, we should not have ++ been called in the first place. */ ++ if (strncmp (setting, SUNMD5_PREFIX, SUNMD5_PREFIX_LEN) ++ || (setting[SUNMD5_PREFIX_LEN] != '$' ++ && setting[SUNMD5_PREFIX_LEN] != ',')) + { +- errno = ERANGE; ++ errno = EINVAL; + return; + } + +- /* If the magic does not match, this +- should not have been called. */ +- if (!strncmp ("$" CRYPT_ALGNAME, setting, sizeof ("$" CRYPT_ALGNAME))) ++ /* For bug-compatibility with the original implementation, we allow ++ 'rounds=' to follow either '$md5,' or '$md5$'. */ ++ const char *p = setting + SUNMD5_PREFIX_LEN + 1; ++ unsigned int nrounds = 4096; ++ if (!strncmp (p, "rounds=", sizeof "rounds=" - 1)) + { +- errno = EINVAL; +- return; ++ p += sizeof "rounds=" - 1; ++ /* Do not allow an explicit setting of zero additional rounds, ++ nor leading zeroes on the number of rounds. */ ++ if (!(*p >= '1' && *p <= '9')) ++ { ++ errno = EINVAL; ++ return; ++ } ++ ++ errno = 0; ++ char *endp; ++ unsigned long arounds = strtoul (p, &endp, 10); ++ if (endp == p || arounds > SUNMD5_MAX_ROUNDS || errno) ++ { ++ errno = EINVAL; ++ return; ++ } ++ nrounds += (unsigned int)arounds; ++ p = endp; ++ if (*p != '$') ++ { ++ errno = EINVAL; ++ return; ++ } ++ p += 1; + } + +- int i; +- int round; +- uint32_t maxrounds = BASIC_ROUND_COUNT; +- uint32_t l; +- const char *ps = 0; +- const char *saltend = 0; +- char *p, *puresalt; +- struct sunmd5_ctx *data = scratch; +- +- /* +- * Extract the rounds (if it exists) and puresalt from the salt string +- * $md5[,rounds=%d]$$ +- */ +- maxrounds += getrounds (setting + sizeof ("$" CRYPT_ALGNAME) - 1, &ps); +- if (ps) +- saltend = ps + strspn (ps, (char *)itoa64); +- if (!saltend || saltend == ps || saltend[0] != '$') ++ /* p now points to the beginning of the actual salt. */ ++ p += strspn (p, (const char *)itoa64); ++ if (*p != '\0' && *p != '$') + { + errno = EINVAL; + return; + } +- /* For bug-compatibility with the original implementation, if saltend +- points at "$$", advance it to point at the second dollar sign. */ +- if (saltend[0] == '$' && saltend[1] == '$') +- saltend += 1; +- +- if (saltend[1] != '\0') +- { +- size_t len = (size_t)(saltend - setting + 1); +- +- if ((puresalt = malloc (len)) == NULL) +- /* malloc() is supposed to set errno == ENOMEM. */ +- return; +- +- /* The original implementation used strlcpy(), +- which is not portable. Since strlcpy() +- always terminated a C string properly after +- copying len - 1 bytes of data, we need to +- do that manually. */ +- (void)strncpy (puresalt, setting, len); +- puresalt[len - 1] = '\0'; +- } +- else ++ /* For bug-compatibility with the original implementation, if p ++ points to a '$' and the following character is either another '$' ++ or NUL, the first '$' should be included in the salt. */ ++ if (p[0] == '$' && (p[1] == '$' || p[1] == '\0')) ++ p += 1; ++ ++ size_t saltlen = (size_t) (p - setting); ++ /* Do we have enough space? */ ++ if (s_size < sizeof (struct crypt_sunmd5_scratch) ++ || o_size < saltlen + SUNMD5_BARE_OUTPUT_LEN + 2) + { +- puresalt = strdup(setting); +- +- if (puresalt == NULL) +- { +- /* strdup() is supposed to set errno == ENOMEM. */ +- return; +- } ++ errno = ERANGE; ++ return; + } + +- /* initialise the context */ +- md5_init_ctx (&(data->context)); +- +- /* update with the (hopefully entropic) plaintext */ +- md5_process_bytes ((const unsigned char *)phrase, strlen (phrase), &(data->context)); +- +- /* update with the (publically known) salt */ +- md5_process_bytes ((unsigned char *)puresalt, strlen (puresalt), &(data->context)); +- +- +- /* compute the digest */ +- md5_finish_ctx (&(data->context), &(data->digest)); ++ struct crypt_sunmd5_scratch *s = scratch; + +- /* +- * now to delay high-speed md5 implementations that have stuff +- * like code inlining, loops unrolled and table lookup +- */ ++ /* Initial round. */ ++ md5_init_ctx (&s->ctx); ++ md5_process_bytes (phrase, strlen (phrase), &s->ctx); ++ md5_process_bytes (setting, saltlen, &s->ctx); ++ md5_finish_ctx (&s->ctx, s->dg); + +- for (round = 0; (uint32_t)round < maxrounds; round++) ++ /* Stretching rounds. */ ++ for (unsigned int i = 0; i < nrounds; i++) + { +- /* re-initialise the context */ +- md5_init_ctx (&(data->context)); ++ md5_init_ctx (&s->ctx); + +- /* update with the previous digest */ +- md5_process_bytes (&(data->digest), sizeof (data->digest), &(data->context)); ++ md5_process_bytes (s->dg, sizeof s->dg, &s->ctx); + +- /* populate the shift schedules for use later */ +- for (i = 0; i < 16; i++) +- { +- int j; +- +- /* offset 3 -> occasionally span more than 1 int32 fetch */ +- j = (i + 3) % 16; +- data->s7shift = data->digest[i] % 8; +- data->shift_4[i] = data->digest[j] % 5; +- data->shift_7[i] = (data->digest[j] >> data->s7shift) & 0x01; +- } +- +- data->shift_a = md5bit (data->digest, round); +- data->shift_b = md5bit (data->digest, round + 64); +- +- /* populate indirect_4 with 4bit values extracted from digest */ +- for (i = 0; i < 16; i++) +- /* shift the digest byte and extract four bits */ +- data->indirect_4[i] = (data->digest[i] >> data->shift_4[i]) & 0x0f; +- +- /* +- * populate indirect_7 with 7bit values from digest +- * indexed via indirect_4 +- */ ++ /* The trailing nul is intentionally included. */ ++ if (muffet_coin_toss (s->dg, i)) ++ md5_process_bytes (hamlet_quotation, sizeof hamlet_quotation, &s->ctx); + +- for (i = 0; i < 16; i++) +- /* shift the digest byte and extract seven bits */ +- data->indirect_7[i] = (data->digest[data->indirect_4[i]] +- >> data->shift_7[i]) & 0x7f; ++ int nwritten = snprintf (s->rn, sizeof s->rn, "%u", i); ++ assert (nwritten >= 1 && (unsigned int)nwritten + 1 <= sizeof s->rn); ++ md5_process_bytes (s->rn, (unsigned int)nwritten, &s->ctx); + +- /* +- * use the 7bit values to indirect into digest, +- * and create two 8bit values from the results. +- */ +- data->indirect_a = data->indirect_b = 0; ++ md5_finish_ctx (&s->ctx, s->dg); ++ } + +- for (i = 0; i < 8; i++) +- { +- data->indirect_a |= (md5bit (data->digest, +- data->indirect_7[i]) << i); ++ memcpy (output, setting, saltlen); ++ *(output + saltlen + 0) = '$'; ++ /* This is the same permuted order used by BSD md5-crypt ($1$). */ ++ write_itoa64_4 (output + saltlen + 1, s->dg[12], s->dg[ 6], s->dg[0]); ++ write_itoa64_4 (output + saltlen + 5, s->dg[13], s->dg[ 7], s->dg[1]); ++ write_itoa64_4 (output + saltlen + 9, s->dg[14], s->dg[ 8], s->dg[2]); ++ write_itoa64_4 (output + saltlen + 13, s->dg[15], s->dg[ 9], s->dg[3]); ++ write_itoa64_4 (output + saltlen + 17, s->dg[ 5], s->dg[10], s->dg[4]); ++ write_itoa64_2 (output + saltlen + 21, s->dg[11], 0, 0); ++ *(output + saltlen + 23) = '\0'; ++} + +- data->indirect_b |= (md5bit (data->digest, +- data->indirect_7[i + 8]) << i); +- } ++void ++gensalt_sunmd5_rn (unsigned long count, ++ const uint8_t *rbytes, ++ size_t nrbytes, ++ uint8_t *output, ++ size_t o_size) ++{ ++ if (o_size < SUNMD5_MAX_SETTING_LEN + 1 || nrbytes < 6 + 2) ++ { ++ errno = ERANGE; ++ return; ++ } ++ if (count > SUNMD5_MAX_ROUNDS) ++ { ++ errno = EINVAL; ++ return; ++ } + +- /* shall we utilise the top or bottom 7 bits? */ +- data->indirect_a = (data->indirect_a >> data->shift_a) & 0x7f; +- data->indirect_b = (data->indirect_b >> data->shift_b) & 0x7f; ++ /* The default number of rounds, 4096, is much too low. The actual ++ number of rounds is somewhat randomized to make construction of ++ rainbow tables more difficult (effectively this means an extra 16 ++ bits of entropy are smuggled into the salt via the round number). */ ++ if (count < 32768) ++ count = 32768; ++ else if (count + 65536 > SUNMD5_MAX_ROUNDS) ++ count = SUNMD5_MAX_ROUNDS - 65536; + +- /* extract two data->digest bits */ +- data->bit_a = md5bit (data->digest, data->indirect_a); +- data->bit_b = md5bit (data->digest, data->indirect_b); ++ count += ((unsigned int)rbytes[0]) << 8; ++ count += ((unsigned int)rbytes[1]) << 0; + +- /* xor a coin-toss; if true, mix-in the constant phrase */ ++ assert (count != 0); + +- if (data->bit_a ^ data->bit_b) +- md5_process_bytes ((const unsigned char *) constant_phrase, +- sizeof (constant_phrase), +- &(data->context)); ++ size_t written = (size_t) snprintf ((char *)output, o_size, ++ "%s,rounds=%lu$", SUNMD5_PREFIX, count); + +- /* digest a decimal sprintf of the current roundcount */ +- snprintf (data->roundascii, ROUND_BUFFER_LEN, "%d", round); +- md5_process_bytes ((unsigned char *) data->roundascii, +- strlen (data->roundascii), +- &(data->context)); + +- /* compute/flush the digest, and loop */ +- md5_finish_ctx (&(data->context), &(data->digest)); +- } ++ write_itoa64_4(output + written + 0, rbytes[2], rbytes[3], rbytes[4]); ++ write_itoa64_4(output + written + 4, rbytes[5], rbytes[6], rbytes[7]); + +- (void)snprintf ((char *)output, o_size, "%s$", puresalt); +- +- free (puresalt); +- +- p = (char *)output + strlen ((const char *)output); +- +- l = (uint32_t)((data->digest[ 0]<<16) | (data->digest[ 6]<<8) | data->digest[12]); +- to64 (p, l, 4); +- p += 4; +- l = (uint32_t)((data->digest[ 1]<<16) | (data->digest[ 7]<<8) | data->digest[13]); +- to64 (p, l, 4); +- p += 4; +- l = (uint32_t)((data->digest[ 2]<<16) | (data->digest[ 8]<<8) | data->digest[14]); +- to64 (p, l, 4); +- p += 4; +- l = (uint32_t)((data->digest[ 3]<<16) | (data->digest[ 9]<<8) | data->digest[15]); +- to64 (p, l, 4); +- p += 4; +- l = (uint32_t)((data->digest[ 4]<<16) | (data->digest[10]<<8) | data->digest[ 5]); +- to64 (p, l, 4); +- p += 4; +- l = (uint32_t)data->digest[11]; +- to64 (p, l, 2); +- p += 2; +- *p = '\0'; ++ output[written + 8] = '$'; ++ output[written + 9] = '\0'; + } + + #endif +diff --git a/test-gensalt.c b/test-gensalt.c +index c08627e..f8d95c3 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -45,7 +45,13 @@ static const char *const nthash_expected_output[] = + }; + #endif + #if INCLUDE_sunmd5 +-#define sunmd5_expected_output 0 /* output is not deterministic */ ++static const char *const sunmd5_expected_output[] = ++{ ++ "$md5,rounds=55349$BPm.fm03$", ++ "$md5,rounds=72501$WKoucttX$", ++ "$md5,rounds=42259$3HtkHq/x$", ++ "$md5,rounds=73773$p.5e9AQf$", ++}; + #endif + #if INCLUDE_sha1 + #define pbkdf_expected_output 0 /* output is not deterministic */ + +From 4067bee9f5b24d5323af232ef25f3b6dc4950f5a Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 10 Jul 2018 20:32:11 -0400 +Subject: [PATCH 24/38] Make crypt_gensalt for $sha1 deterministic. + +All of the randomness is now drawn from the 'rbytes' argument, rather +than taking some of it from direct calls to get_random_bytes. This +simplifies the logic and enables us to test the output more +thoroughly. + +Relatedly, the amount of randomness crypt_gensalt will supply to $sha1 +and $3 when it calls get_random_bytes itself is no longer oversized. +--- + crypt-pbkdf1-sha1.c | 90 ++++++++++++++++++++++++++--------------------------- + hashes.lst | 9 +++--- + test-gensalt.c | 13 +++++--- + 3 files changed, 59 insertions(+), 53 deletions(-) + +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index 6bacc21..ac201f0 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -66,34 +66,6 @@ to64 (uint8_t *s, unsigned long v, int n) + } + } + +-/* +- * This may be called from crypt_sha1 or gensalt. +- * +- * The value returned will be slightly less than which defaults +- * to 24680. The goals are that the number of iterations should take +- * non-zero amount of time on a fast cpu while not taking insanely +- * long on a slow cpu. The current default will take about 5 seconds +- * on a 100MHz sparc, and about 0.04 seconds on a 3GHz i386. +- * The number is varied to frustrate those attempting to generate a +- * dictionary of pre-computed hashes. +- */ +-static unsigned long +-crypt_sha1_iterations (unsigned long hint) +-{ +- unsigned long random; +- +- /* +- * We treat CRYPT_SHA1_ITERATIONS as a hint. +- * Make it harder for someone to pre-compute hashes for a +- * dictionary attack by not using the same iteration count for +- * every entry. +- */ +- get_random_bytes (&random, sizeof (unsigned long)); +- if (hint == 0) +- hint = CRYPT_SHA1_ITERATIONS; +- return hint - (random % (hint / 4)); +-} +- + /* + * UNIX password using hmac_sha1 + * This is PBKDF1 from RFC 2898, but using hmac_sha1. +@@ -107,7 +79,7 @@ crypt_sha1_iterations (unsigned long hint) + * have been applied to . The number + * should vary slightly for each password to make + * it harder to generate a dictionary of +- * pre-computed hashes. See crypt_sha1_iterations. ++ * pre-computed hashes. See gensalt_sha1_rn. + * up to 64 bytes of random data, 8 bytes is + * currently considered more than enough. + * the hashed password. +@@ -234,34 +206,62 @@ gensalt_sha1_rn (unsigned long count, + const uint8_t *rbytes, size_t nrbytes, + uint8_t *output, size_t o_size) + { +- /* The salt can be up to 64 bytes, but 32 +- is considered enough for now. */ +- const uint8_t saltlen = 16; ++ static_assert (sizeof (uint32_t) == 4, ++ "space calculations below assume 8-bit bytes"); + +- const size_t enclen = sizeof (unsigned long)*4/3; ++ /* Make sure we have enough random bytes to use for the salt. ++ The format supports using up to 48 random bytes, but 12 is ++ enough. We require another 4 bytes of randomness to perturb ++ 'count' with. */ ++ if (nrbytes < 12 + 4) ++ { ++ errno = ERANGE; ++ return; ++ } + +- if ((o_size < (size_t)(6 + CRYPT_SHA1_SALT_LENGTH + 2)) || +- ((nrbytes*4/3) < saltlen)) ++ /* Make sure we have enough output space, given the amount of ++ randomness available. $sha1$<10digits>$<(nrbytes-4)*4/3>$ */ ++ if (o_size < (nrbytes - 4) * 4 / 3 + sizeof "$sha1$$$" + 10) + { + errno = ERANGE; + return; + } + +- unsigned long c, encbuf; ++ /* ++ * We treat 'count' as a hint. ++ * Make it harder for someone to pre-compute hashes for a ++ * dictionary attack by not using the same iteration count for ++ * every entry. ++ */ ++ uint32_t rounds, random; ++ memcpy (&random, rbytes, 4); ++ if (count == 0) ++ count = CRYPT_SHA1_ITERATIONS; ++ if (count > UINT32_MAX) ++ count = UINT32_MAX; ++ rounds = (uint32_t) (count - (random % (count / 4))); ++ ++ uint32_t encbuf; ++ int n = snprintf((char *)output, o_size, "$sha1$%u$", (unsigned int)rounds); ++ assert (n >= 1 && (size_t)n + 2 < o_size); + +- unsigned int n = (unsigned int) snprintf((char *)output, o_size, "$sha1$%u$", +- (unsigned int)crypt_sha1_iterations(count)); ++ const uint8_t *r = rbytes + 4; ++ const uint8_t *rlim = rbytes + nrbytes; ++ uint8_t *o = output + n; ++ uint8_t *olim = output + n + CRYPT_SHA1_SALT_LENGTH; ++ if (olim + 2 > output + o_size) ++ olim = output + o_size - 2; + +- for (c = 0; (c * sizeof (unsigned long)) + sizeof (unsigned long) <= nrbytes && +- (c * enclen) + enclen <= CRYPT_SHA1_SALT_LENGTH; ++c) ++ for (; r + 3 < rlim && o + 4 < olim; r += 3, o += 4) + { +- memcpy (&encbuf, rbytes + (c * sizeof (unsigned long)), +- sizeof (unsigned long)); +- to64 (output + n + (c * enclen), encbuf, (int)enclen); ++ encbuf = ((((uint32_t)r[0]) << 16) | ++ (((uint32_t)r[1]) << 8) | ++ (((uint32_t)r[2]) << 0)); ++ to64 (o, encbuf, 4); + } + +- output[n + (c * enclen)] = '$'; +- output[n + (c * enclen) + 1] = '\0'; ++ o[0] = '$'; ++ o[1] = '\0'; + } + + #endif +diff --git a/hashes.lst b/hashes.lst +index 488768f..4ec79cc 100644 +--- a/hashes.lst ++++ b/hashes.lst +@@ -5,8 +5,9 @@ + # name used for the 'crypt_fn' and 'gensalt_fn' entry points to the + # relevant algorithm module; an optional suffix on the name of the + # 'gensalt_fn'; the prefix used to identify the algorithm in hash +-# strings; the number of bytes of random data required to generate a +-# salt; and a set of flags. Currently there are three flags: DEFAULT ++# strings; the number of bytes of random data that crypt_gensalt ++# should draw from the OS when its caller doesn't supply any; ++# and a set of flags. Currently there are three flags: DEFAULT + # means this is the hash to use when no prefix was supplied to + # crypt_gensalt, STRONG means the hash is still considered strong + # enough to use for newly hashed passwords, and GLIBC means the hash +@@ -33,8 +34,8 @@ sha512 : $6$ 15 STRONG,GLIBC + sha256 : $5$ 15 STRONG,GLIBC + md5 : $1$ 9 GLIBC + sunmd5 : $md5 8 : +-sha1 : $sha1 48 : +-nthash : $3$ 16 : ++sha1 : $sha1 20 : ++nthash : $3$ 7 : + des_xbsd : _ 3 : + des_big : : 2 : + des : : 2 GLIBC +diff --git a/test-gensalt.c b/test-gensalt.c +index f8d95c3..98923e5 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -54,7 +54,13 @@ static const char *const sunmd5_expected_output[] = + }; + #endif + #if INCLUDE_sha1 +-#define pbkdf_expected_output 0 /* output is not deterministic */ ++static const char *const pbkdf_expected_output[] = ++{ ++ "$sha1$248488$ggu.H673kaZ5$", ++ "$sha1$248421$SWqudaxXA5L0$", ++ "$sha1$257243$RAtkIrDxEovH$", ++ "$sha1$250464$1j.eVxRfNAPO$", ++}; + #endif + #if INCLUDE_sha256 + static const char *const sha256_expected_output[] = +@@ -131,7 +137,7 @@ static const struct testcase testcases[] = + { "$md5", sunmd5_expected_output, 27, 0 }, // SUNMD5 + #endif + #if INCLUDE_sha1 +- { "$sha1", pbkdf_expected_output, 34, 74 }, // PBKDF with SHA1 ++ { "$sha1", pbkdf_expected_output, 26, 34 }, // PBKDF with SHA1 + #endif + #if INCLUDE_sha256 + { "$5$", sha256_expected_output, 19, 0 }, // SHA-2-256 +@@ -203,8 +209,7 @@ main (void) + tcase->prefix, ent, salt); + status = 1; + } +- else if (entropy[ent] && tcase->expected_output && +- strcmp (salt, tcase->expected_output[ent])) ++ else if (entropy[ent] && strcmp (salt, tcase->expected_output[ent])) + { + fprintf (stderr, "ERROR: %s/%u -> %s (expected %s)\n", + tcase->prefix, ent, salt, tcase->expected_output[ent]); + +From 9bed27f2bd0495361e892a0740bcdf237f560b98 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 10 Jul 2018 21:36:11 -0400 +Subject: [PATCH 25/38] Don't use malloc in crypt-pbkdf1-sha1.c. + +There's no need to copy the salt when we can just use %.*s in two +places. + +Making this change revealed that -Wformat-truncation=2 is too +aggressive; we are actually taking appropriate precautions against +truncated strings in this case, but it warns anyway. Back down to +-Wformat-truncation=1, which warns only when the return value of +snprintf is ignored. +--- + crypt-pbkdf1-sha1.c | 20 ++++++-------------- + m4/zw_simple_warnings.m4 | 2 +- + 2 files changed, 7 insertions(+), 15 deletions(-) + +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index ac201f0..cbf390e 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -109,7 +109,6 @@ crypt_sha1_rn (const char *phrase, const char *setting, + unsigned long ul; + size_t sl; + size_t pl; +- char *salt; + int dl; + unsigned long iterations; + unsigned long i; +@@ -148,32 +147,27 @@ crypt_sha1_rn (const char *phrase, const char *setting, + return; + } + +- /* Get the length of the actual salt */ + sl = (size_t)(sp - setting); +- +- salt = malloc (sl + 1); +- strncpy (salt, setting, sl); +- salt[sl] = '\0'; +- + pl = strlen (phrase); + + /* + * Now get to work... + * Prime the pump with + */ +- dl = snprintf ((char *)output, o_size, "%s%s%lu", +- salt, magic, iterations); ++ dl = snprintf ((char *)output, o_size, "%.*s%s%lu", ++ (int)sl, setting, magic, iterations); + /* + * Then hmac using as key, and repeat... + */ +- hmac_sha1_process_data ((const unsigned char *)output, (size_t)dl, pwu, pl, hmac_buf); ++ hmac_sha1_process_data ((const unsigned char *)output, (size_t)dl, ++ pwu, pl, hmac_buf); + for (i = 1; i < iterations; ++i) + { + hmac_sha1_process_data (hmac_buf, SHA1_SIZE, pwu, pl, hmac_buf); + } + /* Now output... */ +- pl = (size_t)snprintf ((char *)output, o_size, "%s%lu$%s$", +- magic, iterations, salt); ++ pl = (size_t)snprintf ((char *)output, o_size, "%s%lu$%.*s$", ++ magic, iterations, (int)sl, setting); + ep = output + pl; + + /* Every 3 bytes of hash gives 24 bits which is 4 base64 chars */ +@@ -195,8 +189,6 @@ crypt_sha1_rn (const char *phrase, const char *setting, + + /* Don't leave anything around in vm they could use. */ + XCRYPT_SECURE_MEMSET (scratch, s_size) +- XCRYPT_SECURE_MEMSET (salt, sl) +- free (salt); + } + + /* Modified excerpt from: +diff --git a/m4/zw_simple_warnings.m4 b/m4/zw_simple_warnings.m4 +index eeb57d5..75ca300 100644 +--- a/m4/zw_simple_warnings.m4 ++++ b/m4/zw_simple_warnings.m4 +@@ -112,7 +112,7 @@ AC_ARG_ENABLE( + -Wformat=2 dnl + -Wformat-overflow=2 dnl + -Wformat-signedness dnl +- -Wformat-truncation=2 dnl ++ -Wformat-truncation=1 dnl + -Winline dnl + -Wlogical-op dnl + -Wmissing-declarations dnl + +From c20f9f161c0aa362e0ed8bc8ee387badd8acbc38 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 10 Jul 2018 21:44:02 -0400 +Subject: [PATCH 26/38] Fix incorrect output-size computation in crypt_sha1_rn. + +It was testing for enough space for the raw SHA1 digest, not the +digest after base64 expansion. + +(This is not presently detectable by the test suite because the higher +layers always supply crypt__rn functions with CRYPT_OUTPUT_SIZE +bytes of space, which is far more than any of them need.) +--- + crypt-pbkdf1-sha1.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index cbf390e..c96b72d 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -51,7 +51,8 @@ + # define CRYPT_SHA1_SALT_LENGTH 64 + #endif + +-#define SHA1_SIZE 20 ++#define SHA1_SIZE 20 /* size of raw SHA1 digest, 160 bits */ ++#define SHA1_OUTPUT_SIZE 28 /* size of base64-ed output string */ + + static const uint8_t itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +@@ -97,7 +98,8 @@ crypt_sha1_rn (const char *phrase, const char *setting, + { + static const char *magic = "$sha1$"; + +- if ((o_size < (strlen (magic) + 2 + 10 + CRYPT_SHA1_SALT_LENGTH + SHA1_SIZE)) || ++ if ((o_size < (strlen (magic) + 2 + 10 + CRYPT_SHA1_SALT_LENGTH + ++ SHA1_OUTPUT_SIZE)) || + s_size < SHA1_SIZE) + { + errno = ERANGE; + +From 8639108dea0b847282e1de2bae6c7aef8f778b99 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 10 Jul 2018 21:49:14 -0400 +Subject: [PATCH 27/38] Make XCRYPT_SECURE_MEMSET() syntactically a normal + expression. + +All of the alternative definitions of XCRYPT_SECURE_MEMSET expanded to +a full statement including the terminating semicolon, and none of its +uses had a terminating semicolon, which looked like a typo. Correct +this: put semicolons on each use, and remove them from the +definitions. This is entirely cosmetic, but it's been bugging me. + +(There is no risk of unexpected parser behavior after macro expansion: +after this change, XCRYPT_SECURE_MEMSET(...) looks like a function +call expression, and all of its possible expansions are, in fact, +function call expressions.) +--- + alg-md4.c | 6 +++--- + alg-md5.c | 4 ++-- + alg-sha1.c | 4 ++-- + alg-sha256.c | 4 ++-- + alg-sha512.c | 4 ++-- + crypt-des-obsolete.c | 2 +- + crypt-des.c | 4 ++-- + crypt-nthash.c | 2 +- + crypt-pbkdf1-sha1.c | 2 +- + crypt-port.h | 8 ++++---- + crypt.c | 2 +- + randombytes.c | 2 +- + 12 files changed, 22 insertions(+), 22 deletions(-) + +diff --git a/alg-md4.c b/alg-md4.c +index ce62490..c1c4075 100644 +--- a/alg-md4.c ++++ b/alg-md4.c +@@ -163,7 +163,7 @@ md4_read_ctx (struct md4_ctx *ctx, void *resbuf) + cpu_to_le32 (buf + 4, ctx->b); + cpu_to_le32 (buf + 8, ctx->c); + cpu_to_le32 (buf + 12, ctx->d); +- XCRYPT_SECURE_MEMSET (ctx, sizeof(struct md4_ctx)) ++ XCRYPT_SECURE_MEMSET (ctx, sizeof(struct md4_ctx)); + return resbuf; + } + +@@ -230,13 +230,13 @@ md4_finish_ctx (struct md4_ctx *ctx, void *resbuf) + + if (free < 8) + { +- XCRYPT_SECURE_MEMSET (&ctx->buffer[used], free) ++ XCRYPT_SECURE_MEMSET (&ctx->buffer[used], free); + body(ctx, ctx->buffer, 64); + used = 0; + free = 64; + } + +- XCRYPT_SECURE_MEMSET (&ctx->buffer[used], free - 8) ++ XCRYPT_SECURE_MEMSET (&ctx->buffer[used], free - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = (unsigned char)((ctx->lo) & 0xff); +diff --git a/alg-md5.c b/alg-md5.c +index df49fc6..9d9e4e3 100644 +--- a/alg-md5.c ++++ b/alg-md5.c +@@ -52,7 +52,7 @@ md5_read_ctx (struct md5_ctx *ctx, void *resbuf) + cpu_to_le32 (buf + 4, ctx->B); + cpu_to_le32 (buf + 8, ctx->C); + cpu_to_le32 (buf + 12, ctx->D); +- XCRYPT_SECURE_MEMSET (ctx, sizeof(*ctx)) ++ XCRYPT_SECURE_MEMSET (ctx, sizeof(*ctx)); + return resbuf; + } + +@@ -74,7 +74,7 @@ md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) + /* The first byte of padding should be 0x80 and the rest should be + zero. (RFC 1321, 3.1: Step 1) */ + ctx->buffer[bytes] = 0x80u; +- XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1) ++ XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1); + + /* Put the 64-bit file length in little-endian *bits* at the end of + the buffer. */ +diff --git a/alg-sha1.c b/alg-sha1.c +index 421ffbd..a00b06b 100644 +--- a/alg-sha1.c ++++ b/alg-sha1.c +@@ -274,8 +274,8 @@ sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) + + /* Wipe variables */ + i = 0; +- XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha1_ctx)) +- XCRYPT_SECURE_MEMSET (finalcount, 8) /* SWR */ ++ XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha1_ctx)); ++ XCRYPT_SECURE_MEMSET (finalcount, 8); /* SWR */ + + return resbuf; + } +diff --git a/alg-sha256.c b/alg-sha256.c +index 713385d..db4a2fd 100644 +--- a/alg-sha256.c ++++ b/alg-sha256.c +@@ -183,7 +183,7 @@ sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) + /* The first byte of padding should be 0x80 and the rest should be + zero. (FIPS 180-2:5.1.1) */ + ctx->buffer[bytes] = 0x80u; +- XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1) ++ XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1); + + /* Put the 64-bit file length in big-endian *bits* at the end of the + buffer. */ +@@ -196,7 +196,7 @@ sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) + for (i = 0; i < 8; i++) + cpu_to_be32 (rp + i*4, ctx->H[i]); + +- XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha256_ctx)) ++ XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha256_ctx)); + return resbuf; + } + +diff --git a/alg-sha512.c b/alg-sha512.c +index 6a6aab2..60c1877 100644 +--- a/alg-sha512.c ++++ b/alg-sha512.c +@@ -213,7 +213,7 @@ sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) + /* The first byte of padding should be 0x80 and the rest should be + zero. (FIPS 180-2:5.1.2) */ + ctx->buffer[bytes] = 0x80u; +- XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1) ++ XCRYPT_SECURE_MEMSET (&ctx->buffer[bytes+1], pad-1); + + /* Put the 128-bit file length in big-endian *bits* at the end of + the buffer. */ +@@ -229,7 +229,7 @@ sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) + for (i = 0; i < 8; ++i) + cpu_to_be64 (rp + i*8, ctx->H[i]); + +- XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha512_ctx)) ++ XCRYPT_SECURE_MEMSET (ctx, sizeof (struct sha512_ctx)); + return resbuf; + } + +diff --git a/crypt-des-obsolete.c b/crypt-des-obsolete.c +index afe279b..52853e3 100644 +--- a/crypt-des-obsolete.c ++++ b/crypt-des-obsolete.c +@@ -106,7 +106,7 @@ pack_bits (unsigned char bitv[8], const char bytev[64]) + static void + do_setkey_r (const char *key, struct des_ctx *ctx) + { +- XCRYPT_SECURE_MEMSET (ctx, sizeof (struct des_ctx)) ++ XCRYPT_SECURE_MEMSET (ctx, sizeof (struct des_ctx)); + des_set_salt (ctx, 0); + + unsigned char bkey[8]; +diff --git a/crypt-des.c b/crypt-des.c +index b197dcd..733c4d3 100644 +--- a/crypt-des.c ++++ b/crypt-des.c +@@ -107,7 +107,7 @@ des_gen_hash (struct des_ctx *ctx, uint32_t count, uint8_t *output, + uint8_t cbuf[8]) + { + uint8_t plaintext[8]; +- XCRYPT_SECURE_MEMSET (plaintext, 8) ++ XCRYPT_SECURE_MEMSET (plaintext, 8); + des_crypt_block (ctx, cbuf, plaintext, count, false); + + /* Now encode the result. */ +@@ -369,7 +369,7 @@ crypt_des_xbsd_rn (const char *phrase, const char *setting, + set as the DES key, and encrypted to produce the round output. + The salt is zero throughout this procedure. */ + des_set_salt (ctx, 0); +- XCRYPT_SECURE_MEMSET (pkbuf, 8) ++ XCRYPT_SECURE_MEMSET (pkbuf, 8); + for (;;) + { + for (i = 0; i < 8; i++) +diff --git a/crypt-nthash.c b/crypt-nthash.c +index f9fee7b..890f57f 100644 +--- a/crypt-nthash.c ++++ b/crypt-nthash.c +@@ -78,7 +78,7 @@ crypt_nthash_rn (const char *phrase, + return; + } + +- XCRYPT_SECURE_MEMSET (unipw, sizeof unipw) ++ XCRYPT_SECURE_MEMSET (unipw, sizeof unipw); + /* convert to unicode (thanx Archie) */ + unipwLen = 0; + for (s = phrase; unipwLen < sizeof(unipw) / 2 && *s; s++) +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index c96b72d..f15b55d 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -190,7 +190,7 @@ crypt_sha1_rn (const char *phrase, const char *setting, + *ep = '\0'; + + /* Don't leave anything around in vm they could use. */ +- XCRYPT_SECURE_MEMSET (scratch, s_size) ++ XCRYPT_SECURE_MEMSET (scratch, s_size); + } + + /* Modified excerpt from: +diff --git a/crypt-port.h b/crypt-port.h +index 6d94b09..80fa489 100644 +--- a/crypt-port.h ++++ b/crypt-port.h +@@ -95,15 +95,15 @@ typedef union + #if defined HAVE_MEMSET_S + /* Will never be optimized out. */ + #define XCRYPT_SECURE_MEMSET(s, len) \ +- memset_s (s, len, 0x00, len); ++ memset_s (s, len, 0x00, len) + #elif defined HAVE_EXPLICIT_BZERO + /* explicit_bzero() should give us enough guarantees. */ + #define XCRYPT_SECURE_MEMSET(s, len) \ +- explicit_bzero(s, len); ++ explicit_bzero(s, len) + #elif defined HAVE_EXPLICIT_MEMSET + /* Same guarantee goes for explicit_memset(). */ + #define XCRYPT_SECURE_MEMSET(s, len) \ +- explicit_memset (s, 0x00, len); ++ explicit_memset (s, 0x00, len) + #else + /* The best hope we have in this case. */ + static inline +@@ -114,7 +114,7 @@ void _xcrypt_secure_memset (void *s, size_t len) + *c++ = 0x00; + } + #define XCRYPT_SECURE_MEMSET(s, len) \ +- _xcrypt_secure_memset (s, len); ++ _xcrypt_secure_memset (s, len) + #endif + + /* Per-symbol version tagging. Currently we only know how to do this +diff --git a/crypt.c b/crypt.c +index 387b69a..405d9a3 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -259,7 +259,7 @@ do_crypt (const char *phrase, const char *setting, struct crypt_data *data) + #endif + } + +- XCRYPT_SECURE_MEMSET (data->internal, sizeof data->internal) ++ XCRYPT_SECURE_MEMSET (data->internal, sizeof data->internal); + } + + #if INCLUDE_crypt_rn +diff --git a/randombytes.c b/randombytes.c +index 5647250..5053525 100644 +--- a/randombytes.c ++++ b/randombytes.c +@@ -68,7 +68,7 @@ get_random_bytes(void *buf, size_t buflen) + } + /* To eliminate the possibility of one of the primitives below failing + with EFAULT, force a crash now if the buffer is unwritable. */ +- XCRYPT_SECURE_MEMSET (buf, buflen) ++ XCRYPT_SECURE_MEMSET (buf, buflen); + + #ifdef HAVE_ARC4RANDOM_BUF + /* arc4random_buf, if it exists, can never fail. */ + +From 15d1e3bf3d259ea262f3d34e8c225a3abfabaa09 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Wed, 11 Jul 2018 17:15:46 -0400 +Subject: [PATCH 28/38] Add more tests based on gaps in line coverage. + +We were not adequately testing invalid-argument error paths within +crypt_gensalt, and we were also not adequately testing a variety of +corner cases related to non-default round parameters + +After this change, I believe that all of the non-covered lines fall +into three categories: genuinely impossible to hit from the public +API (usually these are double-checks for preconditions already +verified at a higher level); checks for memory allocation failure; and +fallback paths within get_random_bytes. The first two of these, IMHO, +are fine to leave as is. It would probably be worth writing a test +that exercises the get_random_bytes fallbacks but it'd involve getting +one's hands dirty with ELF. I may do it eventually if no one else does. + +This change makes us pickier about non-default round parameters to $5$ +and $6$ hashes; numbers outside the valid range are now rejected, as +are numbers with leading zeroes and an explicit request for the +default number of rounds. This is in keeping with the observation, in +the Passlib documentation, that allowing more than one valid crypt +output string for any given (rounds, salt, phrase) triple is asking +for trouble. + +This partially reverts commit +a7f9df50cecec46bb8176382faa685ce35ca72be, which accidentally caused us +to fail to reject invalid DES setting strings. Because of this, a few +lines in crypt-des.c cease to be covered; they are in category +1 (double-checks of preconditions). +--- + Makefile.am | 4 +- + crypt-pbkdf1-sha1.c | 2 +- + crypt-sha256.c | 26 ++++-- + crypt-sha512.c | 26 ++++-- + crypt-sunmd5.c | 4 +- + crypt.c | 13 ++- + test-badsalt.c | 40 +++++++-- + test-badsetting.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + test-crypt-sha256.c | 10 --- + test-crypt-sha512.c | 10 --- + test-gensalt.c | 82 ++++++++++++++---- + 11 files changed, 391 insertions(+), 62 deletions(-) + create mode 100644 test-badsetting.c + +diff --git a/Makefile.am b/Makefile.am +index fec069e..51cba76 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -126,7 +126,8 @@ check_PROGRAMS = \ + test-crypt-md5 test-crypt-nthash \ + test-crypt-pbkdf1-sha1 test-crypt-sha256 test-crypt-sha512 \ + test-crypt-sunmd5 \ +- test-byteorder test-badsalt test-gensalt test-short-outbuf ++ test-byteorder test-badsalt test-badsetting test-gensalt \ ++ test-short-outbuf + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +@@ -166,6 +167,7 @@ test_crypt_sha256_LDADD = libcrypt.la + test_crypt_sha512_LDADD = libcrypt.la + test_crypt_sunmd5_LDADD = libcrypt.la + test_badsalt_LDADD = libcrypt.la ++test_badsetting_LDADD = libcrypt.la + test_gensalt_LDADD = libcrypt.la + test_des_obsolete_LDADD = libcrypt.la + test_des_obsolete_r_LDADD = libcrypt.la +diff --git a/crypt-pbkdf1-sha1.c b/crypt-pbkdf1-sha1.c +index f15b55d..cf22f67 100644 +--- a/crypt-pbkdf1-sha1.c ++++ b/crypt-pbkdf1-sha1.c +@@ -209,7 +209,7 @@ gensalt_sha1_rn (unsigned long count, + 'count' with. */ + if (nrbytes < 12 + 4) + { +- errno = ERANGE; ++ errno = EINVAL; + return; + } + +diff --git a/crypt-sha256.c b/crypt-sha256.c +index b8640b8..22c6423 100644 +--- a/crypt-sha256.c ++++ b/crypt-sha256.c +@@ -111,7 +111,6 @@ crypt_sha256_rn (const char *phrase, const char *setting, + size_t cnt; + /* Default number of rounds. */ + size_t rounds = ROUNDS_DEFAULT; +- bool rounds_custom = false; + + /* Find beginning of salt string. The prefix should normally always + be present. Just in case it is not. */ +@@ -123,14 +122,27 @@ crypt_sha256_rn (const char *phrase, const char *setting, + == 0) + { + const char *num = salt + sizeof (sha256_rounds_prefix) - 1; ++ /* Do not allow an explicit setting of zero rounds, nor of the ++ default number of rounds, nor leading zeroes on the rounds. */ ++ if (!(*num >= '1' && *num <= '9')) ++ { ++ errno = EINVAL; ++ return; ++ } ++ ++ errno = 0; + char *endp; +- unsigned long int srounds = strtoul (num, &endp, 10); +- if (*endp == '$') ++ rounds = strtoul (num, &endp, 10); ++ if (endp == num || *endp != '$' ++ || rounds < ROUNDS_MIN ++ || rounds > ROUNDS_MAX ++ || rounds == ROUNDS_DEFAULT ++ || errno) + { +- salt = endp + 1; +- rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX)); +- rounds_custom = true; ++ errno = EINVAL; ++ return; + } ++ salt = endp + 1; + } + + salt_len = strspn (salt, b64t); +@@ -243,7 +255,7 @@ crypt_sha256_rn (const char *phrase, const char *setting, + memcpy (cp, sha256_salt_prefix, sizeof (sha256_salt_prefix) - 1); + cp += sizeof (sha256_salt_prefix) - 1; + +- if (rounds_custom) ++ if (rounds != ROUNDS_DEFAULT) + { + int n = snprintf (cp, + SHA256_HASH_LENGTH - (sizeof (sha256_salt_prefix) - 1), +diff --git a/crypt-sha512.c b/crypt-sha512.c +index 1a651e0..7df4805 100644 +--- a/crypt-sha512.c ++++ b/crypt-sha512.c +@@ -111,7 +111,6 @@ crypt_sha512_rn (const char *phrase, const char *setting, + size_t cnt; + /* Default number of rounds. */ + size_t rounds = ROUNDS_DEFAULT; +- bool rounds_custom = false; + + /* Find beginning of salt string. The prefix should normally always + be present. Just in case it is not. */ +@@ -123,14 +122,27 @@ crypt_sha512_rn (const char *phrase, const char *setting, + == 0) + { + const char *num = salt + sizeof (sha512_rounds_prefix) - 1; ++ /* Do not allow an explicit setting of zero rounds, nor of the ++ default number of rounds, nor leading zeroes on the rounds. */ ++ if (!(*num >= '1' && *num <= '9')) ++ { ++ errno = EINVAL; ++ return; ++ } ++ ++ errno = 0; + char *endp; +- unsigned long int srounds = strtoul (num, &endp, 10); +- if (*endp == '$') ++ rounds = strtoul (num, &endp, 10); ++ if (endp == num || *endp != '$' ++ || rounds < ROUNDS_MIN ++ || rounds > ROUNDS_MAX ++ || rounds == ROUNDS_DEFAULT ++ || errno) + { +- salt = endp + 1; +- rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX)); +- rounds_custom = true; ++ errno = EINVAL; ++ return; + } ++ salt = endp + 1; + } + + salt_len = strspn (salt, b64t); +@@ -246,7 +258,7 @@ crypt_sha512_rn (const char *phrase, const char *setting, + memcpy (cp, sha512_salt_prefix, sizeof (sha512_salt_prefix) - 1); + cp += sizeof (sha512_salt_prefix) - 1; + +- if (rounds_custom) ++ if (rounds != ROUNDS_DEFAULT) + { + int n = snprintf (cp, + SHA512_HASH_LENGTH - (sizeof (sha512_salt_prefix) - 1), +diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c +index 9107052..c294797 100644 +--- a/crypt-sunmd5.c ++++ b/crypt-sunmd5.c +@@ -282,12 +282,12 @@ gensalt_sunmd5_rn (unsigned long count, + uint8_t *output, + size_t o_size) + { +- if (o_size < SUNMD5_MAX_SETTING_LEN + 1 || nrbytes < 6 + 2) ++ if (o_size < SUNMD5_MAX_SETTING_LEN + 1) + { + errno = ERANGE; + return; + } +- if (count > SUNMD5_MAX_ROUNDS) ++ if (count > SUNMD5_MAX_ROUNDS || nrbytes < 6 + 2) + { + errno = EINVAL; + return; +diff --git a/crypt.c b/crypt.c +index 405d9a3..753c649 100644 +--- a/crypt.c ++++ b/crypt.c +@@ -83,6 +83,17 @@ static const struct hashfn hash_algorithms[] = + HASH_ALGORITHM_TABLE_ENTRIES + }; + ++#if INCLUDE_des || INCLUDE_des_big ++static int ++is_des_salt_char (char c) ++{ ++ return ((c >= 'a' && c <= 'z') || ++ (c >= 'A' && c <= 'Z') || ++ (c >= '0' && c <= '9') || ++ c == '.' || c == '/'); ++} ++#endif ++ + static const struct hashfn * + get_hashfn (const char *setting) + { +@@ -98,7 +109,7 @@ get_hashfn (const char *setting) + else + { + if (setting[0] == '\0' || +- (setting[0] != '$' && setting[0] != '*')) ++ (is_des_salt_char (setting[0]) && is_des_salt_char (setting[1]))) + return h; + } + #endif +diff --git a/test-badsalt.c b/test-badsalt.c +index 6d57b14..b274337 100644 +--- a/test-badsalt.c ++++ b/test-badsalt.c +@@ -124,7 +124,13 @@ static const struct testcase testcases[] = + { "*MD5 (Sun, plain) invalid char", 14, "$md5$:xMeE.at$" }, + { "MD5 (Sun, rounds)", 25, "$md5,rounds=123$1xMeE.at$" }, + { "*MD5 (Sun, rounds) invalid char", 25, "$md5,rounds=123$:xMeE.at$" }, +- { "*MD5 (Sun, rounds) invalid rounds", 25, "$md5,rounds=:23$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 1", 25, "$md5,rounds=:23$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 2", 25, "$md5,rounds=12:$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 3", 25, "$md5,rounds:123$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 4", 22, "$md5,rounds=$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 5", 23, "$md5,rounds=0$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 6", 25, "$md5,rounds=012$1xMeE.at$" }, ++ { "*MD5 (Sun, rounds) invalid rounds 7", 32, "$md5,rounds=4294967295$1xMeE.at$" }, + #endif + #if INCLUDE_nthash + { "NTHASH (bare)", 3, "$3$" }, +@@ -133,33 +139,51 @@ static const struct testcase testcases[] = + #if INCLUDE_sha1 + { "HMAC-SHA1", 27, "$sha1$123$GGXpNqoJvglVTkGU$" }, + { "*HMAC-SHA1 invalid char", 27, "$sha1$123$:GXpNqoJvglVTkGU$" }, +- { "*HMAC-SHA1 invalid rounds", 27, "$sha1$:23$GGXpNqoJvglVTkGU$" }, ++ { "*HMAC-SHA1 invalid rounds 1", 27, "$sha1$:23$GGXpNqoJvglVTkGU$" }, ++ { "*HMAC-SHA1 invalid rounds 2", 27, "$sha1$12:$GGXpNqoJvglVTkGU$" }, ++ { "*HMAC-SHA1 invalid rounds 3", 27, "$sha1$12:$GGXpNqoJvglVTkGU$" }, + #endif + #if INCLUDE_sha256 + { "SHA-256 (plain)", 20, "$5$MJHnaAkegEVYHsFK$" }, + { "*SHA-256 (plain) invalid char", 20, "$5$:JHnaAkegEVYHsFK$" }, + { "SHA-256 (rounds)", 32, "$5$rounds=1000$MJHnaAkegEVYHsFK$" }, +- { "*SHA-256 (rounds) invalid rounds", 32, "$5$rounds=:000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 1", 32, "$5$rounds=:000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 2", 32, "$5$rounds=100:$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 3", 32, "$5$rounds:1000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 4", 28, "$5$rounds=$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 5", 29, "$5$rounds=0$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 6", 32, "$5$rounds=0100$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-256 (rounds) invalid rounds 7", 38, "$5$rounds=4294967295$MJHnaAkegEVYHsFK$" }, + #endif + #if INCLUDE_sha512 + { "SHA-512 (plain)", 20, "$6$MJHnaAkegEVYHsFK$" }, + { "*SHA-512 (plain) invalid char", 20, "$6$:JHnaAkegEVYHsFK$" }, + { "SHA-512 (rounds)", 32, "$6$rounds=1000$MJHnaAkegEVYHsFK$" }, +- { "*SHA-512 (rounds) invalid rounds", 32, "$6$rounds=:000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 1", 32, "$6$rounds=:000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 2", 32, "$6$rounds=100:$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 3", 32, "$6$rounds:1000$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 4", 28, "$6$rounds=$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 5", 29, "$6$rounds=0$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 6", 32, "$6$rounds=0100$MJHnaAkegEVYHsFK$" }, ++ { "*SHA-512 (rounds) invalid rounds 6", 38, "$6$rounds=4294967295$MJHnaAkegEVYHsFK$" }, + #endif + #if INCLUDE_bcrypt + { "bcrypt (a04)", 29, "$2a$04$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "*bcrypt (a04) invalid char", 29, "$2a$04$:BVLHeMpJ/QQCv3XqJx8zO" }, +- { "*bcrypt (a04) invalid rounds", 29, "$2a$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (a04) invalid rounds 1", 29, "$2a$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (a04) invalid rounds 2", 29, "$2a$0:$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (b04)", 29, "$2b$04$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "*bcrypt (b04) invalid char", 29, "$2b$04$:BVLHeMpJ/QQCv3XqJx8zO" }, +- { "*bcrypt (b04) invalid rounds", 29, "$2b$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (b04) invalid rounds 1", 29, "$2b$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (b04) invalid rounds 2", 29, "$2b$0:$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (x04)", 29, "$2x$04$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "*bcrypt (x04) invalid char", 29, "$2x$04$:BVLHeMpJ/QQCv3XqJx8zO" }, +- { "*bcrypt (x04) invalid rounds", 29, "$2x$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (x04) invalid rounds 1", 29, "$2x$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (x04) invalid rounds 2", 29, "$2x$0:$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "bcrypt (y04)", 29, "$2y$04$UBVLHeMpJ/QQCv3XqJx8zO" }, + { "*bcrypt (y04) invalid char", 29, "$2y$04$:BVLHeMpJ/QQCv3XqJx8zO" }, +- { "*bcrypt (y04) invalid rounds", 29, "$2y$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (y04) invalid rounds 1", 29, "$2y$:4$UBVLHeMpJ/QQCv3XqJx8zO" }, ++ { "*bcrypt (y04) invalid rounds 2", 29, "$2y$0:$UBVLHeMpJ/QQCv3XqJx8zO" }, + #endif + }; + +diff --git a/test-badsetting.c b/test-badsetting.c +new file mode 100644 +index 0000000..ae2337b +--- /dev/null ++++ b/test-badsetting.c +@@ -0,0 +1,236 @@ ++/* Test rejection of ill-formed setting strings. ++ ++ Written by Zack Weinberg in 2017. ++ To the extent possible under law, Zack Weinberg has waived all ++ copyright and related or neighboring rights to this work. ++ ++ See https://creativecommons.org/publicdomain/zero/1.0/ for further ++ details. */ ++ ++#include "crypt-port.h" ++#include ++#include ++#include ++#include ++#include ++ ++/* Supply 64 bytes of "random" data to each gensalt call, for ++ determinism. */ ++static const char rbytes[] = ++ "yC8S8E7o+tmofM3L3DgKRwBy+RjWygAXIda7CAghZeXR9ZSl0UZh3kvt2XHg+aKo"; ++ ++struct testcase ++{ ++ const char *prefix; ++ unsigned long count; ++ int rbytes; /* 0 = use sizeof rbytes - 1 */ ++ int osize; /* 0 = use CRYPT_GENSALT_OUTPUT_SIZE */ ++}; ++ ++/* Note: because all of the test strings below are invalid settings, ++ they can all be tested unconditionally -- it doesn't matter whether ++ the specific hash algorithm that they are invalid for is actually ++ configured in. */ ++ ++static const struct testcase testcases[] = { ++ /* DES (traditional and/or bigcrypt) -- count is ignored */ ++ { "!a", 0, 0, 0 }, // invalid first character ++ { "a!", 0, 0, 0 }, // invalid second character ++ { "xx", 1, 0, 0 }, // doesn't accept variable counts ++ { "xx", 0, 1, 0 }, // inadequate rbytes ++ { "xx", 0, 0, 1 }, // inadequate osize ++ ++ ++ /* BSDi extended DES */ ++ { "_", 2, 0, 0 }, // even number ++ { "_", 16777217, 0, 0 }, // too large ++ { "_", 0, 2, 0 }, // inadequate rbytes ++ { "_", 0, 0, 4 }, // inadequate osize ++ ++ ++ /* MD5 (FreeBSD) */ ++ { "$1", 0, 0, 0 }, // truncated prefix ++ { "$1$", 1, 0, 0 }, // doesn't accept variable counts ++ { "$1$", 0, 2, 0 }, // inadequate rbytes ++ { "$1$", 0, 0, 4 }, // inadequate osize ++ ++ /* MD5 (Sun) */ ++ { "$m", 0, 0, 0 }, // truncated prefix ++ { "$md", 0, 0, 0 }, ++ { "$md5", 4294963200, 0, 0 }, // too large ++ { "$md5", 0, 2, 0 }, // inadequate rbytes ++ { "$md5", 0, 0, 4 }, // inadequate osize ++ ++ /* NTHASH */ ++ { "$3", 0, 0, 0 }, // truncated prefix ++ { "$3$", 0, 0, 4 }, // inadequate osize ++ ++ /* SHA1 */ ++ { "$s", 0, 0, 0 }, // truncated prefix ++ { "$sh", 0, 0, 0 }, ++ { "$sha", 0, 0, 0 }, ++ { "$sha1", 0, 2, 0 }, // inadequate rbytes ++ { "$sha1", 0, 0, 4 }, // inadequate osize ++ ++ /* SHA256 */ ++ { "$5", 0, 0, 0 }, // truncated prefix ++ { "$5$", 999, 0, 0 }, // too small ++ { "$5$", 1000000000, 0, 0 }, // too large ++ { "$5$", 0, 2, 0 }, // inadequate rbytes ++ { "$5$", 0, 0, 4 }, // inadequate osize ++ ++ /* SHA512 */ ++ { "$6", 0, 0, 0 }, // truncated prefix ++ { "$6$", 999, 0, 0 }, // too small ++ { "$6$", 1000000000, 0, 0 }, // too large ++ { "$6$", 0, 2, 0 }, // inadequate rbytes ++ { "$6$", 0, 0, 4 }, // inadequate osize ++ ++ /* bcrypt */ ++ { "$2", 0, 0, 0 }, // truncated prefix ++ { "$2a", 0, 0, 0 }, ++ { "$2b", 0, 0, 0 }, ++ { "$2x", 0, 0, 0 }, ++ { "$2y", 0, 0, 0 }, ++ { "$2b$", 3, 0, 0 }, // too small ++ { "$2b$", 32, 0, 0 }, // too large ++ { "$2b$", 0, 2, 0 }, // inadequate rbytes ++ { "$2b$", 0, 0, 4 }, // inadequate osize ++}; ++ ++static void ++print_escaped_string (const char *s) ++{ ++ putchar ('"'); ++ for (const char *p = s; *p; p++) ++ if (*p >= ' ' && *p <= '~') ++ { ++ if (*p == '\\' || *p == '\"') ++ putchar ('\\'); ++ putchar (*p); ++ } ++ else ++ printf ("\\x%02x", (unsigned int)(unsigned char)*p); ++ putchar ('"'); ++} ++ ++static bool error_occurred = false; ++static void ++report_error (const char *fn, const struct testcase *tc, ++ int err, const char *output) ++{ ++ error_occurred = true; ++ printf ("%s(", fn); ++ print_escaped_string (tc->prefix); ++ printf (", %lu, nrbytes=%d, osize=%d):\n", tc->count, ++ tc->rbytes > 0 ? tc->rbytes : (int) sizeof rbytes - 1, ++ tc->osize > 0 ? tc->osize : CRYPT_GENSALT_OUTPUT_SIZE); ++ ++ if (output) ++ { ++ if (err) ++ printf ("\toutput with errno = %s\n", strerror (err)); ++ printf ("\texpected NULL, got "); ++ print_escaped_string (output); ++ putchar ('\n'); ++ } ++ else if (err != (tc->osize > 0 ? ERANGE : EINVAL)) ++ printf ("\tno output with errno = %s\n", ++ err ? strerror (err) : "0"); ++ else ++ printf ("\tno output with errno = %s" ++ "(shouldn't have been called)\n", strerror (err)); ++ putchar ('\n'); ++} ++ ++static void ++test_one (const struct testcase *tc) ++{ ++ char obuf[CRYPT_GENSALT_OUTPUT_SIZE]; ++ char *s; ++ int nrbytes = tc->rbytes > 0 ? tc->rbytes : (int)(sizeof rbytes - 1); ++ int osize = tc->osize > 0 ? tc->osize : CRYPT_GENSALT_OUTPUT_SIZE; ++ ++ /* It is only possible to provide a variant osize to crypt_gensalt_rn. */ ++ if (tc->osize == 0) ++ { ++ errno = 0; ++ s = crypt_gensalt (tc->prefix, tc->count, rbytes, nrbytes); ++ if (s || errno != EINVAL) ++ report_error ("gensalt", tc, errno, s); ++ ++ errno = 0; ++ s = crypt_gensalt_ra (tc->prefix, tc->count, rbytes, nrbytes); ++ if (s || errno != EINVAL) ++ report_error ("gensalt_ra", tc, errno, s); ++ free (s); ++ } ++ ++ errno = 0; ++ s = crypt_gensalt_rn (tc->prefix, tc->count, rbytes, nrbytes, obuf, osize); ++ if (s || errno != (tc->osize > 0 ? ERANGE : EINVAL)) ++ report_error ("gensalt_rn", tc, errno, s); ++} ++ ++/* All single-character strings (except "_" when BSDi extended DES ++ is enabled) are invalid prefixes, either because the character ++ cannot be the first character of any valid prefix, or because the ++ string is too short. */ ++static void ++test_single_characters (void) ++{ ++ char s[2]; ++ struct testcase tc; ++ s[1] = '\0'; ++ tc.prefix = s; ++ tc.count = 0; ++ tc.rbytes = 0; ++ tc.osize = 0; ++ ++ for (int i = 1; i < 256; i++) ++ { ++#ifdef INCLUDE_des_xbsd ++ if (i == '_') continue; ++#endif ++ s[0] = (char)i; ++ test_one (&tc); ++ } ++} ++ ++/* '$' followed by any non-ASCII-isalnum character is also always ++ invalid. */ ++static void ++test_dollar_nonalphanum (void) ++{ ++ char s[3]; ++ struct testcase tc; ++ s[0] = '$'; ++ s[2] = '\0'; ++ tc.prefix = s; ++ tc.count = 0; ++ tc.rbytes = 0; ++ tc.osize = 0; ++ ++ for (int i = 1; i < 256; i++) ++ { ++ if (('0' >= i && i <= '9') || ++ ('A' >= i && i <= 'Z') || ++ ('a' >= i && i <= 'z')) ++ continue; ++ s[1] = (char)i; ++ test_one (&tc); ++ } ++} ++ ++int ++main(void) ++{ ++ test_single_characters(); ++ test_dollar_nonalphanum(); ++ ++ /* Hand-crafted arguments for each supported algorithm. */ ++ for (size_t i = 0; i < ARRAY_SIZE (testcases); i++) ++ test_one (&testcases[i]); ++ ++ return error_occurred; ++} +diff --git a/test-crypt-sha256.c b/test-crypt-sha256.c +index 7c42398..f0c7cb2 100644 +--- a/test-crypt-sha256.c ++++ b/test-crypt-sha256.c +@@ -21,11 +21,6 @@ static const struct + "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2." + "opqey6IcA" + }, +- { +- "$5$rounds=5000$toolongsaltstring", "This is just a test", +- "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8" +- "mGRcvxa5" +- }, + { + "$5$rounds=1400$anotherlongsaltstring", + "a very much longer text to encrypt. This one even stretches over more" +@@ -43,11 +38,6 @@ static const struct + "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/" + "cZKmF/wJvD" + }, +- { +- "$5$rounds=10$roundstoolow", "the minimum number is still observed", +- "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97" +- "2bIC" +- }, + }; + + #define ntests ARRAY_SIZE (tests) +diff --git a/test-crypt-sha512.c b/test-crypt-sha512.c +index c2a1973..798fb6a 100644 +--- a/test-crypt-sha512.c ++++ b/test-crypt-sha512.c +@@ -22,11 +22,6 @@ static const struct + "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb" + "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." + }, +- { +- "$6$rounds=5000$toolongsaltstring", "This is just a test", +- "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ" +- "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" +- }, + { + "$6$rounds=1400$anotherlongsaltstring", + "a very much longer text to encrypt. This one even stretches over more" +@@ -45,11 +40,6 @@ static const struct + "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc" + "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" + }, +- { +- "$6$rounds=10$roundstoolow", "the minimum number is still observed", +- "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x" +- "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." +- }, + }; + #define ntests ARRAY_SIZE (tests) + +diff --git a/test-gensalt.c b/test-gensalt.c +index 98923e5..6713387 100644 +--- a/test-gensalt.c ++++ b/test-gensalt.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + static const char *const entropy[] = + { +@@ -25,6 +26,13 @@ static const char *const bsdi_expected_output[] = + "_J9..ZAFl", + "_J9..UqGB" + }; ++static const char *const bsdi_expected_output_r[] = ++{ ++ "_DT0.MJHn", ++ "_DT0.PKXc", ++ "_DT0.ZAFl", ++ "_DT0.UqGB" ++}; + #endif + #if INCLUDE_md5 + static const char *const md5_expected_output[] = +@@ -52,15 +60,29 @@ static const char *const sunmd5_expected_output[] = + "$md5,rounds=42259$3HtkHq/x$", + "$md5,rounds=73773$p.5e9AQf$", + }; ++static const char *const sunmd5_expected_output_r[] = ++{ ++ "$md5,rounds=4294920244$BPm.fm03$", ++ "$md5,rounds=4294937396$WKoucttX$", ++ "$md5,rounds=4294907154$3HtkHq/x$", ++ "$md5,rounds=4294938668$p.5e9AQf$", ++}; + #endif + #if INCLUDE_sha1 +-static const char *const pbkdf_expected_output[] = ++static const char *const sha1_expected_output[] = + { + "$sha1$248488$ggu.H673kaZ5$", + "$sha1$248421$SWqudaxXA5L0$", + "$sha1$257243$RAtkIrDxEovH$", + "$sha1$250464$1j.eVxRfNAPO$", + }; ++static const char *const sha1_expected_output_r[] = ++{ ++ "$sha1$3643984551$ggu.H673kaZ5$", ++ "$sha1$4200450659$SWqudaxXA5L0$", ++ "$sha1$3946507480$RAtkIrDxEovH$", ++ "$sha1$3486175838$1j.eVxRfNAPO$", ++}; + #endif + #if INCLUDE_sha256 + static const char *const sha256_expected_output[] = +@@ -70,6 +92,13 @@ static const char *const sha256_expected_output[] = + "$5$ZAFlICwYRETzIzIj", + "$5$UqGBkVu01rurVZqg" + }; ++static const char *const sha256_expected_output_r[] = ++{ ++ "$5$rounds=10191$MJHnaAkegEVYHsFK", ++ "$5$rounds=10191$PKXc3hCOSyMqdaEQ", ++ "$5$rounds=10191$ZAFlICwYRETzIzIj", ++ "$5$rounds=10191$UqGBkVu01rurVZqg" ++}; + #endif + #if INCLUDE_sha512 + static const char *const sha512_expected_output[] = +@@ -79,6 +108,13 @@ static const char *const sha512_expected_output[] = + "$6$ZAFlICwYRETzIzIj", + "$6$UqGBkVu01rurVZqg" + }; ++static const char *const sha512_expected_output_r[] = ++{ ++ "$6$rounds=10191$MJHnaAkegEVYHsFK", ++ "$6$rounds=10191$PKXc3hCOSyMqdaEQ", ++ "$6$rounds=10191$ZAFlICwYRETzIzIj", ++ "$6$rounds=10191$UqGBkVu01rurVZqg" ++}; + #endif + #if INCLUDE_bcrypt + static const char *const bcrypt_a_expected_output[] = +@@ -117,41 +153,57 @@ struct testcase + const char *const *expected_output; + unsigned int expected_len; + unsigned int expected_auto_len; ++ unsigned long rounds; + }; + + static const struct testcase testcases[] = + { + #if INCLUDE_des || INCLUDE_des_big +- { "", des_expected_output, 2, 0 }, // DES ++ { "", des_expected_output, 2, 0, 0 }, ++ // DES doesn't have variable round count. + #endif + #if INCLUDE_des_xbsd +- { "_", bsdi_expected_output, 9, 0 }, // BSDi extended DES ++ { "_", bsdi_expected_output, 9, 0, 0 }, ++ { "_", bsdi_expected_output_r, 9, 0, 10191 }, + #endif + #if INCLUDE_md5 +- { "$1$", md5_expected_output, 11, 0 }, // MD5 ++ { "$1$", md5_expected_output, 11, 0, 0 }, ++ // MD5/BSD doesn't have variable round count. + #endif + #if INCLUDE_nthash +- { "$3$", nthash_expected_output, 29, 0 }, // NTHASH ++ { "$3$", nthash_expected_output, 29, 0, 0 }, ++ // NTHASH doesn't have variable round count. + #endif + #if INCLUDE_sunmd5 +- { "$md5", sunmd5_expected_output, 27, 0 }, // SUNMD5 ++ { "$md5", sunmd5_expected_output, 27, 0, 0 }, ++ // SHA1/PBKDF always emits a round count, but we need to test its ++ // behavior on very large inputs. (This number is the largest ++ // supported round count.) ++ { "$md5", sunmd5_expected_output_r, 32, 0, 4294963199 }, + #endif + #if INCLUDE_sha1 +- { "$sha1", pbkdf_expected_output, 26, 34 }, // PBKDF with SHA1 ++ { "$sha1", sha1_expected_output, 26, 34, 0 }, ++ // SHA1/PBKDF always emits a round count, but we need to test its ++ // behavior on very large inputs. (The behavior should be the ++ // same whether or not ULONG_MAX > UINT32_MAX.) ++ { "$sha1", sha1_expected_output_r, 30, 38, ULONG_MAX }, + #endif + #if INCLUDE_sha256 +- { "$5$", sha256_expected_output, 19, 0 }, // SHA-2-256 ++ { "$5$", sha256_expected_output, 19, 0, 0 }, ++ { "$5$", sha256_expected_output_r, 32, 0, 10191 }, + #endif + #if INCLUDE_sha512 +- { "$6$", sha512_expected_output, 19, 0 }, // SHA-2-512 ++ { "$6$", sha512_expected_output, 19, 0, 0 }, ++ { "$6$", sha512_expected_output_r, 32, 0, 10191 }, + #endif + #if INCLUDE_bcrypt +- { "$2a$", bcrypt_a_expected_output, 29, 0 }, // bcrypt mode A +- { "$2b$", bcrypt_b_expected_output, 29, 0 }, // bcrypt mode B +- { "$2x$", bcrypt_x_expected_output, 29, 0 }, // bcrypt mode X +- { "$2y$", bcrypt_y_expected_output, 29, 0 }, // bcrypt mode Y ++ { "$2a$", bcrypt_a_expected_output, 29, 0, 0 }, ++ { "$2b$", bcrypt_b_expected_output, 29, 0, 0 }, ++ { "$2x$", bcrypt_x_expected_output, 29, 0, 0 }, ++ { "$2y$", bcrypt_y_expected_output, 29, 0, 0 }, ++ // bcrypt gensalt always emits a round count. + #endif +- { 0, 0, 0, 0 } ++ { 0, 0, 0, 0, 0 } + }; + + int +@@ -169,7 +221,7 @@ main (void) + for (ent = 0; ent < ARRAY_SIZE (entropy); ent++) + { + XCRYPT_SECURE_MEMSET (output, CRYPT_GENSALT_OUTPUT_SIZE); +- char *salt = crypt_gensalt_rn (tcase->prefix, 0, ++ char *salt = crypt_gensalt_rn (tcase->prefix, tcase->rounds, + entropy[ent], 16, + output, CRYPT_GENSALT_OUTPUT_SIZE); + if (salt == 0) + +From 4f71018701bf54fb9891cc94d8d268f46ed82e62 Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Wed, 11 Jul 2018 21:53:54 -0400 +Subject: [PATCH 29/38] Fix test-badsetting when not all hashes are enabled. + +It turns out I was wrong to think that we could safely leave the +subtests for excluded hashes enabled, because you get a slightly +different error in some cases (EINVAL instead of ERANGE). Instead, +for excluded hashes, check that a *correct* gensalt invocation will +still fail. +--- + test-badsetting.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 44 insertions(+), 7 deletions(-) + +diff --git a/test-badsetting.c b/test-badsetting.c +index ae2337b..d6abe71 100644 +--- a/test-badsetting.c ++++ b/test-badsetting.c +@@ -27,66 +27,97 @@ struct testcase + int osize; /* 0 = use CRYPT_GENSALT_OUTPUT_SIZE */ + }; + +-/* Note: because all of the test strings below are invalid settings, +- they can all be tested unconditionally -- it doesn't matter whether +- the specific hash algorithm that they are invalid for is actually +- configured in. */ +- ++/* For each included hash, test malformed versions of its prefix ++ and invalid combinations of other arguments to gensalt. ++ For each excluded hash, test that a correct gensalt invocation ++ will still be rejected. */ + static const struct testcase testcases[] = { + /* DES (traditional and/or bigcrypt) -- count is ignored */ ++#if INCLUDE_des || INCLUDE_des_big + { "!a", 0, 0, 0 }, // invalid first character + { "a!", 0, 0, 0 }, // invalid second character + { "xx", 1, 0, 0 }, // doesn't accept variable counts + { "xx", 0, 1, 0 }, // inadequate rbytes + { "xx", 0, 0, 1 }, // inadequate osize +- ++#else ++ { "", 0, 0, 0 }, ++ { "xx", 0, 0, 0 }, ++#endif + + /* BSDi extended DES */ ++#if INCLUDE_des_xbsd + { "_", 2, 0, 0 }, // even number + { "_", 16777217, 0, 0 }, // too large + { "_", 0, 2, 0 }, // inadequate rbytes + { "_", 0, 0, 4 }, // inadequate osize +- ++#else ++ { "_", 0, 0, 0 }, ++#endif + + /* MD5 (FreeBSD) */ ++#if INCLUDE_md5 + { "$1", 0, 0, 0 }, // truncated prefix + { "$1$", 1, 0, 0 }, // doesn't accept variable counts + { "$1$", 0, 2, 0 }, // inadequate rbytes + { "$1$", 0, 0, 4 }, // inadequate osize ++#else ++ { "$1$", 0, 0, 0 }, ++#endif + + /* MD5 (Sun) */ ++#if INCLUDE_sunmd5 + { "$m", 0, 0, 0 }, // truncated prefix + { "$md", 0, 0, 0 }, + { "$md5", 4294963200, 0, 0 }, // too large + { "$md5", 0, 2, 0 }, // inadequate rbytes + { "$md5", 0, 0, 4 }, // inadequate osize ++#else ++ { "$md5", 0, 0, 0 }, ++#endif + + /* NTHASH */ ++#if INCLUDE_nthash + { "$3", 0, 0, 0 }, // truncated prefix + { "$3$", 0, 0, 4 }, // inadequate osize ++#else ++ { "$3$", 0, 0, 0 }, ++#endif + + /* SHA1 */ ++#if INCLUDE_sha1 + { "$s", 0, 0, 0 }, // truncated prefix + { "$sh", 0, 0, 0 }, + { "$sha", 0, 0, 0 }, + { "$sha1", 0, 2, 0 }, // inadequate rbytes + { "$sha1", 0, 0, 4 }, // inadequate osize ++#else ++ { "$sha1", 0, 0, 0 }, ++#endif + + /* SHA256 */ ++#if INCLUDE_sha256 + { "$5", 0, 0, 0 }, // truncated prefix + { "$5$", 999, 0, 0 }, // too small + { "$5$", 1000000000, 0, 0 }, // too large + { "$5$", 0, 2, 0 }, // inadequate rbytes + { "$5$", 0, 0, 4 }, // inadequate osize ++#else ++ { "$5$", 0, 0, 0 }, ++#endif + + /* SHA512 */ ++#if INCLUDE_sha512 + { "$6", 0, 0, 0 }, // truncated prefix + { "$6$", 999, 0, 0 }, // too small + { "$6$", 1000000000, 0, 0 }, // too large + { "$6$", 0, 2, 0 }, // inadequate rbytes + { "$6$", 0, 0, 4 }, // inadequate osize ++#else ++ { "$6$", 0, 0, 0 }, ++#endif + + /* bcrypt */ ++#if INCLUDE_bcrypt + { "$2", 0, 0, 0 }, // truncated prefix + { "$2a", 0, 0, 0 }, + { "$2b", 0, 0, 0 }, +@@ -96,6 +127,12 @@ static const struct testcase testcases[] = { + { "$2b$", 32, 0, 0 }, // too large + { "$2b$", 0, 2, 0 }, // inadequate rbytes + { "$2b$", 0, 0, 4 }, // inadequate osize ++#else ++ { "$2a$", 0, 0, 0 }, ++ { "$2b$", 0, 0, 0 }, ++ { "$2x$", 0, 0, 0 }, ++ { "$2y$", 0, 0, 0 }, ++#endif + }; + + static void + +From b9064279d0d73e7d1f0ce3de3d52c31ed7a8ca2e Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Thu, 12 Jul 2018 12:21:44 -0400 +Subject: [PATCH 30/38] crypt.5: Add docs for SHA1, MD5/Sun, NTHASH. + +Also tighten up the wording in a couple other places and fix a bug +that was making the .hash macro not do what it was supposed to for +the DES-based hashes. +--- + crypt.5 | 114 +++++++++++++++++++++++++++++++++++++++------------------------- + 1 file changed, 70 insertions(+), 44 deletions(-) + +diff --git a/crypt.5 b/crypt.5 +index f79dd3d..5db9c92 100644 +--- a/crypt.5 ++++ b/crypt.5 +@@ -139,8 +139,7 @@ and does not show the division into prefix, options, salt, and hash. + .TP + .B Hash size + \\$6 bits +-.ie "\\$5"\\$6" +-.el (effectively \\$5) ++.if !"\\$5"\\$6" (effectively \\$5) + .TP + .B Salt size + \\$7 bits +@@ -159,66 +158,76 @@ Originally developed by Niels Provos and David Mazieres for OpenBSD + and also supported on recent versions of FreeBSD and NetBSD, + on Solaris 10 and newer, and on several GNU/*/Linux distributions. + Recommended for new password hashes. +-.hash "$2b$" "\e$2[abxy]\e$[0-9]{2}\e$[./A-Za-z0-9]{53}" 72 8 "" 184 128 "4 to 31 (logarithmic)" ++.hash "$2b$" "\e$2[abxy]\e$[0-9]{2}\e$[./A-Za-z0-9]{53}" 72 8 184 184 128 "4 to 31 (logarithmic)" + .PP +-bcrypt hashes originally used the "$2a$" prefix. +-However, in 2011 an implementation bug was discovered in crypt_blowfish +-(versions up to 1.0.4 inclusive) affecting handling of password characters with +-the 8th bit set. +-Besides fixing the bug, +-to provide for upgrade strategies for existing systems, two new prefixes were +-introduced: "$2x$", which fully re-introduces the bug, and "$2y$", which +-guarantees correct handling of both 7- and 8-bit characters. +-OpenBSD 5.5 introduced the "$2b$" prefix for behavior that exactly matches +-crypt_blowfish's "$2y$", and current crypt_blowfish supports it as well. +-Unfortunately, the behavior of "$2a$" on password characters with the 8th bit +-set has to be considered system-specific. +-When generating new password hashes, the "$2b$" or "$2y$" prefix should be used. +-(If such hashes ever need to be migrated to a system that does not yet support +-these new prefixes, the prefix in migrated copies of the already-generated +-hashes may be changed to "$2a$".) ++The alternative prefix "$2y$" is equivalent to "$2b$". ++It exists for historical reasons only. ++The alternative prefixes "$2a$" and "$2x$" ++provide bug-compatibility with crypt_blowfish 1.0.4 and earlier, ++which incorrectly processed characters with the 8th bit set. + .PP + .ti -4 + .B SHA-2-512 + .br +-A hash based on SHA-2 with 512-bit output, originally developed by +-Ulrich Drepper for GNU libc. ++A hash based on SHA-2 with 512-bit output, ++originally developed by Ulrich Drepper for GNU libc. + Supported on Linux but not common elsewhere. + Acceptable for new password hashes. +-The default CPU time cost parameter is 5000, which is too low for +-modern hardware. ++The default CPU time cost parameter is 5000, ++which is too low for modern hardware. + .br +-.hash "$6$" "\e$6\e$(rounds=[0-9]+\e$)?[^$]{1,16}\e$[./0-9A-Za-z]{86}" unlimited 8 512 512 "6 to 96" "1000 to 999,999,999" ++.hash "$6$" "\e$6\e$(rounds=[1-9][0-9]+\e$)?[./0-9A-Za-z]{1,16}\e$[./0-9A-Za-z]{86}" unlimited 8 512 512 "6 to 96" "1000 to 999,999,999" + .PP + .ti -4 + .B SHA-2-256 + .br +-A hash based on SHA-2 with 256-bit output, originally developed by +-Ulrich Drepper for GNU libc. ++A hash based on SHA-2 with 256-bit output, ++originally developed by Ulrich Drepper for GNU libc. + Supported on Linux but not common elsewhere. + Acceptable for new password hashes. +-The default CPU time cost parameter is 5000, which is too low for +-modern hardware. ++The default CPU time cost parameter is 5000, ++which is too low for modern hardware. + .br +-.hash "$5$" "\e$5\e$(rounds=[0-9]+\e$)?[^$]{1,16}\e$[./0-9A-Za-z]{43}" unlimited 8 256 256 "6 to 96" "1000 to 999,999,999" ++.hash "$5$" "\e$5\e$(rounds=[1-9][0-9]+\e$)?[./0-9A-Za-z]{1,16}\e$[./0-9A-Za-z]{43}" unlimited 8 256 256 "6 to 96" "1000 to 999,999,999" + .PP + .ti -4 +-.B MD5 ++.B SHA-1 ++.br ++A hash based on HMAC-SHA1. ++Originally developed by Simon Gerraty for NetBSD. ++Not as weak as the DES-based hashes below, ++but SHA1 is so cheap on modern hardware ++that it should not be used for new hashes. ++.hash "$sha1" "\e$sha1\e$[1-9][0-9]+\e$[./0-9A-Za-z]{1,64}\e$[./0-9A-Za-z]{8,64}[./0-9A-Za-z]{32}" unlimited 8 160 160 "6 to 384" "1 to 4,294,967,295" ++.PP ++.ti -4 ++.B MD5 (Sun) ++.br ++A hash based on the MD5 algorithm, ++with additional cleverness to make precomputation difficult, ++originally developed by Alec David Muffet for Solaris. ++Not adopted elsewhere, to our knowledge. ++Not as weak as the DES-based hashes below, ++but MD5 is so cheap on modern hardware ++that it should not be used for new hashes. ++.hash "$md5" "\e$md5(,rounds=[1-9][0-9]+)?\e$[./0-9A-Za-z]{8}\e${1,2}[./0-9A-Za-z]{22}" unlimited 8 128 128 48 "4096 to 4,294,963,199" ++.PP ++.ti -4 ++.B MD5 (FreeBSD) + .br + A hash based on the MD5 algorithm, originally developed by + Poul-Henning Kamp for FreeBSD. + Supported on most free Unixes and newer versions of Solaris. + Not as weak as the DES-based hashes below, +-but due to the weak cryptographic primitive at its heart +-and the fixed CPU time cost +-(which is already much too low) +-it should not be used for new hashes. ++but MD5 is so cheap on modern hardware ++that it should not be used for new hashes. ++CPU time cost is not adjustable. + .hash "$1$" "\e$1\e$[^$]{1,8}\e$[./0-9A-Za-z]{22}" unlimited 8 128 128 "6 to 48" 1000 + .PP + .ti -4 + .B BSDI extended DES + .br +-This is another weak extension of traditional DES, ++A weak extension of traditional DES, + which eliminates the length limit, + increases the salt size, + and makes the time cost tunable. +@@ -227,30 +236,47 @@ and is also available on at least NetBSD, OpenBSD, and FreeBSD + due to the use of David Burren's FreeSec library. + It is better than bigcrypt and traditional DES, + but still should not be used for new hashes. +-.hash _ "_[./0-9A-Za-z]{19}" unlimited 7 56 64 24 "1 to 2**24-1 (must be odd)" ++.hash _ "_[./0-9A-Za-z]{19}" unlimited 7 56 64 24 "1 to 16,777,215 (must be odd)" + .PP + .ti -4 + .B bigcrypt + .br +-This is a weak extension of traditional DES, ++A weak extension of traditional DES, + available on some System V-derived Unixes. +-All it does is raise the length limit from 8 to 128 characters. ++All it does is raise the length limit from 8 to 128 characters, ++and it does this in a crude way that allows attackers to ++guess chunks of a long passphrase in parallel. + It should not be used for new hashes. + .hash "" "[./0-9A-Za-z]{13,178}" 128 7 "up to 896" "up to 1024" 12 25 + .PP + .ti -4 + .B Traditional DES-based + .br +-This method is supported by almost all implementations of +-.BR crypt . +-Because it is based on a weak cipher primitive, ++The original hashing method from Unix V7, based on the DES block cipher. ++Because DES is cheap on modern hardware, + because there are only 4096 possible salts and 2**56 possible hashes, +-and especially because it truncates passphrases to 8 characters, +-it no longer offers adequate security for new passphrases. ++and because it truncates passphrases to 8 characters, ++it is feasible to discover ++.I any ++passphrase hashed with this method. + It should only be used if you absolutely have to generate hashes + that will work on an old operating system that supports nothing else. + .hash "" "[./0-9A-Za-z]{13}" 8 7 56 64 12 25 +- ++.PP ++.ti -4 ++.B NTHASH ++.br ++The hashing method used for network authentication ++in some versions of the SMB/CIFS protocol. ++Available, for cross-compatibility's sake, on FreeBSD. ++Based on MD4. ++Has no salt or tunable cost parameter. ++Like traditional DES, it is so weak that ++.I any ++passphrase hashed with this method is guessable. ++It should only be used if you absolutely have to generate hashes ++that will work on an old operating system that supports nothing else. ++.hash "$3$" "\e$3\e$\e$[0-9a-f]{32}" unlimited 8 256 256 0 1 + .SH SEE ALSO + .BR crypt (3), + .BR crypt_rn (3), + +From 77461c03422ce1f5829b0180e68c4bdbf914956c Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Thu, 12 Jul 2018 12:23:59 -0400 +Subject: [PATCH 31/38] Add two more test programs to .gitignore. + +--- + .gitignore | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/.gitignore b/.gitignore +index bb7f15c..16488f3 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -54,6 +54,7 @@ + /test-alg-sha256 + /test-alg-sha512 + /test-badsalt ++/test-badsetting + /test-bigcrypt + /test-byteorder + /test-crypt-bcrypt +@@ -67,6 +68,7 @@ + /test-des-obsolete + /test-des-obsolete_r + /test-gensalt ++/test-short-outbuf + + # backup-files + + +From 9f728b79718a8e8b371f48b75592beed638f9c2b Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Thu, 12 Jul 2018 12:24:46 -0400 +Subject: [PATCH 32/38] test-badsetting.c: correct "Written by" year. + +--- + test-badsetting.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test-badsetting.c b/test-badsetting.c +index d6abe71..665e830 100644 +--- a/test-badsetting.c ++++ b/test-badsetting.c +@@ -1,6 +1,6 @@ + /* Test rejection of ill-formed setting strings. + +- Written by Zack Weinberg in 2017. ++ Written by Zack Weinberg in 2018. + To the extent possible under law, Zack Weinberg has waived all + copyright and related or neighboring rights to this work. + + +From b3ee64bf08082367ea2116ea1fb2007e1a2896cd Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Thu, 12 Jul 2018 12:25:12 -0400 +Subject: [PATCH 33/38] Add tests for get_random_bytes. + +It turns out not to be *that* hard to exercise the fallback logic in +get_random_bytes, thanks to GNU ld's --wrap feature. There is also +some basic black-box testing of the get_random_bytes interface. + +The change to randombytes.c itself ensures 100% predictable behavior +if get_random_bytes should ever be called with buflen zero. +--- + .gitignore | 2 + + Makefile.am | 10 +- + configure.ac | 1 + + m4/zw_ld_wrap.m4 | 47 ++++++++ + randombytes.c | 2 + + test-getrandom-fallbacks.c | 282 +++++++++++++++++++++++++++++++++++++++++++++ + test-getrandom-interface.c | 211 +++++++++++++++++++++++++++++++++ + 7 files changed, 554 insertions(+), 1 deletion(-) + create mode 100644 m4/zw_ld_wrap.m4 + create mode 100644 test-getrandom-fallbacks.c + create mode 100644 test-getrandom-interface.c + +diff --git a/.gitignore b/.gitignore +index 16488f3..06ee727 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -68,6 +68,8 @@ + /test-des-obsolete + /test-des-obsolete_r + /test-gensalt ++/test-getrandom-fallbacks ++/test-getrandom-interface + /test-short-outbuf + + # backup-files +diff --git a/Makefile.am b/Makefile.am +index 51cba76..f99f842 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -127,7 +127,8 @@ check_PROGRAMS = \ + test-crypt-pbkdf1-sha1 test-crypt-sha256 test-crypt-sha512 \ + test-crypt-sunmd5 \ + test-byteorder test-badsalt test-badsetting test-gensalt \ +- test-short-outbuf ++ test-short-outbuf \ ++ test-getrandom-interface test-getrandom-fallbacks + + if ENABLE_OBSOLETE_API + libcrypt_la_SOURCES += crypt-des-obsolete.c +@@ -183,6 +184,13 @@ test_alg_sha1_LDADD = alg-sha1.lo + test_alg_sha256_LDADD = alg-sha256.lo + test_alg_sha512_LDADD = alg-sha512.lo + ++test_getrandom_interface_LDADD = randombytes.lo ++test_getrandom_fallbacks_LDADD = randombytes.lo ++if HAVE_LD_WRAP ++test_getrandom_fallbacks_LDFLAGS = \ ++ -Wl,--wrap,getentropy -Wl,--wrap,getrandom -Wl,--wrap,syscall \ ++ -Wl,--wrap,open -Wl,--wrap,read -Wl,--wrap,close ++endif + + # Every object file depends on crypt-symbol-vers.h and crypt-hashes.h, + # which are generated files, so automatic dependency generation is not +diff --git a/configure.ac b/configure.ac +index 119f171..274c16a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -137,6 +137,7 @@ zw_C_ALIGNAS + zw_C_ALIGNOF + zw_C_MAX_ALIGN_T + zw_C_STATIC_ASSERT ++zw_PROG_LD_WRAP + + # Checks for library functions. + AC_CHECK_FUNCS_ONCE([ +diff --git a/m4/zw_ld_wrap.m4 b/m4/zw_ld_wrap.m4 +new file mode 100644 +index 0000000..87b22e7 +--- /dev/null ++++ b/m4/zw_ld_wrap.m4 +@@ -0,0 +1,47 @@ ++dnl Written by Zack Weinberg in 2018. ++dnl To the extent possible under law, Zack Weinberg has waived all ++dnl copyright and related or neighboring rights to this work. ++dnl ++dnl See https://creativecommons.org/publicdomain/zero/1.0/ for further ++dnl details. ++dnl ++dnl Find out whether ld --wrap is supported. ++AC_DEFUN([zw_PROG_LD_WRAP], ++ [AC_REQUIRE([AC_PROG_CC]) ++ AC_CACHE_CHECK([for ld --wrap], [zw_cv_prog_ld_wrap], ++ [save_LDFLAGS="$LDFLAGS" ++ save_LIBS="$LIBS" ++ LDFLAGS="" ++ LIBS="" ++ AC_COMPILE_IFELSE( ++ [AC_LANG_SOURCE([[ ++ extern void bar(void); ++ void foo(void) { bar(); } ++ ]])], ++ [mv conftest.$OBJEXT conftest2.$OBJEXT ++ LDFLAGS="-Wl,--wrap,bar" ++ LIBS="conftest2.$OBJEXT" ++ AC_LINK_IFELSE( ++ [AC_LANG_PROGRAM([[ ++ extern void foo(void); ++ void __wrap_bar(void) {} ++ ]], [[ ++ foo(); ++ ]])], ++ [zw_cv_prog_ld_wrap=yes], ++ [zw_cv_prog_ld_wrap=no]) ++ rm -f conftest2.$OBJEXT ++ ], ++ [zw_cv_prog_ld_wrap=no]) ++ LDFLAGS="$save_LDFLAGS" ++ LIBS="$save_LIBS"]) ++ if test x$zw_cv_prog_ld_wrap = xyes; then ++ have_ld_wrap=yes ++ AC_DEFINE([HAVE_LD_WRAP], 1, ++ [Define to 1 if -Wl,--wrap,SYMBOL can be used to intercept ++ calls to SYMBOL at link time.]) ++ else ++ have_ld_wrap=no ++ fi ++ AM_CONDITIONAL([HAVE_LD_WRAP], [test $have_ld_wrap = yes]) ++]) +diff --git a/randombytes.c b/randombytes.c +index 5053525..8d95dcc 100644 +--- a/randombytes.c ++++ b/randombytes.c +@@ -61,6 +61,8 @@ + bool + get_random_bytes(void *buf, size_t buflen) + { ++ if (buflen == 0) ++ return true; + if (buflen > 256) + { + errno = EIO; +diff --git a/test-getrandom-fallbacks.c b/test-getrandom-fallbacks.c +new file mode 100644 +index 0000000..8cbab5f +--- /dev/null ++++ b/test-getrandom-fallbacks.c +@@ -0,0 +1,282 @@ ++/* Test the fallback logic in get_random_bytes. ++ ++ Written by Zack Weinberg in 2018. ++ To the extent possible under law, Zack Weinberg has waived all ++ copyright and related or neighboring rights to this work. ++ ++ See https://creativecommons.org/publicdomain/zero/1.0/ for further ++ details. */ ++ ++#include "crypt-port.h" ++#include "crypt-private.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_FCNTL_H ++#include ++#endif ++#if defined HAVE_SYS_SYSCALL_H ++#include ++#endif ++#ifdef HAVE_SYS_STAT_H ++#include ++#endif ++#ifdef HAVE_UNISTD_H ++#include ++#endif ++ ++/* If arc4random_buf is available, all of the fallback logic is compiled ++ out and this test is unnecessary. If ld --wrap is not available this ++ test will not work. */ ++#if defined HAVE_ARC4RANDOM_BUF || !defined HAVE_LD_WRAP ++ ++int ++main (void) ++{ ++ return 77; ++} ++ ++#else ++ ++/* All of the mock system primitives below fill in their buffer with ++ repeats of these bytes, so we can tell where the data came from. */ ++#define MOCK_getentropy 'e' ++#define MOCK_getrandom 'r' ++#define MOCK_sys_getentropy 'E' ++#define MOCK_sys_getrandom 'R' ++#define MOCK_urandom 'u' ++ ++#ifdef HAVE_GETENTROPY ++static bool getentropy_should_fail = false; ++extern int __wrap_getentropy (void *, size_t); ++int ++__wrap_getentropy (void *buf, size_t buflen) ++{ ++ if (getentropy_should_fail) ++ { ++ errno = ENOSYS; ++ return -1; ++ } ++ else ++ { ++ memset (buf, MOCK_getentropy, buflen); ++ return 0; ++ } ++} ++#endif ++ ++#ifdef HAVE_GETRANDOM ++static bool getrandom_should_fail = false; ++extern ssize_t __wrap_getrandom (void *, size_t, unsigned int); ++ssize_t ++__wrap_getrandom (void *buf, size_t buflen, unsigned int ARG_UNUSED(flags)) ++{ ++ if (getrandom_should_fail) ++ { ++ errno = ENOSYS; ++ return -1; ++ } ++ else ++ { ++ buflen = MIN (buflen, SSIZE_MAX); ++ memset (buf, MOCK_getrandom, buflen); ++ return (ssize_t)buflen; ++ } ++} ++#endif ++ ++#ifdef HAVE_SYSCALL ++#ifdef SYS_getentropy ++static bool sys_getentropy_should_fail = false; ++#endif ++#ifdef SYS_getrandom ++static bool sys_getrandom_should_fail = false; ++#endif ++static bool other_syscalls = false; ++extern long __wrap_syscall (long, ...); ++long ++__wrap_syscall(long number, ...) ++{ ++#ifdef SYS_getentropy ++ if (number == SYS_getentropy) ++ { ++ if (sys_getentropy_should_fail) ++ { ++ errno = ENOSYS; ++ return -1; ++ } ++ else ++ { ++ va_list ap; ++ va_start (ap, number); ++ void *buf = va_arg (ap, void *); ++ size_t buflen = va_arg (ap, size_t); ++ va_end (ap); ++ memset (buf, MOCK_sys_getentropy, buflen); ++ return 0; ++ } ++ } ++#endif ++#ifdef SYS_getrandom ++ if (number == SYS_getrandom) ++ { ++ if (sys_getrandom_should_fail) ++ { ++ errno = ENOSYS; ++ return -1; ++ } ++ else ++ { ++ va_list ap; ++ va_start (ap, number); ++ void *buf = va_arg (ap, void *); ++ size_t buflen = va_arg (ap, size_t); ++ buflen = MIN (buflen, SSIZE_MAX); ++ memset (buf, MOCK_sys_getrandom, buflen); ++ return (ssize_t)buflen; ++ } ++ } ++#endif ++ /* There is no vsyscall. We just have to hope nobody in this test ++ program wants to use syscall() for anything else. */ ++ other_syscalls = true; ++ fprintf (stderr, "ERROR: unexpected syscall(%ld)\n", number); ++ errno = ENOSYS; ++ return -1; ++} ++#endif /* HAVE_SYSCALL */ ++ ++/* It is not possible to hit both of the code paths that can set the ++ "/dev/urandom doesn't work" flag in a single test program, because ++ there's no way to _clear_ that flag again. This test chooses to ++ exercise the read-failure path, not the open-failure path. */ ++#if defined HAVE_SYS_STAT_H && defined HAVE_FCNTL_H && defined HAVE_UNISTD_H ++static bool urandom_should_fail = false; ++static int urandom_fd = -1; ++extern int __wrap_open (const char *, int, mode_t); ++extern int __real_open (const char *, int, mode_t); ++int ++__wrap_open (const char *path, int flags, mode_t mode) ++{ ++ int ret = __real_open (path, flags, mode); ++ if (ret == -1) ++ return ret; ++ if (!strcmp (path, "/dev/urandom")) ++ urandom_fd = ret; ++ return ret; ++} ++ ++extern int __wrap_close (int); ++extern int __real_close (int); ++int ++__wrap_close (int fd) ++{ ++ if (fd == urandom_fd) ++ urandom_fd = -1; ++ return __real_close (fd); ++} ++ ++extern ssize_t __wrap_read (int, void *, size_t); ++extern ssize_t __real_read (int, void *, size_t); ++ssize_t ++__wrap_read (int fd, void *buf, size_t count) ++{ ++ if (fd == urandom_fd) ++ { ++ if (urandom_should_fail) ++ { ++ errno = ENOSYS; ++ return -1; ++ } ++ else ++ { ++ count = MIN (count, SSIZE_MAX); ++ memset (buf, MOCK_urandom, count); ++ return (ssize_t)count; ++ } ++ } ++ else ++ return __real_read (fd, buf, count); ++} ++ ++#endif ++ ++struct subtest ++{ ++ const char *what; ++ bool *make_fail; ++ char expected; ++}; ++const struct subtest subtests[] = { ++ { "initial", 0, 'x' }, ++ ++#ifdef HAVE_GETENTROPY ++ { "getentropy", &getentropy_should_fail, MOCK_getentropy }, ++#endif ++#ifdef HAVE_GETRANDOM ++ { "getrandom", &getrandom_should_fail, MOCK_getrandom }, ++#endif ++ ++#ifdef HAVE_SYSCALL ++#ifdef SYS_getentropy ++ { "sys_getentropy", &sys_getentropy_should_fail, MOCK_sys_getentropy }, ++#endif ++#ifdef SYS_getrandom ++ { "sys_getrandom", &sys_getrandom_should_fail, MOCK_sys_getrandom }, ++#endif ++#endif ++ ++#if defined HAVE_SYS_STAT_H && defined HAVE_FCNTL_H && defined HAVE_UNISTD_H ++ { "/dev/urandom", &urandom_should_fail, MOCK_urandom }, ++#endif ++ ++ { "final", 0, 0 } ++}; ++ ++int ++main (void) ++{ ++ char buf[257]; ++ char expected[2] = { 0, 0 }; ++ memset (buf, 'x', sizeof buf - 1); ++ buf[256] = '\0'; ++ bool failed = false; ++ const struct subtest *s; ++ ++ for (s = subtests; s->expected;) ++ { ++ expected[0] = s->expected; ++ if (strspn (buf, expected) != 256) ++ { ++ printf ("FAIL: %s: buffer not filled with '%c'\n", ++ s->what, s->expected); ++ failed = true; ++ } ++ else ++ printf ("ok: %s (output)\n", s->what); ++ ++ if (s->make_fail) ++ *(s->make_fail) = true; ++ s++; ++ ++ bool r = get_random_bytes (buf, sizeof buf - 1); ++ if ((s->expected && !r) || (!s->expected && r)) ++ { ++ printf ("FAIL: %s: get_random_bytes: %s\n", ++ s->what, strerror (errno)); ++ failed = true; ++ } ++ else ++ printf ("ok: %s (return)\n", s->what); ++ } ++#if HAVE_SYSCALL ++ failed |= other_syscalls; ++#endif ++ return failed; ++} ++ ++#endif +diff --git a/test-getrandom-interface.c b/test-getrandom-interface.c +new file mode 100644 +index 0000000..16df6d0 +--- /dev/null ++++ b/test-getrandom-interface.c +@@ -0,0 +1,211 @@ ++/* Test the exposed interface of get_random_bytes. ++ ++ Written by Zack Weinberg in 2018. ++ To the extent possible under law, Zack Weinberg has waived all ++ copyright and related or neighboring rights to this work. ++ ++ See https://creativecommons.org/publicdomain/zero/1.0/ for further ++ details. */ ++ ++#include "crypt-port.h" ++#include "crypt-private.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static bool error_occurred; ++ ++/* Note: both of the following test functions expect PAGE to point to ++ PAGESIZE bytes of read-write memory followed by another PAGESIZE ++ bytes of unwritable memory. Both functions also assume that ++ PAGESIZE is greater than or equal to 256. */ ++ ++static void ++test_basic (char *page, size_t pagesize) ++{ ++ printf ("Testing basic functionality...\n"); ++ ++ // A request for zero bytes should succeed, and should not touch the ++ // output buffer. ++ if (!get_random_bytes (page + pagesize, 0)) ++ { ++ printf ("ERROR: get_random_bytes(0) = %s\n", strerror (errno)); ++ error_occurred = 1; ++ } ++ else ++ printf ("ok: get_random_bytes(0)\n"); ++ ++ // A request for 257 bytes should fail, and should not touch the ++ // output buffer. ++ if (get_random_bytes (page + pagesize, 257)) ++ { ++ printf ("ERROR: get_random_bytes(257) succeeded\n"); ++ error_occurred = 1; ++ } ++ else if (errno != EIO) ++ { ++ printf ("ERROR: get_random_bytes(257) = %s (expected: %s)\n", ++ strerror (errno), strerror (EIO)); ++ error_occurred = 1; ++ } ++ else ++ printf ("ok: get_random_bytes(257)\n"); ++ ++ // A request for five bytes should succeed, and should not write ++ // past the end of the buffer. (We use an odd, prime number here to ++ // catch implementations that might write e.g. four or eight bytes ++ // at once.) ++ if (!get_random_bytes (page + pagesize - 5, 5)) ++ { ++ printf ("ERROR: get_random_bytes(5) = %s\n", strerror (errno)); ++ error_occurred = 1; ++ } ++ else ++ printf ("ok: get_random_bytes(5)\n"); ++ ++ // It's extremely difficult to say whether any output of a random ++ // number generator is or is not "good", but the odds that 251 bytes ++ // of RNG output are all zero is one in 2**2008, and the odds that ++ // the first 251 bytes of RNG output are equal to the second 251 ++ // bytes of RNG output is also one in 2**2008. (Again, we use an ++ // odd, prime number to trip up implementations that do wide writes.) ++ ++ char prev[251]; ++ memset (prev, 0, 251); ++ ++ if (!get_random_bytes (page + pagesize - 251, 251)) ++ { ++ printf ("ERROR: get_random_bytes(251)/1 = %s\n", strerror (errno)); ++ error_occurred = 1; ++ return; ++ } ++ ++ if (!memcmp (prev, page + pagesize - 251, 251)) ++ { ++ printf ("ERROR: get_random_bytes(251)/1 produced all zeroes\n"); ++ error_occurred = 1; ++ return; ++ } ++ ++ memcpy (prev, page + pagesize - 251, 251); ++ ++ if (!get_random_bytes (page + pagesize - 251, 251)) ++ { ++ printf ("ERROR: get_random_bytes(251)/2 = %s\n", strerror (errno)); ++ error_occurred = 1; ++ return; ++ } ++ ++ if (!memcmp (prev, page + pagesize - 251, 251)) ++ { ++ printf ("ERROR: get_random_bytes(251)/2 produced same output " ++ "as /1\n"); ++ error_occurred = 1; ++ return; ++ } ++ ++ printf ("ok: get_random_bytes(251) smoke test of output\n"); ++} ++ ++static void ++test_fault (char *page, size_t pagesize) ++{ ++ printf ("Testing partially inaccessible output buffer...\n"); ++ bool rv = get_random_bytes (page + pagesize - 64, 128); ++ /* shouldn't ever get here */ ++ error_occurred = 1; ++ if (rv) ++ printf ("ERROR: success (should have faulted)\n"); ++ else ++ printf ("ERROR: failed with %s (should have faulted)\n", ++ strerror (errno)); ++} ++ ++/* In one of the tests above, a segmentation fault is the expected result. */ ++static jmp_buf env; ++static void ++segv_handler (int sig) ++{ ++ siglongjmp (env, sig); ++} ++ ++static void ++expect_no_fault (char *page, size_t pagesize, ++ void (*testfn) (char *, size_t)) ++{ ++ int rv = sigsetjmp (env, 1); ++ if (!rv) ++ testfn (page, pagesize); ++ else ++ { ++ printf ("ERROR: Unexpected %s\n", strsignal (rv)); ++ error_occurred = 1; ++ } ++} ++ ++static void ++expect_a_fault (char *page, size_t pagesize, ++ void (*testfn) (char *, size_t)) ++{ ++ int rv = sigsetjmp (env, 1); ++ if (!rv) ++ { ++ testfn (page, pagesize); ++ printf ("ERROR: No signal occurred\n"); ++ error_occurred = 1; ++ } ++ else ++ { ++ printf ("ok: %s (as expected)\n", strsignal (rv)); ++ } ++} ++ ++int ++main (void) ++{ ++ /* Set up a two-page region whose first page is read-write and ++ whose second page is inaccessible. */ ++ size_t pagesize = (size_t) sysconf (_SC_PAGESIZE); ++ if (pagesize < 256) ++ { ++ printf ("ERROR: pagesize of %zu is too small\n", pagesize); ++ return 1; ++ } ++ ++ char *page = mmap (0, pagesize * 2, PROT_READ|PROT_WRITE, ++ MAP_PRIVATE|MAP_ANON, -1, 0); ++ if (page == MAP_FAILED) ++ { ++ perror ("mmap"); ++ return 1; ++ } ++ memset (page, 'x', pagesize * 2); ++ if (mprotect (page + pagesize, pagesize, PROT_NONE)) ++ { ++ perror ("mprotect"); ++ return 1; ++ } ++ ++ struct sigaction sa, os, ob; ++ sigfillset (&sa.sa_mask); ++ sa.sa_flags = SA_RESTART; ++ sa.sa_handler = segv_handler; ++ if (sigaction (SIGBUS, &sa, &ob) || sigaction (SIGSEGV, &sa, &os)) ++ { ++ perror ("sigaction"); ++ return 1; ++ } ++ ++ expect_no_fault (page, pagesize, test_basic); ++ expect_a_fault (page, pagesize, test_fault); ++ ++ sigaction (SIGBUS, &ob, 0); ++ sigaction (SIGSEGV, &os, 0); ++ ++ return error_occurred; ++} + +From 59680ceac13f85a1506fca87255ea47304a8e493 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Tue, 26 Jun 2018 22:45:01 +0000 +Subject: [PATCH 34/38] crypt.h: introduce CRYPT_GENSALT_IMPLEMENTS_* feature + test macros + +Define CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX and +CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY feature test macros. + +These macros could be checked by portable users of crypt_gensalt* +functions to find out whether null pointers could be specified +as PREFIX and RBYTES arguments. +--- + crypt-base.h | 6 ++++++ + crypt_gensalt.3 | 21 +++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/crypt-base.h b/crypt-base.h +index 565f943..dd27b8e 100644 +--- a/crypt-base.h ++++ b/crypt-base.h +@@ -185,6 +185,12 @@ extern char *crypt_gensalt_ra (const char *__prefix, unsigned long __count, + const char *__rbytes, int __nrbytes) + __THROW; + ++/* These macros could be checked by portable users of crypt_gensalt* ++ functions to find out whether null pointers could be specified ++ as PREFIX and RBYTES arguments. */ ++#define CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX 1 ++#define CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY 1 ++ + /*TRAILER*/ + + #endif /* crypt.h */ +diff --git a/crypt_gensalt.3 b/crypt_gensalt.3 +index 8759011..ebfff28 100644 +--- a/crypt_gensalt.3 ++++ b/crypt_gensalt.3 +@@ -172,6 +172,19 @@ failed to allocate memory for the compiled + string. + .ad b + .hy 1 ++.SH FEATURE TEST MACROS ++The following macros are defined by ++.BR crypt.h : ++.TP ++.B CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX ++A null pointer can be specified as ++.I prefix ++argument. ++.TP ++.B CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY ++A null pointer can be specified as ++.I rbytes ++argument. + .SH PORTABILITY NOTES + The functions + .BR crypt_gensalt ", " crypt_gensalt_rn ", and " crypt_gensalt_ra +@@ -181,6 +194,14 @@ A function with the name + .B crypt_gensalt + also exists on Solaris 10 and newer, but its prototype and semantics differ. + .PP ++The default prefix and auto entropy features are available since libxcrypt ++version 4.0.0. Portable software can use feature test macros to find out ++whether null pointers could be specified as ++.I prefix ++and ++.I rbytes ++arguments. ++.PP + The set of supported hashing methods varies considerably from system + to system. + .SH ATTRIBUTES + +From d077e0bf39c7b4e3443c35ac8abd6eae4489aecd Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Mon, 9 Jul 2018 17:35:38 +0000 +Subject: [PATCH 35/38] Install libcrypt.pc symlink along with libxcrypt.pc + +As the library name differs from the project name, avoid potential +confusion libcrypt.pc vs libxcrypt.pc by installing libcrypt.pc symlink +to libxcrypt.pc file. +--- + Makefile.am | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/Makefile.am b/Makefile.am +index f99f842..945f283 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -36,6 +36,15 @@ libcrypt_la_SOURCES = \ + randombytes.c + + pkgconfig_DATA = libxcrypt.pc ++# Install libcrypt.pc symlink to libxcrypt.pc file. ++.PHONY: install-data-hook-pkgconfig uninstall-hook-pkgconfig ++install-data-hook: install-data-hook-pkgconfig ++uninstall-hook: uninstall-hook-pkgconfig ++install-data-hook-pkgconfig: ++ cd $(DESTDIR)$(pkgconfigdir) && \ ++ $(LN_S) libxcrypt.pc libcrypt.pc ++uninstall-hook-pkgconfig: ++ -rm -f $(DESTDIR)$(pkgconfigdir)/libcrypt.pc + + # Build libcrypt.so.2 if obsolete APIs are excluded, libcrypt.so.1 otherwise. + if ENABLE_OBSOLETE_API + +From 4f22827c619c2196898b32de44bd45ca627de545 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Fri, 22 Jun 2018 00:07:54 +0000 +Subject: [PATCH 36/38] Extend --enable-obsolete-api configure option + +Make vendor specific parts of compatibility ABI that are enabled by +--enable-obsolete-api option configurable. This allows vendors to +enable only those parts of compatibility ABI that are relevant to them. +--- + Makefile.am | 10 ++++++++-- + configure.ac | 37 ++++++++++++++++++++++++++++--------- + gen-map.awk | 29 +++++++++++++++++++++-------- + gen-vers.awk | 26 +++++++++++++++++++------- + libcrypt.map.in | 10 +++++----- + 5 files changed, 81 insertions(+), 31 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 945f283..be8b585 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -68,13 +68,17 @@ CLEANFILES = libcrypt.map libcrypt.map.T \ + + libcrypt.map: libcrypt.map.in gen-map.awk Makefile + $(AM_V_GEN)LC_ALL=C $(AWK) \ +- -v SYMVER_MIN=$(SYMVER_MIN) -v SYMVER_FLOOR=$(SYMVER_FLOOR) \ ++ -v SYMVER_MIN=$(SYMVER_MIN) \ ++ -v SYMVER_FLOOR=$(SYMVER_FLOOR) \ ++ -v COMPAT_ABI=$(COMPAT_ABI) \ + -f $(srcdir)/gen-map.awk $(srcdir)/libcrypt.map.in > libcrypt.map.T + $(AM_V_at)mv -f libcrypt.map.T libcrypt.map + + crypt-symbol-vers.h: libcrypt.map.in gen-vers.awk Makefile + $(AM_V_GEN)LC_ALL=C $(AWK) \ +- -v SYMVER_MIN=$(SYMVER_MIN) -v SYMVER_FLOOR=$(SYMVER_FLOOR) \ ++ -v SYMVER_MIN=$(SYMVER_MIN) \ ++ -v SYMVER_FLOOR=$(SYMVER_FLOOR) \ ++ -v COMPAT_ABI=$(COMPAT_ABI) \ + -f $(srcdir)/gen-vers.awk \ + $(srcdir)/libcrypt.map.in > crypt-symbol-vers.h.T + $(AM_V_at)mv -f crypt-symbol-vers.h.T crypt-symbol-vers.h +@@ -91,6 +95,7 @@ crypt-hashes.h: hashes.lst gen-hashes.awk Makefile + $(srcdir)/hashes.lst > crypt-hashes.h.T + $(AM_V_at)mv -f crypt-hashes.h.T crypt-hashes.h + ++if ENABLE_COMPAT_SUSE + # When we are being binary compatible, also install symbolic links to + # mimic SUSE's libowcrypt; any program that uses -lowcrypt in its + # build, or already has a NEEDED entry for libowcrypt.so.1, will be +@@ -127,6 +132,7 @@ uninstall-hook-libshared: + $(DESTDIR)$(libdir)/libowcrypt.so.1 + endif + endif ++endif + + check_PROGRAMS = \ + test-alg-des test-alg-hmac-sha1 test-alg-md4 test-alg-md5 \ +diff --git a/configure.ac b/configure.ac +index 274c16a..3b13d9d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -187,20 +187,38 @@ fi + + AC_ARG_ENABLE([obsolete-api], + AS_HELP_STRING( +- [--disable-obsolete-api], +- [do not include compatibility definitions of obsolete APIs +- (fcrypt, encrypt, setkey) in the shared library. +- Breaks binary compatibility with glibc's libcrypt. +- Only affects existing binaries; new programs cannot be +- linked against these functions in any case.] ++ [--enable-obsolete-api[=ARG]], ++ [When set to "yes", include all compatibility interfaces. ++ When set to "alt", include interfaces for compatibility with ALT. ++ When set to "glibc", include interfaces for compatibility with glibc. ++ When set to "owl", include interfaces for compatibility with Owl. ++ When set to "suse", include interfaces for compatibility with SUSE. ++ When set to "no", do not include compatibility definitions of obsolete ++ APIs (fcrypt, encrypt, setkey) in the shared library, which breaks ++ binary compatibility with glibc's libcrypt. Only affects existing ++ binaries; new programs cannot be linked against these compatibility ++ functions in any case. [default=yes]] + ), + [case "${enableval}" in +- yes) enable_obsolete_api=1 ;; +- no) enable_obsolete_api=0 ;; ++ alt|glibc|owl) ++ enable_obsolete_api=1 ++ enable_compat_suse=0 ++ COMPAT_ABI=${enableval} ;; ++ yes|suse) ++ enable_obsolete_api=1 ++ enable_compat_suse=1 ++ COMPAT_ABI=${enableval} ;; ++ no) ++ enable_obsolete_api=0 ++ enable_compat_suse=0 ++ COMPAT_ABI=${enableval} ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-obsolete-api]) ;; + esac], +- [enable_obsolete_api=1] ++ [enable_obsolete_api=1 ++ enable_compat_suse=1 ++ COMPAT_ABI=yes] + ) ++AC_SUBST(COMPAT_ABI) + + AC_ARG_ENABLE([hashes], + AS_HELP_STRING( +@@ -298,6 +316,7 @@ AC_DEFINE_UNQUOTED([ENABLE_OBSOLETE_API], [$enable_obsolete_api], + [Define as 1 if the obsolete APIs (fcrypt, encrypt, setkey) + should be included, 0 otherwise.]) + AM_CONDITIONAL([ENABLE_OBSOLETE_API], [test $enable_obsolete_api = 1]) ++AM_CONDITIONAL([ENABLE_COMPAT_SUSE], [test $enable_compat_suse = 1]) + + # The Makefile needs to know which versions of the library we are building. + AM_CONDITIONAL([ENABLE_STATIC], [test $enable_static = yes]) +diff --git a/gen-map.awk b/gen-map.awk +index f8289e2..025af05 100644 +--- a/gen-map.awk ++++ b/gen-map.awk +@@ -8,10 +8,11 @@ + # details. + + # The .map.in file is the first input file, and we expect the Makefile +-# to have set the variables SYMVER_MIN and SYMVER_FLOOR. All symbol +-# versions lower than SYMVER_MIN are discarded from the output. +-# All symbol versions lower than SYMVER_FLOOR are replaced with +-# SYMVER_FLOOR. SYMVER_FLOOR must be greater than or equal to SYMVER_MIN. ++# to have set the variables SYMVER_MIN, SYMVER_FLOOR, and COMPAT_ABI. ++# All compat symbol versions that do not match COMPAT_ABI are ignored. ++# All symbol versions lower than SYMVER_MIN are discarded from the output. ++# All symbol versions lower than SYMVER_FLOOR are replaced with SYMVER_FLOOR. ++# SYMVER_FLOOR must be greater than or equal to SYMVER_MIN. + # + # The ordering of symbol versions is entirely controlled by the %chain + # directive, which must therefore list both all of the versions +@@ -42,11 +43,23 @@ $1 == "%chain" { + + { + for (i = 2; i <= NF; i++) { +- if ($i != "-") { +- if ($i in SYMBOLS) { +- SYMBOLS[$i] = SYMBOLS[$i] SUBSEP $1 ++ sym=$i ++ if (sym != "-") { ++ n=split(sym, a, ":") ++ if (n > 1) { ++ sym="-" ++ for (j = 2; j <= n; j++) { ++ if (COMPAT_ABI == "yes" || COMPAT_ABI == a[j]) { ++ sym=a[1] ++ } ++ } ++ } ++ } ++ if (sym != "-") { ++ if (sym in SYMBOLS) { ++ SYMBOLS[sym] = SYMBOLS[sym] SUBSEP $1 + } else { +- SYMBOLS[$i] = $1 ++ SYMBOLS[sym] = $1 + } + } + } +diff --git a/gen-vers.awk b/gen-vers.awk +index 4870d05..a846a58 100644 +--- a/gen-vers.awk ++++ b/gen-vers.awk +@@ -9,9 +9,9 @@ + # details. + + # The .map.in file is the first input file, and we expect the Makefile +-# to have set the variables SYMVER_MIN and SYMVER_FLOOR. See +-# libcrypt.map.in and gen-vers.awk for explanations of the format of +-# .map.in files. See crypt-port.h for an explanation of how to use ++# to have set the variables SYMVER_MIN, SYMVER_FLOOR, and COMPAT_ABI. ++# See libcrypt.map.in and gen-vers.awk for explanations of the format ++# of .map.in files. See crypt-port.h for an explanation of how to use + # the macros generated by this program. + # + # Note: if you change the format of .map.in files you probably need to +@@ -51,10 +51,22 @@ $1 == "%chain" { + } + } + for (i = 3; i <= NF; i++) { +- if ($i in SYMBOLS) { +- SYMBOLS[$i] = SYMBOLS[$i] SUBSEP $1 +- } else { +- SYMBOLS[$i] = $1 ++ sym=$i ++ n=split(sym, a, ":") ++ if (n > 1) { ++ sym="" ++ for (j = 2; j <= n; j++) { ++ if (COMPAT_ABI == "yes" || COMPAT_ABI == a[j]) { ++ sym=a[1] ++ } ++ } ++ } ++ if (sym != "") { ++ if (sym in SYMBOLS) { ++ SYMBOLS[sym] = SYMBOLS[sym] SUBSEP $1 ++ } else { ++ SYMBOLS[sym] = $1 ++ } + } + } + } +diff --git a/libcrypt.map.in b/libcrypt.map.in +index 18aac79..0989990 100644 +--- a/libcrypt.map.in ++++ b/libcrypt.map.in +@@ -9,12 +9,12 @@ crypt_r XCRYPT_2.0 GLIBC_2.0 + # Actively supported Openwall extensions; never actually added to + # upstream GNU libc, but present in at least Openwall, ALT, and SUSE + # Linux distributions with one or more of these symbol versions +-crypt_rn XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.1 +-crypt_gensalt XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.1 OW_CRYPT_1.0 +-crypt_gensalt_rn XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.1 OW_CRYPT_1.0 ++crypt_rn XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt ++crypt_gensalt XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt OW_CRYPT_1.0:suse ++crypt_gensalt_rn XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt OW_CRYPT_1.0:suse + +-crypt_ra XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.2 +-crypt_gensalt_ra XCRYPT_2.0 GLIBC_2.0 GLIBC_2.2.2 OW_CRYPT_1.0 ++crypt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt ++crypt_gensalt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt OW_CRYPT_1.0:suse + + # Deprecated interfaces, POSIX and otherwise; also present in GNU libc + # since 2.0 + +From 022c86e681d2497ac02d88ac265d3c7c2d8b4ac5 Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Tue, 10 Jul 2018 15:38:15 +0000 +Subject: [PATCH 37/38] .travis.yml: add --enable-obsolete-api=glibc to the + test matrix + +--- + .travis.yml | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/.travis.yml b/.travis.yml +index 31c50fa..db45ded 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -118,6 +118,30 @@ matrix: + env: + - CONF="--enable-obsolete-api --enable-hashes=glibc" + - FCVER="latest" ++ - compiler: gcc ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api=glibc --enable-hashes=strong,glibc" ++ - FCVER="rawhide" ++ - compiler: clang ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api=glibc --enable-hashes=strong,glibc" ++ - FCVER="rawhide" ++ - compiler: gcc ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api=glibc --enable-hashes=strong,glibc" ++ - FCVER="latest" ++ - compiler: clang ++ os: linux ++ services: docker ++ env: ++ - CONF="--enable-obsolete-api=glibc --enable-hashes=strong,glibc" ++ - FCVER="latest" + + before_install: + - for i in `seq 0 99`; do docker pull fedora:$FCVER && i= && break || sleep 1; done; [ -z "$i" ] + +From 430212bcae4b9f31ed12bc52706b313da723c5cb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= +Date: Fri, 13 Jul 2018 12:21:32 +0200 +Subject: [PATCH 38/38] test-short-outbuf.c: Fix to build on 32 bit arches + +--- + test-short-outbuf.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/test-short-outbuf.c b/test-short-outbuf.c +index 7ab9d11..d928daa 100644 +--- a/test-short-outbuf.c ++++ b/test-short-outbuf.c +@@ -44,8 +44,8 @@ main (void) + ok = false; + } + +- printf ("Test %lu.0: %s, expected: \"%-2s\", got: \"%-2s\"\n", +- i + 1, result, testcases[i].exp_rn, *outbuf); ++ printf ("Test %u.0: %s, expected: \"%-2s\", got: \"%-2s\"\n", ++ (unsigned int)(i + 1), result, testcases[i].exp_rn, *outbuf); + + crypt_ra ("@@", "@@", (void **) outbuf, (int *) j); + +@@ -59,8 +59,8 @@ main (void) + ok = false; + } + +- printf ("Test %lu.1: %s, expected: \"%-2s\", got: \"%-2s\"\n", +- i + 1, result, testcases[i].exp_ra, *outbuf); ++ printf ("Test %u.1: %s, expected: \"%-2s\", got: \"%-2s\"\n", ++ (unsigned int)(i + 1), result, testcases[i].exp_ra, *outbuf); + + free (j); + free (*outbuf); diff --git a/libxcrypt-rh1592445.patch b/libxcrypt-rh1592445.patch deleted file mode 100644 index 2c50339..0000000 --- a/libxcrypt-rh1592445.patch +++ /dev/null @@ -1,668 +0,0 @@ -Remove SUNMD5 support due to potential incompatibility with the CDDL -license. According to - -https://lists.fedoraproject.org/archives/list/legal@lists.fedoraproject.org/message/KCDXNZJQ4S24NVB6OUPDGQA2VF53YZIT/ - -we do not have to repackage the source tarball, patching out the code -like this is sufficient. - -diff --git a/Makefile.am b/Makefile.am -index a7e726f9cb82a4b1..ca2b0accf886895d 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -115,7 +115,6 @@ check_PROGRAMS = \ - if ENABLE_WEAK_HASHES - libcrypt_la_SOURCES += \ - crypt-md5.c crypt-des.c crypt-nthash.c crypt-pbkdf1-sha1.c \ -- crypt-sunmd5.c \ - alg-des.c alg-hmac-sha1.c alg-md4.c alg-md5.c alg-sha1.c - - nodist_libcrypt_la_SOURCES = \ -@@ -146,7 +145,7 @@ check_PROGRAMS += \ - test-alg-des test-alg-hmac-sha1 test-alg-md4 \ - test-alg-md5 test-alg-sha1 \ - test-crypt-badsalt test-crypt-des test-crypt-md5 \ -- test-crypt-nthash test-crypt-sunmd5 test-crypt-pbkdf1-sha1 -+ test-crypt-nthash test-crypt-pbkdf1-sha1 - endif - - if ENABLE_OBSOLETE_API -@@ -187,7 +186,6 @@ test_crypt_nthash_LDADD = libcrypt.la - test_crypt_pbkdf1_sha1_LDADD = libcrypt.la - test_crypt_sha256_LDADD = libcrypt.la - test_crypt_sha512_LDADD = libcrypt.la --test_crypt_sunmd5_LDADD = libcrypt.la - test_gensalt_LDADD = libcrypt.la - test_des_obsolete_LDADD = libcrypt.la - test_des_obsolete_r_LDADD = libcrypt.la -diff --git a/crypt-port.h b/crypt-port.h -index 2b74ec9ef7252ba4..6331d56391a0b093 100644 ---- a/crypt-port.h -+++ b/crypt-port.h -@@ -219,7 +219,6 @@ void _xcrypt_secure_memset (void *s, size_t len) - #define crypt_md5_rn _crypt_crypt_md5_rn - #define crypt_nthash_rn _crypt_crypt_nthash_rn - #define crypt_sha1_rn _crypt_crypt_sha1_rn --#define crypt_sunmd5_rn _crypt_crypt_sunmd5_rn - #define des_crypt_block _crypt_des_crypt_block - #define des_set_key _crypt_des_set_key - #define des_set_salt _crypt_des_set_salt -@@ -230,7 +229,6 @@ void _xcrypt_secure_memset (void *s, size_t len) - #define gensalt_md5_rn _crypt_gensalt_md5_rn - #define gensalt_nthash_rn _crypt_gensalt_nthash_rn - #define gensalt_sha1_rn _crypt_gensalt_sha1_rn --#define gensalt_sunmd5_rn _crypt_gensalt_sunmd5_rn - #define ip_maskl _crypt_ip_maskl - #define ip_maskr _crypt_ip_maskr - #define key_perm_maskl _crypt_key_perm_maskl -diff --git a/crypt-private.h b/crypt-private.h -index 80a916d76181ed66..c595c0fc163b2639 100644 ---- a/crypt-private.h -+++ b/crypt-private.h -@@ -54,9 +54,6 @@ extern void crypt_nthash_rn (const char *phrase, const char *setting, - extern void crypt_sha1_rn (const char *phrase, const char *setting, - uint8_t *output, size_t o_size, - void *scratch, size_t s_size); --extern void crypt_sunmd5_rn (const char *phrase, const char *setting, -- uint8_t *output, size_t o_size, -- void *scratch, size_t s_size); - #endif - - extern void crypt_sha256_rn (const char *phrase, const char *setting, -@@ -85,9 +82,6 @@ extern void gensalt_nthash_rn (unsigned long count, - extern void gensalt_sha1_rn (unsigned long count, - const uint8_t *rbytes, size_t nrbytes, - uint8_t *output, size_t o_size); --extern void gensalt_sunmd5_rn (unsigned long count, -- const uint8_t *rbytes, size_t nrbytes, -- uint8_t *output, size_t o_size); - #endif - - extern void gensalt_sha256_rn (unsigned long count, -diff --git a/crypt-sunmd5.c b/crypt-sunmd5.c -deleted file mode 100644 -index 43054b96be357df3..0000000000000000 ---- a/crypt-sunmd5.c -+++ /dev/null -@@ -1,421 +0,0 @@ --/* -- * CDDL HEADER START -- * -- * The contents of this file are subject to the terms of the -- * Common Development and Distribution License, Version 1.0 only -- * (the "License"). You may not use this file except in compliance -- * with the License. -- * -- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -- * or http://www.opensolaris.org/os/licensing. -- * See the License for the specific language governing permissions -- * and limitations under the License. -- * -- * When distributing Covered Code, include this CDDL HEADER in each -- * file and include the License file at usr/src/OPENSOLARIS.LICENSE. -- * If applicable, add the following below this CDDL HEADER, with the -- * fields enclosed by brackets "[]" replaced with your own identifying -- * information: Portions Copyright [yyyy] [name of copyright owner] -- * -- * CDDL HEADER END -- */ --/* -- * Copyright 2003 Sun Microsystems, Inc. All rights reserved. -- * Use is subject to license terms. -- */ -- --#include "crypt-port.h" --#include "crypt-private.h" --#include "alg-md5.h" -- --#include --#include --#include -- --#define CRYPT_ALGNAME "md5" -- --/* minimum number of rounds we do, not including the per-user ones */ --#define BASIC_ROUND_COUNT 4096 /* enough to make things interesting */ --#define DIGEST_LEN 16 --#define ROUND_BUFFER_LEN 64 -- --/* -- * Public domain quotation courtesy of Project Gutenberg. -- * ftp://metalab.unc.edu/pub/docs/books/gutenberg/etext98/2ws2610.txt -- * Hamlet III.ii - 1517 bytes, including trailing NUL -- * ANSI-C string constant concatenation is a requirement here. -- */ --static const char constant_phrase[] = -- "To be, or not to be,--that is the question:--\n" -- "Whether 'tis nobler in the mind to suffer\n" -- "The slings and arrows of outrageous fortune\n" -- "Or to take arms against a sea of troubles,\n" -- "And by opposing end them?--To die,--to sleep,--\n" -- "No more; and by a sleep to say we end\n" -- "The heartache, and the thousand natural shocks\n" -- "That flesh is heir to,--'tis a consummation\n" -- "Devoutly to be wish'd. To die,--to sleep;--\n" -- "To sleep! perchance to dream:--ay, there's the rub;\n" -- "For in that sleep of death what dreams may come,\n" -- "When we have shuffled off this mortal coil,\n" -- "Must give us pause: there's the respect\n" -- "That makes calamity of so long life;\n" -- "For who would bear the whips and scorns of time,\n" -- "The oppressor's wrong, the proud man's contumely,\n" -- "The pangs of despis'd love, the law's delay,\n" -- "The insolence of office, and the spurns\n" -- "That patient merit of the unworthy takes,\n" -- "When he himself might his quietus make\n" -- "With a bare bodkin? who would these fardels bear,\n" -- "To grunt and sweat under a weary life,\n" -- "But that the dread of something after death,--\n" -- "The undiscover'd country, from whose bourn\n" -- "No traveller returns,--puzzles the will,\n" -- "And makes us rather bear those ills we have\n" -- "Than fly to others that we know not of?\n" -- "Thus conscience does make cowards of us all;\n" -- "And thus the native hue of resolution\n" -- "Is sicklied o'er with the pale cast of thought;\n" -- "And enterprises of great pith and moment,\n" -- "With this regard, their currents turn awry,\n" -- "And lose the name of action.--Soft you now!\n" -- "The fair Ophelia!--Nymph, in thy orisons\n" -- "Be all my sins remember'd.\n"; -- --/* ------------------------------------------------------------------ */ -- --static int --md5bit (uint8_t *digest, int bit_num) --{ -- int byte_off; -- int bit_off; -- -- bit_num %= 128; /* keep this bounded for convenience */ -- byte_off = bit_num / 8; -- bit_off = bit_num % 8; -- -- /* return the value of bit N from the digest */ -- return ((digest[byte_off] & (0x01 << bit_off)) ? 1 : 0); --} -- --/* 0 ... 63 => ascii - 64 */ --static unsigned char itoa64[] = -- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -- --static void --to64 (char *s, uint64_t v, int n) --{ -- while (--n >= 0) -- { -- *s++ = (char)itoa64[v&0x3f]; -- v >>= 6; -- } --} -- --#define ROUNDS "rounds=" --#define ROUNDSLEN (sizeof (ROUNDS) - 1) -- --/* -- * get the integer value after rounds= where ever it occurs in the string. -- * if the last char after the int is a , or $ that is fine anything else is an -- * error. -- */ --static uint32_t --getrounds (const char *s) --{ -- char *r, *p, *e; -- long val; -- -- if (s == NULL) -- return (0); -- -- if ((r = strstr (s, ROUNDS)) == NULL) -- return (0); -- -- if (strncmp (r, ROUNDS, ROUNDSLEN) != 0) -- return (0); -- -- p = r + ROUNDSLEN; -- errno = 0; -- val = strtol (p, &e, 10); -- /* -- * An error occured or there is non-numeric stuff at the end -- * which isn't one of the crypt(3c) special chars ',' or '$' -- */ -- if (errno != 0 || val < 0 || -- !(*e == '\0' || *e == ',' || *e == '$')) -- { -- return (0); -- } -- -- return ((uint32_t)val); --} -- --void --gensalt_sunmd5_rn (unsigned long count, -- const uint8_t *rbytes, size_t nrbytes, -- uint8_t *output, size_t o_size) --{ -- /* This should not happen, but. */ -- if ((nrbytes < sizeof (uint64_t)) || (o_size < 33)) -- { -- errno = ERANGE; -- return; -- } -- -- uint64_t rndval; -- char rndstr[sizeof (rndval) + 1]; /* rndval as a base64 string */ -- const uint8_t minrounds = 15; /* Min. number of rounds = 2^X */ -- -- /* Set count to a reasonable random value, -- if count was not set high enough by the -- caller. */ -- if (count < (unsigned long)(1 << minrounds)) -- { -- uint64_t rand1, rand2; -- get_random_bytes(&rand1, sizeof (uint64_t)); -- get_random_bytes(&rand2, sizeof (uint64_t)); -- count = (long unsigned int)(1 << ((rand1 % 2) + minrounds)); -- count += (long unsigned int)(rand2 % (uint64_t)((1 << (minrounds - 1)) + 1)); -- } -- -- memcpy (&rndval, rbytes, sizeof (rndval)); -- to64 ((char *)&rndstr, rndval, sizeof (rndval)); -- rndstr[sizeof (rndstr) - 1] = '\0'; -- -- /* Generated salt is at least 27 bytes -- and a maximum of 32 bytes long. */ -- snprintf ((char *)output, o_size, -- "$" CRYPT_ALGNAME "," ROUNDS "%u$%s$", -- (unsigned int)count, rndstr); --} -- --void --crypt_sunmd5_rn (const char *phrase, const char *setting, -- uint8_t *output, size_t o_size, -- void *scratch, size_t s_size) --{ -- /* put all the sensitive data in a struct */ -- struct sunmd5_ctx -- { -- struct md5_ctx context; /* working buffer for MD5 algorithm */ -- uint8_t digest[DIGEST_LEN]; /* where the MD5 digest is stored */ -- -- int indirect_4[16]; /* extracted array of 4bit values */ -- int shift_4[16]; /* shift schedule, vals 0..4 */ -- -- int s7shift; /* shift for shift_7 creation, vals 0..7 */ -- int indirect_7[16]; /* extracted array of 7bit values */ -- int shift_7[16]; /* shift schedule, vals 0..1 */ -- -- int indirect_a; /* 7bit index into digest */ -- int shift_a; /* shift schedule, vals 0..1 */ -- -- int indirect_b; /* 7bit index into digest */ -- int shift_b; /* shift schedule, vals 0..1 */ -- -- int bit_a; /* single bit for cointoss */ -- int bit_b; /* single bit for cointoss */ -- -- char roundascii[ROUND_BUFFER_LEN]; /* ascii rep of roundcount */ -- }; -- -- /* Scratch space needs to be large enough -- to fit struct sunmd5_ctx. Output must -- be able to fit up to 32 bytes for the -- setting + '$' + 22 bytes of hash. */ -- if (s_size < sizeof (struct sunmd5_ctx) || (o_size < 32 + 1 + 22)) -- { -- errno = ERANGE; -- return; -- } -- -- /* If the magic does not match, this -- should not have been called. */ -- if (!strncmp ("$" CRYPT_ALGNAME, setting, sizeof ("$" CRYPT_ALGNAME))) -- { -- errno = EINVAL; -- return; -- } -- -- int i; -- int round; -- uint32_t maxrounds = BASIC_ROUND_COUNT; -- uint32_t l; -- char *puresalt; -- char *saltend; -- char *p; -- struct sunmd5_ctx *data = scratch; -- -- /* -- * Extract the puresalt (if it exists) from the existing salt string -- * $md5[,rounds=%d]$$ -- */ -- saltend = strrchr (setting, '$'); -- -- if (saltend == NULL || saltend == setting) -- { -- errno = EINVAL; -- return; -- } -- -- if (saltend[1] != '\0') -- { -- size_t len = (size_t)(saltend - setting + 1); -- -- if ((puresalt = malloc (len)) == NULL) -- /* malloc() is supposed to set errno == ENOMEM. */ -- return; -- -- /* The original implementation used strlcpy(), -- which is not portable. Since strlcpy() -- always terminated a C string properly after -- copying len - 1 bytes of data, we need to -- do that manually. */ -- (void)strncpy (puresalt, setting, len); -- puresalt[len - 1] = '\0'; -- } -- else -- { -- puresalt = strdup(setting); -- -- if (puresalt == NULL) -- { -- /* strdup() is supposed to set errno == ENOMEM. */ -- return; -- } -- } -- -- /* There must not be any dollar sign '$', but -- the last character before the terminating -- '\0' in the string containing the salt. */ -- if (puresalt[strlen (puresalt) - 2] == '$') -- { -- errno = EINVAL; -- return; -- } -- -- maxrounds += getrounds (setting); -- -- /* initialise the context */ -- md5_init_ctx (&(data->context)); -- -- /* update with the (hopefully entropic) plaintext */ -- md5_process_bytes ((const unsigned char *)phrase, strlen (phrase), &(data->context)); -- -- /* update with the (publically known) salt */ -- md5_process_bytes ((unsigned char *)puresalt, strlen (puresalt), &(data->context)); -- -- -- /* compute the digest */ -- md5_finish_ctx (&(data->context), &(data->digest)); -- -- /* -- * now to delay high-speed md5 implementations that have stuff -- * like code inlining, loops unrolled and table lookup -- */ -- -- for (round = 0; (uint32_t)round < maxrounds; round++) -- { -- /* re-initialise the context */ -- md5_init_ctx (&(data->context)); -- -- /* update with the previous digest */ -- md5_process_bytes (&(data->digest), sizeof (data->digest), &(data->context)); -- -- /* populate the shift schedules for use later */ -- for (i = 0; i < 16; i++) -- { -- int j; -- -- /* offset 3 -> occasionally span more than 1 int32 fetch */ -- j = (i + 3) % 16; -- data->s7shift = data->digest[i] % 8; -- data->shift_4[i] = data->digest[j] % 5; -- data->shift_7[i] = (data->digest[j] >> data->s7shift) & 0x01; -- } -- -- data->shift_a = md5bit (data->digest, round); -- data->shift_b = md5bit (data->digest, round + 64); -- -- /* populate indirect_4 with 4bit values extracted from digest */ -- for (i = 0; i < 16; i++) -- /* shift the digest byte and extract four bits */ -- data->indirect_4[i] = (data->digest[i] >> data->shift_4[i]) & 0x0f; -- -- /* -- * populate indirect_7 with 7bit values from digest -- * indexed via indirect_4 -- */ -- -- for (i = 0; i < 16; i++) -- /* shift the digest byte and extract seven bits */ -- data->indirect_7[i] = (data->digest[data->indirect_4[i]] -- >> data->shift_7[i]) & 0x7f; -- -- /* -- * use the 7bit values to indirect into digest, -- * and create two 8bit values from the results. -- */ -- data->indirect_a = data->indirect_b = 0; -- -- for (i = 0; i < 8; i++) -- { -- data->indirect_a |= (md5bit (data->digest, -- data->indirect_7[i]) << i); -- -- data->indirect_b |= (md5bit (data->digest, -- data->indirect_7[i + 8]) << i); -- } -- -- /* shall we utilise the top or bottom 7 bits? */ -- data->indirect_a = (data->indirect_a >> data->shift_a) & 0x7f; -- data->indirect_b = (data->indirect_b >> data->shift_b) & 0x7f; -- -- /* extract two data->digest bits */ -- data->bit_a = md5bit (data->digest, data->indirect_a); -- data->bit_b = md5bit (data->digest, data->indirect_b); -- -- /* xor a coin-toss; if true, mix-in the constant phrase */ -- -- if (data->bit_a ^ data->bit_b) -- md5_process_bytes ((const unsigned char *) constant_phrase, -- sizeof (constant_phrase), -- &(data->context)); -- -- /* digest a decimal sprintf of the current roundcount */ -- snprintf (data->roundascii, ROUND_BUFFER_LEN, "%d", round); -- md5_process_bytes ((unsigned char *) data->roundascii, -- strlen (data->roundascii), -- &(data->context)); -- -- /* compute/flush the digest, and loop */ -- md5_finish_ctx (&(data->context), &(data->digest)); -- } -- -- (void)snprintf ((char *)output, o_size, "%s$", puresalt); -- -- free (puresalt); -- -- p = (char *)output + strlen ((const char *)output); -- -- l = (uint32_t)((data->digest[ 0]<<16) | (data->digest[ 6]<<8) | data->digest[12]); -- to64 (p, l, 4); -- p += 4; -- l = (uint32_t)((data->digest[ 1]<<16) | (data->digest[ 7]<<8) | data->digest[13]); -- to64 (p, l, 4); -- p += 4; -- l = (uint32_t)((data->digest[ 2]<<16) | (data->digest[ 8]<<8) | data->digest[14]); -- to64 (p, l, 4); -- p += 4; -- l = (uint32_t)((data->digest[ 3]<<16) | (data->digest[ 9]<<8) | data->digest[15]); -- to64 (p, l, 4); -- p += 4; -- l = (uint32_t)((data->digest[ 4]<<16) | (data->digest[10]<<8) | data->digest[ 5]); -- to64 (p, l, 4); -- p += 4; -- l = (uint32_t)data->digest[11]; -- to64 (p, l, 2); -- p += 2; -- *p = '\0'; --} -diff --git a/crypt.c b/crypt.c -index d7f0ffcdd10ee0fa..8437d96834824d45 100644 ---- a/crypt.c -+++ b/crypt.c -@@ -88,7 +88,6 @@ static const struct hashfn tagged_hashes[] = - #if ENABLE_WEAK_HASHES - { "$1$", crypt_md5_rn, gensalt_md5_rn }, - { "$3$", crypt_nthash_rn, gensalt_nthash_rn }, -- { "$md5", crypt_sunmd5_rn, gensalt_sunmd5_rn }, - { "$sha1", crypt_sha1_rn, gensalt_sha1_rn }, - #endif - { "$5$", crypt_sha256_rn, gensalt_sha256_rn }, -diff --git a/test-crypt-sunmd5.c b/test-crypt-sunmd5.c -deleted file mode 100644 -index d4fc0dc9a3716381..0000000000000000 ---- a/test-crypt-sunmd5.c -+++ /dev/null -@@ -1,130 +0,0 @@ --#include "crypt-port.h" --#include "crypt-base.h" -- --#include --#include -- --const char *password = "abcdefg"; --const char *tests[][3] = --{ -- /* Hashes have been computed with the following program: -- -- #!/usr/bin/python -- -- from passlib.hash import sun_md5_crypt -- import csv -- -- with open('sunmd5.txt') as csvfile: -- params = csv.reader(csvfile) -- for row in params: -- print(sun_md5_crypt.using(rounds=int(row[0]), -- salt=row[1]).hash("abcdefg")) -- -- The used csv file had the following format: -- -- , (when no rounds parameter was given, -- rounds were set to zero.) -- -- The salts have been generated by crypt_gensalt on OpenSolaris. -- -- -- Test X.0: checks the password is encryptable with the full hash -- as setting. -- Test X.1: checks the password is encryptable with the initially -- used salt as setting. -- Test X.0: checks for the bug in Sun's original implementation -- is present. -- See: http://passlib.readthedocs.io/en/stable/lib/passlib.hash.sun_md5_crypt.html#smc-bare-salt -- */ -- { -- "$md5,rounds=5619$9ZLwtuT0$$mLoRQuWY/qcxCRWhD1C2M.", -- "$md5,rounds=5619$9ZLwtuT0$", -- "$md5,rounds=5619$9ZLwtuT0$mLoRQuWY/qcxCRWhD1C2M." -- }, -- { -- "$md5,rounds=963$er0EceI7$$SdWKu/EgaVvya0m3T4Ml61", -- "$md5,rounds=963$er0EceI7$", -- "$md5,rounds=963$er0EceI7$SdWKu/EgaVvya0m3T4Ml61" -- }, -- { -- "$md5$1xMeE.at$$qRpVD46c.sEWM/48tNk191", -- "$md5$1xMeE.at$", -- "$md5$1xMeE.at$qRpVD46c.sEWM/48tNk191" -- }, -- { -- "$md5,rounds=9748$2kkhnoZI$$HzOCKmX2sus/1S9CmohBY/", -- "$md5,rounds=9748$2kkhnoZI$", -- "$md5,rounds=9748$2kkhnoZI$HzOCKmX2sus/1S9CmohBY/" -- }, -- { -- "$md5$9ZLwtuT0$$ZRfjIfcFjDekvFzC6wCa2/", -- "$md5$9ZLwtuT0$", -- "$md5$9ZLwtuT0$ZRfjIfcFjDekvFzC6wCa2/" -- }, -- { -- "$md5,rounds=5619$9ZLwtuT0$5.D2mO0RKrZtrrBh3fduf.", -- "$md5,rounds=5619$9ZLwtuT0$x", -- "$md5,rounds=5619$9ZLwtuT0$$5.D2mO0RKrZtrrBh3fduf." -- }, -- { -- "$md5,rounds=963$er0EceI7$Pt3h1M5TiSImJ4jk663aR/", -- "$md5,rounds=963$er0EceI7$x", -- "$md5,rounds=963$er0EceI7$$Pt3h1M5TiSImJ4jk663aR/" -- }, -- { -- "$md5$1xMeE.at$I566aJ9IitIdjKKjZJ8Zo0", -- "$md5$1xMeE.at$x", -- "$md5$1xMeE.at$$I566aJ9IitIdjKKjZJ8Zo0" -- }, -- { -- "$md5,rounds=9748$2kkhnoZI$suo2yEVmCZnnnz6ZZHYit0", -- "$md5,rounds=9748$2kkhnoZI$x", -- "$md5,rounds=9748$2kkhnoZI$$suo2yEVmCZnnnz6ZZHYit0" -- }, -- { -- "$md5$9ZLwtuT0$UvTt17ajkoa7kwpCrtMeb1", -- "$md5$9ZLwtuT0$x", -- "$md5$9ZLwtuT0$$UvTt17ajkoa7kwpCrtMeb1" -- }, --}; -- --#define ntests (sizeof (tests) / sizeof (tests[0])) -- --int --main (void) --{ -- struct crypt_data output; -- int result = 0; -- unsigned int i, j; -- char *previous = malloc (sizeof (output.output) + 1); -- -- for (i = 0; i < ntests; ++i) -- { -- for (j = 0; j < 3; ++j) -- { -- char *cp = crypt_r (password, tests[i][j], &output); -- if ((j == 0) && (strcmp (cp, tests[i][j]) != 0)) -- { -- printf ("test %u.%u: expected \"%s\", got \"%s\"\n", -- i, j, tests[i][j], cp); -- result = 1; -- } -- if ((j == 1) && (strcmp (cp, previous) != 0)) -- { -- printf ("test %u.%u: expected \"%s\", got \"%s\"\n", -- i, j, previous, cp); -- result = 1; -- } -- if ((j == 2) && (strcmp (cp, tests[i][j]) == 0)) -- { -- printf ("test %u.%u: \"%s\" was not different from returned hash.\n", -- i, j, tests[i][j]); -- result = 1; -- } -- strcpy (previous, tests[i][j]); -- } -- } -- -- free (previous); -- return result; --} -diff --git a/test-gensalt.c b/test-gensalt.c -index dfe194c69b732ee8..e02eb284c72fb514 100644 ---- a/test-gensalt.c -+++ b/test-gensalt.c -@@ -27,7 +27,6 @@ static const struct testcase testcases[] = - { "_", 9 }, // BSDi extended DES - { "$1$", 11 }, // MD5 - { "$3$", 29 }, // NTHASH -- { "$md5", 27 }, // SUNMD5 - { "$sha1", 34 }, // PBKDF with SHA1 - #endif - { "$5$", 19 }, // SHA-2-256 diff --git a/libxcrypt.spec b/libxcrypt.spec index 5ee707f..8b48d9f 100644 --- a/libxcrypt.spec +++ b/libxcrypt.spec @@ -19,7 +19,7 @@ Name: libxcrypt Version: 4.0.1 -Release: 4%{?dist} +Release: 5%{?dist} Summary: Extended crypt library for DES, MD5, Blowfish and others # For explicit license breakdown, see the @@ -27,7 +27,8 @@ Summary: Extended crypt library for DES, MD5, Blowfish and others License: LGPLv2+ and BSD and Public Domain URL: https://github.com/besser82/%{name} Source0: %{url}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz -Patch1: libxcrypt-rh1592445.patch + +Patch1: %{url}/compare/v4.0.1...develop.patch#/%{name}-4.0.1_to_develop.patch BuildRequires: fipscheck BuildRequires: libtool @@ -111,13 +112,13 @@ is highly discouraged. %build -%configure \ - --libdir=/%{_lib} \ - --disable-silent-rules \ - --enable-shared \ - --enable-static \ - --enable-obsolete-api \ - --enable-weak-hashes \ +%configure \ + --libdir=/%{_lib} \ + --disable-silent-rules \ + --enable-shared \ + --enable-static \ + --enable-hashes=all \ + --enable-obsolete-api=glibc \ --with-pkgconfigdir=%{_libdir}/pkgconfig %make_build @@ -128,11 +129,6 @@ is highly discouraged. # Get rid of libtool crap. %{_bindir}/find %{buildroot} -name '*.la' -print -delete -# We do not need libowcrypt.*, since it is a SUSE -# compat thing. Software needing it to be build can -# be patched easily to just link against '-lcrypt'. -%{_bindir}/find %{buildroot} -name 'libow*' -print -delete - # Install documentation to shared %%_pkgdocdir. %{__install} -Dpm 0644 -t %{buildroot}%{_pkgdocdir} \ ChangeLog NEWS README THANKS TODO @@ -172,6 +168,7 @@ is highly discouraged. %doc %{_pkgdocdir}/TODO /%{_lib}/libcrypt.so %{_includedir}/crypt.h +%{_libdir}/pkgconfig/libcrypt.pc %{_libdir}/pkgconfig/%{name}.pc @@ -180,6 +177,11 @@ is highly discouraged. %changelog +* Fri Jul 13 2018 Björn Esser - 4.0.1-5 +- Add patch to update to recent development branch +- Re-enable SUNMD5 support as it is BSD licensed now +- Build compatibility symbols for glibc only + * Fri Jul 13 2018 Fedora Release Engineering - 4.0.1-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild