libxcrypt/libxcrypt-4.1.1_to_master.patch

2809 lines
103 KiB
Diff
Raw Normal View History

From 0e5a38cde2ede896e4dca6d85f133d9e23ec72cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Wed, 1 Aug 2018 11:51:23 +0200
Subject: [PATCH 01/10] Bump tarball version to 4.1.2 and update NEWS.
---
NEWS | 2 ++
configure.ac | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index 0288c44..40effdc 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ libxcrypt NEWS -- history of user-visible changes.
Please send bug reports, questions and suggestions to
<https://github.com/besser82/libxcrypt/issues>.
+Version 4.1.2
+
Version 4.1.1
* --enable-hashes now supports additional groups of hashing methods:
'freebsd', 'netbsd', 'openbsd', 'osx', and 'solaris', which select
diff --git a/configure.ac b/configure.ac
index a22a592..8940e2d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script.
m4_include([m4/zw_automodern.m4])
AC_INIT([xcrypt],
- [4.1.1],
+ [4.1.2],
[https://github.com/besser82/libxcrypt/issues],
[libxcrypt],
[https://github.com/besser82/libxcrypt])
From 7281ceb60e404e8734784670490aaf7d95ffb970 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Thu, 2 Aug 2018 09:44:07 +0200
Subject: [PATCH 02/10] Use valgrind memcheck if available to test for memory
leaks.
---
.travis.yml | 5 +-
Makefile.am | 11 +-
NEWS | 1 +
configure.ac | 13 +-
m4/ax_valgrind_check.m4 | 239 ++++++++++++++++++
test-symbols-compat => test-symbols-compat.sh | 0
...symbols-renames => test-symbols-renames.sh | 0
test-symbols-static => test-symbols-static.sh | 0
8 files changed, 261 insertions(+), 8 deletions(-)
create mode 100644 m4/ax_valgrind_check.m4
rename test-symbols-compat => test-symbols-compat.sh (100%)
rename test-symbols-renames => test-symbols-renames.sh (100%)
rename test-symbols-static => test-symbols-static.sh (100%)
diff --git a/.travis.yml b/.travis.yml
index db45ded..1f8e224 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -155,7 +155,7 @@ before_install:
- 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" ]'
+ - docker exec -t buildenv /bin/sh -c 'for i in `seq 0 99`; do dnf -y install libtool valgrind && 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
@@ -178,6 +178,7 @@ script:
- docker exec -t buildenv /bin/sh -c "make -C /opt/libxcrypt -j$((`nproc --all` * 2))"
- docker exec -t buildenv /bin/sh -c "make -C /opt/libxcrypt install"
- docker exec -t buildenv /bin/sh -c "(make -C /opt/libxcrypt -j$((`nproc --all` * 2)) check || (cat /opt/libxcrypt/test-suite.log && exit 1))"
+ - docker exec -t buildenv /bin/sh -c "(make -C /opt/libxcrypt -j$((`nproc --all` * 2)) check-valgrind-memcheck || (cat /opt/libxcrypt/test-suite-memcheck.log && exit 1))"
after_success:
- - 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
+ - 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 all_coverage.info && codecov -X gcov" ; fi
diff --git a/Makefile.am b/Makefile.am
index 201dea5..874db12 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,6 +9,9 @@ ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = $(WARN_CFLAGS)
+@VALGRIND_CHECK_RULES@
+TEST_EXTENSIONS = .sh
+
EXTRA_DIST = \
LICENSING THANKS \
libcrypt.map.in libcrypt.minver \
@@ -158,15 +161,15 @@ endif
TESTS = $(check_PROGRAMS)
if ENABLE_STATIC
-TESTS += test-symbols-static
+TESTS += test-symbols-static.sh
if HAVE_CPP_dD
-TESTS += test-symbols-renames
+TESTS += test-symbols-renames.sh
endif
endif
if ENABLE_OBSOLETE_API
-TESTS += test-symbols-compat
+TESTS += test-symbols-compat.sh
endif
-EXTRA_DIST += test-symbols-static test-symbols-compat test-symbols-renames
+EXTRA_DIST += test-symbols-static.sh test-symbols-compat.sh test-symbols-renames.sh
AM_TESTS_ENVIRONMENT = \
lib_la="./libcrypt.la"; lib_map="$(srcdir)/libcrypt.map.in"; \
diff --git a/NEWS b/NEWS
index 40effdc..77b556f 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Please send bug reports, questions and suggestions to
<https://github.com/besser82/libxcrypt/issues>.
Version 4.1.2
+* Add optional 'check-valgrind' target to the Makefile.
Version 4.1.1
* --enable-hashes now supports additional groups of hashing methods:
diff --git a/configure.ac b/configure.ac
index 8940e2d..9ea30f6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,7 +51,6 @@ AC_C_BIGENDIAN(
AC_DEFINE([IS_BIGENDIAN], 0,
[Define to 0 if system's architecture is little-endian.])
)
-
# One of the test scripts needs to use -dD.
AC_CACHE_CHECK([whether the preprocessor ($CPP) supports -dD],
[ac_cv_prog_cc_dD],
@@ -151,8 +150,18 @@ AC_CHECK_FUNCS_ONCE([
syscall
])
-# Configure options.
+# Disable valgrind tools for checking multithreaded
+# programs, as we don't use them in checks.
+AX_VALGRIND_DFLT([drd], [off])
+AX_VALGRIND_DFLT([helgrind], [off])
+
+# Valgrind's sgcheck is b0rk3n upstream.
+AX_VALGRIND_DFLT([sgcheck], [off])
+# Add a target to run testsuite with valgrind.
+AX_VALGRIND_CHECK()
+
+# Configure options.
AC_ARG_ENABLE([obsolete-api],
AS_HELP_STRING(
[--enable-obsolete-api[=ARG]],
diff --git a/m4/ax_valgrind_check.m4 b/m4/ax_valgrind_check.m4
new file mode 100644
index 0000000..7033798
--- /dev/null
+++ b/m4/ax_valgrind_check.m4
@@ -0,0 +1,239 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_VALGRIND_DFLT(memcheck|helgrind|drd|sgcheck, on|off)
+# AX_VALGRIND_CHECK()
+#
+# DESCRIPTION
+#
+# AX_VALGRIND_CHECK checks whether Valgrind is present and, if so, allows
+# running `make check` under a variety of Valgrind tools to check for
+# memory and threading errors.
+#
+# Defines VALGRIND_CHECK_RULES which should be substituted in your
+# Makefile; and $enable_valgrind which can be used in subsequent configure
+# output. VALGRIND_ENABLED is defined and substituted, and corresponds to
+# the value of the --enable-valgrind option, which defaults to being
+# enabled if Valgrind is installed and disabled otherwise. Individual
+# Valgrind tools can be disabled via --disable-valgrind-<tool>, the
+# default is configurable via the AX_VALGRIND_DFLT command or is to use
+# all commands not disabled via AX_VALGRIND_DFLT. All AX_VALGRIND_DFLT
+# calls must be made before the call to AX_VALGRIND_CHECK.
+#
+# If unit tests are written using a shell script and automake's
+# LOG_COMPILER system, the $(VALGRIND) variable can be used within the
+# shell scripts to enable Valgrind, as described here:
+#
+# https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html
+#
+# Usage example:
+#
+# configure.ac:
+#
+# AX_VALGRIND_DFLT([sgcheck], [off])
+# AX_VALGRIND_CHECK
+#
+# in each Makefile.am with tests:
+#
+# @VALGRIND_CHECK_RULES@
+# VALGRIND_SUPPRESSIONS_FILES = my-project.supp
+# EXTRA_DIST = my-project.supp
+#
+# This results in a "check-valgrind" rule being added. Running `make
+# check-valgrind` in that directory will recursively run the module's test
+# suite (`make check`) once for each of the available Valgrind tools (out
+# of memcheck, helgrind and drd) while the sgcheck will be skipped unless
+# enabled again on the commandline with --enable-valgrind-sgcheck. The
+# results for each check will be output to test-suite-$toolname.log. The
+# target will succeed if there are zero errors and fail otherwise.
+#
+# Alternatively, a "check-valgrind-$TOOL" rule will be added, for $TOOL in
+# memcheck, helgrind, drd and sgcheck. These are useful because often only
+# some of those tools can be ran cleanly on a codebase.
+#
+# The macro supports running with and without libtool.
+#
+# LICENSE
+#
+# Copyright (c) 2014, 2015, 2016 Philip Withnall <philip.withnall@collabora.co.uk>
+#
+# 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 17
+
+dnl Configured tools
+m4_define([valgrind_tool_list], [[memcheck], [helgrind], [drd], [sgcheck]])
+m4_set_add_all([valgrind_exp_tool_set], [sgcheck])
+m4_foreach([vgtool], [valgrind_tool_list],
+ [m4_define([en_dflt_valgrind_]vgtool, [on])])
+
+AC_DEFUN([AX_VALGRIND_DFLT],[
+ m4_define([en_dflt_valgrind_$1], [$2])
+])dnl
+
+AM_EXTRA_RECURSIVE_TARGETS([check-valgrind])
+m4_foreach([vgtool], [valgrind_tool_list],
+ [AM_EXTRA_RECURSIVE_TARGETS([check-valgrind-]vgtool)])
+
+AC_DEFUN([AX_VALGRIND_CHECK],[
+ dnl Check for --enable-valgrind
+ AC_ARG_ENABLE([valgrind],
+ [AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])],
+ [enable_valgrind=$enableval],[enable_valgrind=])
+
+ AS_IF([test "$enable_valgrind" != "no"],[
+ # Check for Valgrind.
+ AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind])
+ AS_IF([test "$VALGRIND" = ""],[
+ AS_IF([test "$enable_valgrind" = "yes"],[
+ AC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind])
+ ],[
+ enable_valgrind=no
+ ])
+ ],[
+ enable_valgrind=yes
+ ])
+ ])
+
+ AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
+ AC_SUBST([VALGRIND_ENABLED],[$enable_valgrind])
+
+ # Check for Valgrind tools we care about.
+ [valgrind_enabled_tools=]
+ m4_foreach([vgtool],[valgrind_tool_list],[
+ AC_ARG_ENABLE([valgrind-]vgtool,
+ m4_if(m4_defn([en_dflt_valgrind_]vgtool),[off],dnl
+[AS_HELP_STRING([--enable-valgrind-]vgtool, [Whether to use ]vgtool[ during the Valgrind tests])],dnl
+[AS_HELP_STRING([--disable-valgrind-]vgtool, [Whether to skip ]vgtool[ during the Valgrind tests])]),
+ [enable_valgrind_]vgtool[=$enableval],
+ [enable_valgrind_]vgtool[=])
+ AS_IF([test "$enable_valgrind" = "no"],[
+ enable_valgrind_]vgtool[=no],
+ [test "$enable_valgrind_]vgtool[" ]dnl
+m4_if(m4_defn([en_dflt_valgrind_]vgtool), [off], [= "yes"], [!= "no"]),[
+ AC_CACHE_CHECK([for Valgrind tool ]vgtool,
+ [ax_cv_valgrind_tool_]vgtool,[
+ ax_cv_valgrind_tool_]vgtool[=no
+ m4_set_contains([valgrind_exp_tool_set],vgtool,
+ [m4_define([vgtoolx],[exp-]vgtool)],
+ [m4_define([vgtoolx],vgtool)])
+ AS_IF([`$VALGRIND --tool=]vgtoolx[ --help >/dev/null 2>&1`],[
+ ax_cv_valgrind_tool_]vgtool[=yes
+ ])
+ ])
+ AS_IF([test "$ax_cv_valgrind_tool_]vgtool[" = "no"],[
+ AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
+ AC_MSG_ERROR([Valgrind does not support ]vgtool[; reconfigure with --disable-valgrind-]vgtool)
+ ],[
+ enable_valgrind_]vgtool[=no
+ ])
+ ],[
+ enable_valgrind_]vgtool[=yes
+ ])
+ ])
+ AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
+ valgrind_enabled_tools="$valgrind_enabled_tools ]m4_bpatsubst(vgtool,[^exp-])["
+ ])
+ AC_SUBST([ENABLE_VALGRIND_]vgtool,[$enable_valgrind_]vgtool)
+ ])
+ AC_SUBST([valgrind_tools],["]m4_join([ ], valgrind_tool_list)["])
+ AC_SUBST([valgrind_enabled_tools],[$valgrind_enabled_tools])
+
+[VALGRIND_CHECK_RULES='
+# Valgrind check
+#
+# Optional:
+# - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions
+# files to load. (Default: empty)
+# - VALGRIND_FLAGS: General flags to pass to all Valgrind tools.
+# (Default: --num-callers=30)
+# - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of:
+# memcheck, helgrind, drd, sgcheck). (Default: various)
+
+# Optional variables
+VALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES))
+VALGRIND_FLAGS ?= --num-callers=30
+VALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no
+VALGRIND_helgrind_FLAGS ?= --history-level=approx
+VALGRIND_drd_FLAGS ?=
+VALGRIND_sgcheck_FLAGS ?=
+
+# Internal use
+valgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools)))
+
+valgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS)
+valgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS)
+valgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS)
+valgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS)
+
+valgrind_quiet = $(valgrind_quiet_$(V))
+valgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY))
+valgrind_quiet_0 = --quiet
+valgrind_v_use = $(valgrind_v_use_$(V))
+valgrind_v_use_ = $(valgrind_v_use_$(AM_DEFAULT_VERBOSITY))
+valgrind_v_use_0 = @echo " USE " $(patsubst check-valgrind-%-am,%,$''@):;
+
+# Support running with and without libtool.
+ifneq ($(LIBTOOL),)
+valgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute
+else
+valgrind_lt =
+endif
+
+# Use recursive makes in order to ignore errors during check
+check-valgrind-am:
+ifeq ($(VALGRIND_ENABLED),yes)
+ $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k \
+ $(foreach tool, $(valgrind_enabled_tools), check-valgrind-$(tool))
+else
+ @echo "Need to reconfigure with --enable-valgrind"
+endif
+
+# Valgrind running
+VALGRIND_TESTS_ENVIRONMENT = \
+ $(TESTS_ENVIRONMENT) \
+ env VALGRIND=$(VALGRIND) \
+ G_SLICE=always-malloc,debug-blocks \
+ G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly
+
+VALGRIND_LOG_COMPILER = \
+ $(valgrind_lt) \
+ $(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS)
+
+define valgrind_tool_rule
+check-valgrind-$(1)-am:
+ifeq ($$(VALGRIND_ENABLED)-$$(ENABLE_VALGRIND_$(1)),yes-yes)
+ifneq ($$(TESTS),)
+ $$(valgrind_v_use)$$(MAKE) check-TESTS \
+ TESTS_ENVIRONMENT="$$(VALGRIND_TESTS_ENVIRONMENT)" \
+ LOG_COMPILER="$$(VALGRIND_LOG_COMPILER)" \
+ LOG_FLAGS="$$(valgrind_$(1)_flags)" \
+ TEST_SUITE_LOG=test-suite-$(1).log
+endif
+else ifeq ($$(VALGRIND_ENABLED),yes)
+ @echo "Need to reconfigure with --enable-valgrind-$(1)"
+else
+ @echo "Need to reconfigure with --enable-valgrind"
+endif
+endef
+
+$(foreach tool,$(valgrind_tools),$(eval $(call valgrind_tool_rule,$(tool))))
+
+A''M_DISTCHECK_CONFIGURE_FLAGS ?=
+A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind
+
+MOSTLYCLEANFILES ?=
+MOSTLYCLEANFILES += $(valgrind_log_files)
+
+.PHONY: check-valgrind $(add-prefix check-valgrind-,$(valgrind_tools))
+']
+
+ AC_SUBST([VALGRIND_CHECK_RULES])
+ m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])])
+])
diff --git a/test-symbols-compat b/test-symbols-compat.sh
similarity index 100%
rename from test-symbols-compat
rename to test-symbols-compat.sh
diff --git a/test-symbols-renames b/test-symbols-renames.sh
similarity index 100%
rename from test-symbols-renames
rename to test-symbols-renames.sh
diff --git a/test-symbols-static b/test-symbols-static.sh
similarity index 100%
rename from test-symbols-static
rename to test-symbols-static.sh
From 307c223a0f8c7b52678bf3fed59685932ec57c18 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 14 Jul 2018 20:36:30 +0200
Subject: [PATCH 03/10] Replace crypt-sha256.c with an implementation in the
Public Domain.
This implementation is based on the SHA256-based Unix crypt
implementation. Released into the Public Domain [1] by
Ulrich Drepper <drepper@redhat.com>.
This file is a modified except from [2], lines 648 up to 909.
[1] https://www.akkadia.org/drepper/sha-crypt.html
[2] https://www.akkadia.org/drepper/SHA-crypt.txt
---
crypt-sha256.c | 351 +++++++++++++++++++++++++------------------------
1 file changed, 176 insertions(+), 175 deletions(-)
diff --git a/crypt-sha256.c b/crypt-sha256.c
index e8d3808..c2954a4 100644
--- a/crypt-sha256.c
+++ b/crypt-sha256.c
@@ -1,20 +1,17 @@
-/* One way encryption based on SHA256 sum.
-
- Copyright (C) 2007-2017 Free Software Foundation, Inc.
-
- 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
- <https://www.gnu.org/licenses/>. */
+/* One way encryption based on the SHA256-based Unix crypt implementation.
+ *
+ * Written by Ulrich Drepper <drepper at redhat.com> in 2007 [1].
+ * To the extent possible under law, Ulrich Drepper has waived all
+ * copyright and related or neighboring rights to this work.
+ *
+ * See https://creativecommons.org/publicdomain/zero/1.0/ for further
+ * details.
+ *
+ * This file is an except from [2], lines 648 up to 909.
+ *
+ * [1] https://www.akkadia.org/drepper/sha-crypt.html
+ * [2] https://www.akkadia.org/drepper/SHA-crypt.txt
+ */
#include "crypt-port.h"
#include "crypt-private.h"
@@ -42,35 +39,8 @@ static const char sha256_rounds_prefix[] = "rounds=";
/* Maximum number of rounds. */
#define ROUNDS_MAX 999999999
-/* The maximum possible length of a SHA256-hashed password string,
- including the terminating NUL character. Prefix (including its NUL)
- + rounds tag ("rounds=$" = "rounds=\0") + strlen(ROUNDS_MAX)
- + salt (up to SALT_LEN_MAX chars) + '$' + hash (43 chars). */
-
-#define LENGTH_OF_NUMBER(n) (sizeof #n - 1)
-
-#define SHA256_HASH_LENGTH \
- (sizeof (sha256_salt_prefix) + sizeof (sha256_rounds_prefix) + \
- LENGTH_OF_NUMBER (ROUNDS_MAX) + SALT_LEN_MAX + 1 + 43)
-
-static_assert (SHA256_HASH_LENGTH <= CRYPT_OUTPUT_SIZE,
- "CRYPT_OUTPUT_SIZE is too small for SHA256");
-
-/* A sha256_buffer holds all of the sensitive intermediate data. */
-struct sha256_buffer
-{
- struct sha256_ctx ctx;
- uint8_t result[32];
- uint8_t p_bytes[32];
- uint8_t s_bytes[32];
-};
-
-static_assert (sizeof (struct sha256_buffer) <= ALG_SPECIFIC_SIZE,
- "ALG_SPECIFIC_SIZE is too small for SHA256");
-
-
/* Table with characters for base64 transformation. */
-static const char b64t[] =
+static const char b64t[64] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/* Subroutine of _xcrypt_crypt_sha256_rn: Feed CTX with LEN bytes of a
@@ -86,30 +56,23 @@ sha256_process_recycled_bytes (unsigned char block[32], size_t len,
sha256_process_bytes (block, cnt, ctx);
}
-void
-crypt_sha256_rn (const char *phrase, size_t phr_size,
- const char *setting, size_t ARG_UNUSED (set_size),
- uint8_t *output, size_t out_size,
- void *scratch, size_t scr_size)
+static char *
+sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
{
- /* This shouldn't ever happen, but... */
- if (out_size < SHA256_HASH_LENGTH
- || scr_size < sizeof (struct sha256_buffer))
- {
- errno = ERANGE;
- return;
- }
-
- struct sha256_buffer *buf = scratch;
- struct sha256_ctx *ctx = &buf->ctx;
- uint8_t *result = buf->result;
- uint8_t *p_bytes = buf->p_bytes;
- uint8_t *s_bytes = buf->s_bytes;
- char *cp = (char *)output;
- const char *salt = setting;
-
- size_t salt_size;
+ unsigned char alt_result[32]
+ __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
+ unsigned char temp_result[32]
+ __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
+ struct sha256_ctx ctx;
+ struct sha256_ctx alt_ctx;
+ size_t salt_len;
+ size_t key_len;
size_t cnt;
+ char *cp;
+ char *copied_key = NULL;
+ char *copied_salt = NULL;
+ char *p_bytes;
+ char *s_bytes;
/* Default number of rounds. */
size_t rounds = ROUNDS_DEFAULT;
bool rounds_custom = false;
@@ -124,176 +87,214 @@ crypt_sha256_rn (const char *phrase, size_t phr_size,
== 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;
- rounds = strtoul (num, &endp, 10);
- if (endp == num || *endp != '$'
- || rounds < ROUNDS_MIN
- || rounds > ROUNDS_MAX
- || errno)
+ unsigned long int srounds = strtoul (num, &endp, 10);
+ if (*endp == '$')
{
- errno = EINVAL;
- return;
+ salt = endp + 1;
+ rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
+ rounds_custom = true;
}
- salt = endp + 1;
- rounds_custom = true;
}
- salt_size = strspn (salt, b64t);
- if (salt[salt_size] && salt[salt_size] != '$')
+ salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
+ key_len = strlen (key);
+
+ if ((key - (char *) 0) % __alignof__ (uint32_t) != 0)
{
- errno = EINVAL;
- return;
+ char *tmp = (char *) alloca (key_len + __alignof__ (uint32_t));
+ key = copied_key =
+ memcpy (tmp + __alignof__ (uint32_t)
+ - (tmp - (char *) 0) % __alignof__ (uint32_t),
+ key, key_len);
}
- if (salt_size > SALT_LEN_MAX)
- salt_size = SALT_LEN_MAX;
- /* Compute alternate SHA256 sum with input PHRASE, SALT, and PHRASE. The
- final result will be added to the first context. */
- sha256_init_ctx (ctx);
+ if ((salt - (char *) 0) % __alignof__ (uint32_t) != 0)
+ {
+ char *tmp = (char *) alloca (salt_len + __alignof__ (uint32_t));
+ salt = copied_salt =
+ memcpy (tmp + __alignof__ (uint32_t)
+ - (tmp - (char *) 0) % __alignof__ (uint32_t),
+ salt, salt_len);
+ }
- /* Add phrase. */
- sha256_process_bytes (phrase, phr_size, ctx);
+ /* Prepare for the real work. */
+ sha256_init_ctx (&ctx);
- /* Add salt. */
- sha256_process_bytes (salt, salt_size, ctx);
+ /* Add the key string. */
+ sha256_process_bytes (key, key_len, &ctx);
- /* Add phrase again. */
- sha256_process_bytes (phrase, phr_size, ctx);
+ /* The last part is the salt string. This must be at most 16
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha256_process_bytes (salt, salt_len, &ctx);
- /* Now get result of this (32 bytes). */
- sha256_finish_ctx (ctx, result);
+ /* Compute alternate SHA256 sum with input KEY, SALT, and KEY. The
+ final result will be added to the first context. */
+ sha256_init_ctx (&alt_ctx);
- /* Prepare for the real work. */
- sha256_init_ctx (ctx);
+ /* Add key. */
+ sha256_process_bytes (key, key_len, &alt_ctx);
- /* Add the phrase string. */
- sha256_process_bytes (phrase, phr_size, ctx);
+ /* Add salt. */
+ sha256_process_bytes (salt, salt_len, &alt_ctx);
- /* The last part is the salt string. This must be at most 8
- characters and it ends at the first `$' character (for
- compatibility with existing implementations). */
- sha256_process_bytes (salt, salt_size, ctx);
+ /* Add key again. */
+ sha256_process_bytes (key, key_len, &alt_ctx);
+
+ /* Now get result of this (32 bytes) and add it to the other
+ context. */
+ sha256_finish_ctx (&alt_ctx, alt_result);
- /* Add for any character in the phrase one byte of the alternate sum. */
- for (cnt = phr_size; cnt > 32; cnt -= 32)
- sha256_process_bytes (result, 32, ctx);
- sha256_process_bytes (result, cnt, ctx);
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 32; cnt -= 32)
+ sha256_process_bytes (alt_result, 32, &ctx);
+ sha256_process_bytes (alt_result, cnt, &ctx);
- /* Take the binary representation of the length of the phrase and for every
- 1 add the alternate sum, for every 0 the phrase. */
- for (cnt = phr_size; cnt > 0; cnt >>= 1)
+ /* Take the binary representation of the length of the key and for every
+ 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
if ((cnt & 1) != 0)
- sha256_process_bytes (result, 32, ctx);
+ sha256_process_bytes (alt_result, 32, &ctx);
else
- sha256_process_bytes (phrase, phr_size, ctx);
+ sha256_process_bytes (key, key_len, &ctx);
/* Create intermediate result. */
- sha256_finish_ctx (ctx, result);
+ sha256_finish_ctx (&ctx, alt_result);
/* Start computation of P byte sequence. */
- sha256_init_ctx (ctx);
+ sha256_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < phr_size; ++cnt)
- sha256_process_bytes (phrase, phr_size, ctx);
+ for (cnt = 0; cnt < key_len; ++cnt)
+ sha256_process_bytes (key, key_len, &alt_ctx);
/* Finish the digest. */
- sha256_finish_ctx (ctx, p_bytes);
+ sha256_finish_ctx (&alt_ctx, temp_result);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca (key_len);
+ for (cnt = key_len; cnt >= 32; cnt -= 32)
+ cp = mempcpy (cp, temp_result, 32);
+ memcpy (cp, temp_result, cnt);
/* Start computation of S byte sequence. */
- sha256_init_ctx (ctx);
+ sha256_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < (size_t) 16 + (size_t) result[0]; ++cnt)
- sha256_process_bytes (salt, salt_size, ctx);
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ sha256_process_bytes (salt, salt_len, &alt_ctx);
/* Finish the digest. */
- sha256_finish_ctx (ctx, s_bytes);
+ sha256_finish_ctx (&alt_ctx, temp_result);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca (salt_len);
+ for (cnt = salt_len; cnt >= 32; cnt -= 32)
+ cp = mempcpy (cp, temp_result, 32);
+ memcpy (cp, temp_result, cnt);
/* Repeatedly run the collected hash value through SHA256 to burn
CPU cycles. */
for (cnt = 0; cnt < rounds; ++cnt)
{
/* New context. */
- sha256_init_ctx (ctx);
+ sha256_init_ctx (&ctx);
- /* Add phrase or last result. */
+ /* Add key or last result. */
if ((cnt & 1) != 0)
- sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha256_process_bytes (p_bytes, key_len, &ctx);
else
- sha256_process_bytes (result, 32, ctx);
+ sha256_process_bytes (alt_result, 32, &ctx);
/* Add salt for numbers not divisible by 3. */
if (cnt % 3 != 0)
- sha256_process_recycled_bytes (s_bytes, salt_size, ctx);
+ sha256_process_bytes (s_bytes, salt_len, &ctx);
- /* Add phrase for numbers not divisible by 7. */
+ /* Add key for numbers not divisible by 7. */
if (cnt % 7 != 0)
- sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha256_process_bytes (p_bytes, key_len, &ctx);
- /* Add phrase or last result. */
+ /* Add key or last result. */
if ((cnt & 1) != 0)
- sha256_process_bytes (result, 32, ctx);
+ sha256_process_bytes (alt_result, 32, &ctx);
else
- sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha256_process_bytes (p_bytes, key_len, &ctx);
/* Create intermediate result. */
- sha256_finish_ctx (ctx, result);
+ sha256_finish_ctx (&ctx, alt_result);
}
- /* Now we can construct the result string. It consists of four
- parts, one of which is optional. We already know that there
- is sufficient space at CP for the longest possible result string. */
- memcpy (cp, sha256_salt_prefix, sizeof (sha256_salt_prefix) - 1);
- cp += sizeof (sha256_salt_prefix) - 1;
+ /* Now we can construct the result string. It consists of three
+ parts. */
+ cp = stpncpy (buffer, sha256_salt_prefix, MAX (0, buflen));
+ buflen -= sizeof (sha256_salt_prefix) - 1;
if (rounds_custom)
{
- int n = snprintf (cp,
- SHA256_HASH_LENGTH - (sizeof (sha256_salt_prefix) - 1),
- "%s%zu$", sha256_rounds_prefix, rounds);
+ int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
+ sha256_rounds_prefix, rounds);
cp += n;
+ buflen -= n;
}
- memcpy (cp, salt, salt_size);
- cp += salt_size;
- *cp++ = '$';
-
-#define b64_from_24bit(B2, B1, B0, N) \
- do { \
- unsigned int w = ((((unsigned int)(B2)) << 16) | \
- (((unsigned int)(B1)) << 8) | \
- ((unsigned int)(B0))); \
- int n = (N); \
- while (n-- > 0) \
- { \
- *cp++ = b64t[w & 0x3f]; \
- w >>= 6; \
- } \
+ cp = stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
+ buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
+
+ if (buflen > 0)
+ {
+ *cp++ = '$';
+ --buflen;
+ }
+
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (n-- > 0 && buflen > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ --buflen; \
+ w >>= 6; \
+ } \
} while (0)
- b64_from_24bit (result[0], result[10], result[20], 4);
- b64_from_24bit (result[21], result[1], result[11], 4);
- b64_from_24bit (result[12], result[22], result[2], 4);
- b64_from_24bit (result[3], result[13], result[23], 4);
- b64_from_24bit (result[24], result[4], result[14], 4);
- b64_from_24bit (result[15], result[25], result[5], 4);
- b64_from_24bit (result[6], result[16], result[26], 4);
- b64_from_24bit (result[27], result[7], result[17], 4);
- b64_from_24bit (result[18], result[28], result[8], 4);
- b64_from_24bit (result[9], result[19], result[29], 4);
- b64_from_24bit (0, result[31], result[30], 3);
-
- *cp = '\0';
+ b64_from_24bit (alt_result[0], alt_result[10], alt_result[20], 4);
+ b64_from_24bit (alt_result[21], alt_result[1], alt_result[11], 4);
+ b64_from_24bit (alt_result[12], alt_result[22], alt_result[2], 4);
+ b64_from_24bit (alt_result[3], alt_result[13], alt_result[23], 4);
+ b64_from_24bit (alt_result[24], alt_result[4], alt_result[14], 4);
+ b64_from_24bit (alt_result[15], alt_result[25], alt_result[5], 4);
+ b64_from_24bit (alt_result[6], alt_result[16], alt_result[26], 4);
+ b64_from_24bit (alt_result[27], alt_result[7], alt_result[17], 4);
+ b64_from_24bit (alt_result[18], alt_result[28], alt_result[8], 4);
+ b64_from_24bit (alt_result[9], alt_result[19], alt_result[29], 4);
+ b64_from_24bit (0, alt_result[31], alt_result[30], 3);
+ if (buflen <= 0)
+ {
+ errno = ERANGE;
+ buffer = NULL;
+ }
+ else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. We do it in this way to clear correct_words[]
+ inside the SHA256 implementation as well. */
+ sha256_init_ctx (&ctx);
+ sha256_finish_ctx (&ctx, alt_result);
+ memset (temp_result, '\0', sizeof (temp_result));
+ memset (p_bytes, '\0', key_len);
+ memset (s_bytes, '\0', salt_len);
+ memset (&ctx, '\0', sizeof (ctx));
+ memset (&alt_ctx, '\0', sizeof (alt_ctx));
+ if (copied_key != NULL)
+ memset (copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset (copied_salt, '\0', salt_len);
+
+ return buffer;
}
void
From 40a0d88687d7944ae618b1f507e6a0adc532399c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 14 Jul 2018 21:00:10 +0200
Subject: [PATCH 04/10] crypt-sha256.c: Apply previous commits from Zack
Weinberg
This patch summarizes the changes from:
* 4a1152b4f9bc900d0488b473e20daed95025f4b0
* ccc833b4b2c60cefd74cb91a05f1ce7628179657
* 118abc2c5c08542fe528a1193328b161a756db90
* 9483c648978378a9cd128382049a88055d5b2a61
* a67c7cd73c19592315ae184fe8dee155ef6ebd31
* 4856729bd75c78e4e1e4e35ab5afd7cef6c66afc
* a2d558581c3cd9b3d62f916825405cebd708f268
* b46a39a57e4801f5c41b1bac207239b6ed8e31a5
* cbdf27e254b0a113f0bea87071177f083e3f2545
* 00ec9369ac4875a8e3903d6e41ae785bbc8e8b26
* 114d4200eaa572525089795cf7990c3dafd5028c
* ed4be6afa7b34fe0d827cc3f7f9608de0d9325cd
* a7f9df50cecec46bb8176382faa685ce35ca72be
* 15d1e3bf3d259ea262f3d34e8c225a3abfabaa09
---
crypt-sha256.c | 326 ++++++++++++++++++++++++-------------------------
1 file changed, 162 insertions(+), 164 deletions(-)
diff --git a/crypt-sha256.c b/crypt-sha256.c
index c2954a4..e036a18 100644
--- a/crypt-sha256.c
+++ b/crypt-sha256.c
@@ -1,13 +1,15 @@
/* One way encryption based on the SHA256-based Unix crypt implementation.
*
* Written by Ulrich Drepper <drepper at redhat.com> in 2007 [1].
- * To the extent possible under law, Ulrich Drepper has waived all
+ * Modified by Zack Weinberg <zackw at panix.com> in 2017, 2018.
+ * Composed by Björn Esser <besser82 at fedoraproject.org> in 2018.
+ * To the extent possible under law, the named authors have waived all
* copyright and related or neighboring rights to this work.
*
* See https://creativecommons.org/publicdomain/zero/1.0/ for further
* details.
*
- * This file is an except from [2], lines 648 up to 909.
+ * This file is a modified except from [2], lines 648 up to 909.
*
* [1] https://www.akkadia.org/drepper/sha-crypt.html
* [2] https://www.akkadia.org/drepper/SHA-crypt.txt
@@ -39,8 +41,35 @@ static const char sha256_rounds_prefix[] = "rounds=";
/* Maximum number of rounds. */
#define ROUNDS_MAX 999999999
+/* The maximum possible length of a SHA256-hashed password string,
+ including the terminating NUL character. Prefix (including its NUL)
+ + rounds tag ("rounds=$" = "rounds=\0") + strlen(ROUNDS_MAX)
+ + salt (up to SALT_LEN_MAX chars) + '$' + hash (43 chars). */
+
+#define LENGTH_OF_NUMBER(n) (sizeof #n - 1)
+
+#define SHA256_HASH_LENGTH \
+ (sizeof (sha256_salt_prefix) + sizeof (sha256_rounds_prefix) + \
+ LENGTH_OF_NUMBER (ROUNDS_MAX) + SALT_LEN_MAX + 1 + 43)
+
+static_assert (SHA256_HASH_LENGTH <= CRYPT_OUTPUT_SIZE,
+ "CRYPT_OUTPUT_SIZE is too small for SHA256");
+
+/* A sha256_buffer holds all of the sensitive intermediate data. */
+struct sha256_buffer
+{
+ struct sha256_ctx ctx;
+ uint8_t result[32];
+ uint8_t p_bytes[32];
+ uint8_t s_bytes[32];
+};
+
+static_assert (sizeof (struct sha256_buffer) <= ALG_SPECIFIC_SIZE,
+ "ALG_SPECIFIC_SIZE is too small for SHA256");
+
+
/* 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
@@ -56,23 +85,30 @@ sha256_process_recycled_bytes (unsigned char block[32], size_t len,
sha256_process_bytes (block, cnt, ctx);
}
-static char *
-sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
+void
+crypt_sha256_rn (const char *phrase, size_t phr_size,
+ const char *setting, size_t ARG_UNUSED (set_size),
+ uint8_t *output, size_t out_size,
+ void *scratch, size_t scr_size)
{
- unsigned char alt_result[32]
- __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
- unsigned char temp_result[32]
- __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
- struct sha256_ctx ctx;
- struct sha256_ctx alt_ctx;
- size_t salt_len;
- size_t key_len;
+ /* This shouldn't ever happen, but... */
+ if (out_size < SHA256_HASH_LENGTH
+ || scr_size < sizeof (struct sha256_buffer))
+ {
+ errno = ERANGE;
+ return;
+ }
+
+ struct sha256_buffer *buf = scratch;
+ struct sha256_ctx *ctx = &buf->ctx;
+ uint8_t *result = buf->result;
+ uint8_t *p_bytes = buf->p_bytes;
+ uint8_t *s_bytes = buf->s_bytes;
+ char *cp = (char *)output;
+ const char *salt = setting;
+
+ size_t salt_size;
size_t cnt;
- char *cp;
- char *copied_key = NULL;
- char *copied_salt = NULL;
- char *p_bytes;
- char *s_bytes;
/* Default number of rounds. */
size_t rounds = ROUNDS_DEFAULT;
bool rounds_custom = false;
@@ -87,214 +123,176 @@ sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
== 0)
{
const char *num = salt + sizeof (sha256_rounds_prefix) - 1;
- char *endp;
- unsigned long int srounds = strtoul (num, &endp, 10);
- if (*endp == '$')
+ /* 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'))
{
- salt = endp + 1;
- rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
- rounds_custom = true;
+ errno = EINVAL;
+ return;
}
- }
-
- salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
- key_len = strlen (key);
- if ((key - (char *) 0) % __alignof__ (uint32_t) != 0)
- {
- char *tmp = (char *) alloca (key_len + __alignof__ (uint32_t));
- key = copied_key =
- memcpy (tmp + __alignof__ (uint32_t)
- - (tmp - (char *) 0) % __alignof__ (uint32_t),
- key, key_len);
+ errno = 0;
+ char *endp;
+ rounds = strtoul (num, &endp, 10);
+ if (endp == num || *endp != '$'
+ || rounds < ROUNDS_MIN
+ || rounds > ROUNDS_MAX
+ || errno)
+ {
+ errno = EINVAL;
+ return;
+ }
+ salt = endp + 1;
+ rounds_custom = true;
}
- if ((salt - (char *) 0) % __alignof__ (uint32_t) != 0)
+ salt_size = strspn (salt, b64t);
+ if (salt[salt_size] && salt[salt_size] != '$')
{
- char *tmp = (char *) alloca (salt_len + __alignof__ (uint32_t));
- salt = copied_salt =
- memcpy (tmp + __alignof__ (uint32_t)
- - (tmp - (char *) 0) % __alignof__ (uint32_t),
- salt, salt_len);
+ errno = EINVAL;
+ return;
}
+ if (salt_size > SALT_LEN_MAX)
+ salt_size = SALT_LEN_MAX;
- /* Prepare for the real work. */
- sha256_init_ctx (&ctx);
+ /* Compute alternate SHA256 sum with input PHRASE, SALT, and PHRASE. The
+ final result will be added to the first context. */
+ sha256_init_ctx (ctx);
- /* Add the key string. */
- sha256_process_bytes (key, key_len, &ctx);
+ /* Add phrase. */
+ sha256_process_bytes (phrase, phr_size, ctx);
- /* The last part is the salt string. This must be at most 16
- characters and it ends at the first `$' character (for
- compatibility with existing implementations). */
- sha256_process_bytes (salt, salt_len, &ctx);
+ /* Add salt. */
+ sha256_process_bytes (salt, salt_size, ctx);
- /* Compute alternate SHA256 sum with input KEY, SALT, and KEY. The
- final result will be added to the first context. */
- sha256_init_ctx (&alt_ctx);
+ /* Add phrase again. */
+ sha256_process_bytes (phrase, phr_size, ctx);
- /* Add key. */
- sha256_process_bytes (key, key_len, &alt_ctx);
+ /* Now get result of this (32 bytes). */
+ sha256_finish_ctx (ctx, result);
- /* Add salt. */
- sha256_process_bytes (salt, salt_len, &alt_ctx);
+ /* Prepare for the real work. */
+ sha256_init_ctx (ctx);
- /* Add key again. */
- sha256_process_bytes (key, key_len, &alt_ctx);
+ /* Add the phrase string. */
+ sha256_process_bytes (phrase, phr_size, ctx);
- /* Now get result of this (32 bytes) and add it to the other
- context. */
- sha256_finish_ctx (&alt_ctx, alt_result);
+ /* The last part is the salt string. This must be at most 8
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha256_process_bytes (salt, salt_size, ctx);
- /* Add for any character in the key one byte of the alternate sum. */
- for (cnt = key_len; cnt > 32; cnt -= 32)
- sha256_process_bytes (alt_result, 32, &ctx);
- sha256_process_bytes (alt_result, cnt, &ctx);
+ /* Add for any character in the phrase one byte of the alternate sum. */
+ for (cnt = phr_size; cnt > 32; cnt -= 32)
+ sha256_process_bytes (result, 32, ctx);
+ sha256_process_bytes (result, cnt, ctx);
- /* Take the binary representation of the length of the key and for every
- 1 add the alternate sum, for every 0 the key. */
- for (cnt = key_len; cnt > 0; cnt >>= 1)
+ /* Take the binary representation of the length of the phrase and for every
+ 1 add the alternate sum, for every 0 the phrase. */
+ for (cnt = phr_size; cnt > 0; cnt >>= 1)
if ((cnt & 1) != 0)
- sha256_process_bytes (alt_result, 32, &ctx);
+ sha256_process_bytes (result, 32, ctx);
else
- sha256_process_bytes (key, key_len, &ctx);
+ sha256_process_bytes (phrase, phr_size, ctx);
/* Create intermediate result. */
- sha256_finish_ctx (&ctx, alt_result);
+ sha256_finish_ctx (ctx, result);
/* Start computation of P byte sequence. */
- sha256_init_ctx (&alt_ctx);
+ sha256_init_ctx (ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < key_len; ++cnt)
- sha256_process_bytes (key, key_len, &alt_ctx);
+ for (cnt = 0; cnt < phr_size; ++cnt)
+ sha256_process_bytes (phrase, phr_size, ctx);
/* Finish the digest. */
- sha256_finish_ctx (&alt_ctx, temp_result);
-
- /* Create byte sequence P. */
- cp = p_bytes = alloca (key_len);
- for (cnt = key_len; cnt >= 32; cnt -= 32)
- cp = mempcpy (cp, temp_result, 32);
- memcpy (cp, temp_result, cnt);
+ sha256_finish_ctx (ctx, p_bytes);
/* Start computation of S byte sequence. */
- sha256_init_ctx (&alt_ctx);
+ sha256_init_ctx (ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
- sha256_process_bytes (salt, salt_len, &alt_ctx);
+ for (cnt = 0; cnt < (size_t) 16 + (size_t) result[0]; ++cnt)
+ sha256_process_bytes (salt, salt_size, ctx);
/* Finish the digest. */
- sha256_finish_ctx (&alt_ctx, temp_result);
-
- /* Create byte sequence S. */
- cp = s_bytes = alloca (salt_len);
- for (cnt = salt_len; cnt >= 32; cnt -= 32)
- cp = mempcpy (cp, temp_result, 32);
- memcpy (cp, temp_result, cnt);
+ sha256_finish_ctx (ctx, s_bytes);
/* Repeatedly run the collected hash value through SHA256 to burn
CPU cycles. */
for (cnt = 0; cnt < rounds; ++cnt)
{
/* New context. */
- sha256_init_ctx (&ctx);
+ sha256_init_ctx (ctx);
- /* Add key or last result. */
+ /* Add phrase or last result. */
if ((cnt & 1) != 0)
- sha256_process_bytes (p_bytes, key_len, &ctx);
+ sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
else
- sha256_process_bytes (alt_result, 32, &ctx);
+ sha256_process_bytes (result, 32, ctx);
/* Add salt for numbers not divisible by 3. */
if (cnt % 3 != 0)
- sha256_process_bytes (s_bytes, salt_len, &ctx);
+ sha256_process_recycled_bytes (s_bytes, salt_size, ctx);
- /* Add key for numbers not divisible by 7. */
+ /* Add phrase for numbers not divisible by 7. */
if (cnt % 7 != 0)
- sha256_process_bytes (p_bytes, key_len, &ctx);
+ sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
- /* Add key or last result. */
+ /* Add phrase or last result. */
if ((cnt & 1) != 0)
- sha256_process_bytes (alt_result, 32, &ctx);
+ sha256_process_bytes (result, 32, ctx);
else
- sha256_process_bytes (p_bytes, key_len, &ctx);
+ sha256_process_recycled_bytes (p_bytes, phr_size, ctx);
/* Create intermediate result. */
- sha256_finish_ctx (&ctx, alt_result);
+ sha256_finish_ctx (ctx, result);
}
- /* Now we can construct the result string. It consists of three
- parts. */
- cp = stpncpy (buffer, sha256_salt_prefix, MAX (0, buflen));
- buflen -= sizeof (sha256_salt_prefix) - 1;
+ /* Now we can construct the result string. It consists of four
+ parts, one of which is optional. We already know that there
+ is sufficient space at CP for the longest possible result string. */
+ memcpy (cp, sha256_salt_prefix, sizeof (sha256_salt_prefix) - 1);
+ cp += sizeof (sha256_salt_prefix) - 1;
if (rounds_custom)
{
- int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
- sha256_rounds_prefix, rounds);
+ int n = snprintf (cp,
+ SHA256_HASH_LENGTH - (sizeof (sha256_salt_prefix) - 1),
+ "%s%zu$", sha256_rounds_prefix, rounds);
cp += n;
- buflen -= n;
- }
-
- cp = stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
- buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
-
- if (buflen > 0)
- {
- *cp++ = '$';
- --buflen;
}
-#define b64_from_24bit(B2, B1, B0, N) \
- do { \
- unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
- int n = (N); \
- while (n-- > 0 && buflen > 0) \
- { \
- *cp++ = b64t[w & 0x3f]; \
- --buflen; \
- w >>= 6; \
- } \
+ memcpy (cp, salt, salt_size);
+ cp += salt_size;
+ *cp++ = '$';
+
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((((unsigned int)(B2)) << 16) | \
+ (((unsigned int)(B1)) << 8) | \
+ ((unsigned int)(B0))); \
+ int n = (N); \
+ while (n-- > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ w >>= 6; \
+ } \
} while (0)
- b64_from_24bit (alt_result[0], alt_result[10], alt_result[20], 4);
- b64_from_24bit (alt_result[21], alt_result[1], alt_result[11], 4);
- b64_from_24bit (alt_result[12], alt_result[22], alt_result[2], 4);
- b64_from_24bit (alt_result[3], alt_result[13], alt_result[23], 4);
- b64_from_24bit (alt_result[24], alt_result[4], alt_result[14], 4);
- b64_from_24bit (alt_result[15], alt_result[25], alt_result[5], 4);
- b64_from_24bit (alt_result[6], alt_result[16], alt_result[26], 4);
- b64_from_24bit (alt_result[27], alt_result[7], alt_result[17], 4);
- b64_from_24bit (alt_result[18], alt_result[28], alt_result[8], 4);
- b64_from_24bit (alt_result[9], alt_result[19], alt_result[29], 4);
- b64_from_24bit (0, alt_result[31], alt_result[30], 3);
- if (buflen <= 0)
- {
- errno = ERANGE;
- buffer = NULL;
- }
- else
- *cp = '\0'; /* Terminate the string. */
-
- /* Clear the buffer for the intermediate result so that people
- attaching to processes or reading core dumps cannot get any
- information. We do it in this way to clear correct_words[]
- inside the SHA256 implementation as well. */
- sha256_init_ctx (&ctx);
- sha256_finish_ctx (&ctx, alt_result);
- memset (temp_result, '\0', sizeof (temp_result));
- memset (p_bytes, '\0', key_len);
- memset (s_bytes, '\0', salt_len);
- memset (&ctx, '\0', sizeof (ctx));
- memset (&alt_ctx, '\0', sizeof (alt_ctx));
- if (copied_key != NULL)
- memset (copied_key, '\0', key_len);
- if (copied_salt != NULL)
- memset (copied_salt, '\0', salt_len);
-
- return buffer;
+ b64_from_24bit (result[0], result[10], result[20], 4);
+ b64_from_24bit (result[21], result[1], result[11], 4);
+ b64_from_24bit (result[12], result[22], result[2], 4);
+ b64_from_24bit (result[3], result[13], result[23], 4);
+ b64_from_24bit (result[24], result[4], result[14], 4);
+ b64_from_24bit (result[15], result[25], result[5], 4);
+ b64_from_24bit (result[6], result[16], result[26], 4);
+ b64_from_24bit (result[27], result[7], result[17], 4);
+ b64_from_24bit (result[18], result[28], result[8], 4);
+ b64_from_24bit (result[9], result[19], result[29], 4);
+ b64_from_24bit (0, result[31], result[30], 3);
+
+ *cp = '\0';
}
void
From 989f1faae098a9345855bf733b8f35f92cefcf23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 14 Jul 2018 21:40:34 +0200
Subject: [PATCH 05/10] Replace crypt-sha512.c with an implementation in the
Public Domain.
This implementation is based on the SHA512-based Unix crypt
implementation. Released into the Public Domain [1] by
Ulrich Drepper <drepper@redhat.com>.
This file is a modified except from [2], lines 1403 up to 1676.
[1] https://www.akkadia.org/drepper/sha-crypt.html
[2] https://www.akkadia.org/drepper/SHA-crypt.txt
---
crypt-sha512.c | 383 ++++++++++++++++++++++++-------------------------
1 file changed, 191 insertions(+), 192 deletions(-)
diff --git a/crypt-sha512.c b/crypt-sha512.c
index 955a27b..f3798a0 100644
--- a/crypt-sha512.c
+++ b/crypt-sha512.c
@@ -1,20 +1,17 @@
-/* One way encryption based on SHA512 sum.
-
- Copyright (C) 2007-2017 Free Software Foundation, Inc.
-
- 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
- <https://www.gnu.org/licenses/>. */
+/* One way encryption based on the SHA512-based Unix crypt implementation.
+ *
+ * Written by Ulrich Drepper <drepper at redhat.com> in 2007 [1].
+ * To the extent possible under law, Ulrich Drepper has waived all
+ * copyright and related or neighboring rights to this work.
+ *
+ * See https://creativecommons.org/publicdomain/zero/1.0/ for further
+ * details.
+ *
+ * This file is a modified except from [2], lines 1403 up to 1676.
+ *
+ * [1] https://www.akkadia.org/drepper/sha-crypt.html
+ * [2] https://www.akkadia.org/drepper/SHA-crypt.txt
+ */
#include "crypt-port.h"
#include "crypt-private.h"
@@ -42,36 +39,9 @@ static const char sha512_rounds_prefix[] = "rounds=";
/* Maximum number of rounds. */
#define ROUNDS_MAX 999999999
-/* The maximum possible length of a SHA512-hashed password string,
- including the terminating NUL character. Prefix (including its NUL)
- + rounds tag ("rounds=$" = "rounds=\0") + strlen(ROUNDS_MAX)
- + salt (up to SALT_LEN_MAX chars) + '$' + hash (86 chars). */
-
-#define LENGTH_OF_NUMBER(n) (sizeof #n - 1)
-
-#define SHA512_HASH_LENGTH \
- (sizeof (sha512_salt_prefix) + sizeof (sha512_rounds_prefix) + \
- LENGTH_OF_NUMBER (ROUNDS_MAX) + SALT_LEN_MAX + 1 + 86)
-
-static_assert (SHA512_HASH_LENGTH <= CRYPT_OUTPUT_SIZE,
- "CRYPT_OUTPUT_SIZE is too small for SHA512");
-
-/* A sha512_buffer holds all of the sensitive intermediate data. */
-struct sha512_buffer
-{
- struct sha512_ctx ctx;
- uint8_t result[64];
- uint8_t p_bytes[64];
- uint8_t s_bytes[64];
-};
-
-static_assert (sizeof (struct sha512_buffer) <= ALG_SPECIFIC_SIZE,
- "ALG_SPECIFIC_SIZE is too small for SHA512");
-
-
/* Table with characters for base64 transformation. */
-static const char b64t[] =
- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+static const char b64t[64] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/* Subroutine of _xcrypt_crypt_sha512_rn: Feed CTX with LEN bytes of a
virtual byte sequence consisting of BLOCK repeated over and over
@@ -86,30 +56,23 @@ sha512_process_recycled_bytes (unsigned char block[64], size_t len,
sha512_process_bytes (block, cnt, ctx);
}
-void
-crypt_sha512_rn (const char *phrase, size_t phr_size,
- const char *setting, size_t ARG_UNUSED (set_size),
- uint8_t *output, size_t out_size,
- void *scratch, size_t scr_size)
+static char *
+sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
{
- /* This shouldn't ever happen, but... */
- if (out_size < SHA512_HASH_LENGTH
- || scr_size < sizeof (struct sha512_buffer))
- {
- errno = ERANGE;
- return;
- }
-
- struct sha512_buffer *buf = scratch;
- struct sha512_ctx *ctx = &buf->ctx;
- uint8_t *result = buf->result;
- uint8_t *p_bytes = buf->p_bytes;
- uint8_t *s_bytes = buf->s_bytes;
- char *cp = (char *)output;
- const char *salt = setting;
-
- size_t salt_size;
+ unsigned char alt_result[64]
+ __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
+ unsigned char temp_result[64]
+ __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
+ struct sha512_ctx ctx;
+ struct sha512_ctx alt_ctx;
+ size_t salt_len;
+ size_t key_len;
size_t cnt;
+ char *cp;
+ char *copied_key = NULL;
+ char *copied_salt = NULL;
+ char *p_bytes;
+ char *s_bytes;
/* Default number of rounds. */
size_t rounds = ROUNDS_DEFAULT;
bool rounds_custom = false;
@@ -124,191 +87,227 @@ crypt_sha512_rn (const char *phrase, size_t phr_size,
== 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;
- rounds = strtoul (num, &endp, 10);
- if (endp == num || *endp != '$'
- || rounds < ROUNDS_MIN
- || rounds > ROUNDS_MAX
- || errno)
- {
- errno = EINVAL;
- return;
- }
- salt = endp + 1;
- rounds_custom = true;
+ unsigned long int srounds = strtoul (num, &endp, 10);
+ if (*endp == '$')
+ {
+ salt = endp + 1;
+ rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
+ key_len = strlen (key);
+
+ if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
+ {
+ char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
+ key = copied_key =
+ memcpy (tmp + __alignof__ (uint64_t)
+ - (tmp - (char *) 0) % __alignof__ (uint64_t),
+ key, key_len);
}
- salt_size = strspn (salt, b64t);
- if (salt[salt_size] && salt[salt_size] != '$')
+ if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
{
- errno = EINVAL;
- return;
+ char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
+ salt = copied_salt =
+ memcpy (tmp + __alignof__ (uint64_t)
+ - (tmp - (char *) 0) % __alignof__ (uint64_t),
+ salt, salt_len);
}
- if (salt_size > SALT_LEN_MAX)
- salt_size = SALT_LEN_MAX;
- phr_size = strlen (phrase);
- /* Compute alternate SHA512 sum with input PHRASE, SALT, and PHRASE. The
+ /* Prepare for the real work. */
+ sha512_init_ctx (&ctx);
+
+ /* Add the key string. */
+ sha512_process_bytes (key, key_len, &ctx);
+
+ /* The last part is the salt string. This must be at most 16
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha512_process_bytes (salt, salt_len, &ctx);
+
+
+ /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
final result will be added to the first context. */
- sha512_init_ctx (ctx);
+ sha512_init_ctx (&alt_ctx);
- /* Add phrase. */
- sha512_process_bytes (phrase, phr_size, ctx);
+ /* Add key. */
+ sha512_process_bytes (key, key_len, &alt_ctx);
/* Add salt. */
- sha512_process_bytes (salt, salt_size, ctx);
+ sha512_process_bytes (salt, salt_len, &alt_ctx);
- /* Add phrase again. */
- sha512_process_bytes (phrase, phr_size, ctx);
+ /* Add key again. */
+ sha512_process_bytes (key, key_len, &alt_ctx);
/* Now get result of this (64 bytes) and add it to the other
context. */
- sha512_finish_ctx (ctx, result);
-
- /* Prepare for the real work. */
- sha512_init_ctx (ctx);
+ sha512_finish_ctx (&alt_ctx, alt_result);
- /* Add the phrase string. */
- sha512_process_bytes (phrase, phr_size, ctx);
-
- /* The last part is the salt string. This must be at most 8
- characters and it ends at the first `$' character (for
- compatibility with existing implementations). */
- sha512_process_bytes (salt, salt_size, ctx);
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 64; cnt -= 64)
+ sha512_process_bytes (alt_result, 64, &ctx);
+ sha512_process_bytes (alt_result, cnt, &ctx);
- /* Add for any character in the phrase one byte of the alternate sum. */
- for (cnt = phr_size; cnt > 64; cnt -= 64)
- sha512_process_bytes (result, 64, ctx);
- sha512_process_bytes (result, cnt, ctx);
-
- /* Take the binary representation of the length of the phrase and for every
- 1 add the alternate sum, for every 0 the phrase. */
- for (cnt = phr_size; cnt > 0; cnt >>= 1)
+ /* Take the binary representation of the length of the key and for every
+ 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
if ((cnt & 1) != 0)
- sha512_process_bytes (result, 64, ctx);
+ sha512_process_bytes (alt_result, 64, &ctx);
else
- sha512_process_bytes (phrase, phr_size, ctx);
+ sha512_process_bytes (key, key_len, &ctx);
/* Create intermediate result. */
- sha512_finish_ctx (ctx, result);
+ sha512_finish_ctx (&ctx, alt_result);
/* Start computation of P byte sequence. */
- sha512_init_ctx (ctx);
+ sha512_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < phr_size; ++cnt)
- sha512_process_bytes (phrase, phr_size, ctx);
+ for (cnt = 0; cnt < key_len; ++cnt)
+ sha512_process_bytes (key, key_len, &alt_ctx);
/* Finish the digest. */
- sha512_finish_ctx (ctx, p_bytes);
+ sha512_finish_ctx (&alt_ctx, temp_result);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca (key_len);
+ for (cnt = key_len; cnt >= 64; cnt -= 64)
+ cp = mempcpy (cp, temp_result, 64);
+ memcpy (cp, temp_result, cnt);
/* Start computation of S byte sequence. */
- sha512_init_ctx (ctx);
+ sha512_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < (size_t) 16 + (size_t) result[0]; ++cnt)
- sha512_process_bytes (salt, salt_size, ctx);
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ sha512_process_bytes (salt, salt_len, &alt_ctx);
/* Finish the digest. */
- sha512_finish_ctx (ctx, s_bytes);
+ sha512_finish_ctx (&alt_ctx, temp_result);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca (salt_len);
+ for (cnt = salt_len; cnt >= 64; cnt -= 64)
+ cp = mempcpy (cp, temp_result, 64);
+ memcpy (cp, temp_result, cnt);
/* Repeatedly run the collected hash value through SHA512 to burn
CPU cycles. */
for (cnt = 0; cnt < rounds; ++cnt)
{
/* New context. */
- sha512_init_ctx (ctx);
+ sha512_init_ctx (&ctx);
- /* Add phrase or last result. */
+ /* Add key or last result. */
if ((cnt & 1) != 0)
- sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha512_process_bytes (p_bytes, key_len, &ctx);
else
- sha512_process_bytes (result, 64, ctx);
+ sha512_process_bytes (alt_result, 64, &ctx);
/* Add salt for numbers not divisible by 3. */
if (cnt % 3 != 0)
- sha512_process_recycled_bytes (s_bytes, salt_size, ctx);
+ sha512_process_bytes (s_bytes, salt_len, &ctx);
- /* Add phrase for numbers not divisible by 7. */
+ /* Add key for numbers not divisible by 7. */
if (cnt % 7 != 0)
- sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha512_process_bytes (p_bytes, key_len, &ctx);
- /* Add phrase or last result. */
+ /* Add key or last result. */
if ((cnt & 1) != 0)
- sha512_process_bytes (result, 64, ctx);
+ sha512_process_bytes (alt_result, 64, &ctx);
else
- sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
+ sha512_process_bytes (p_bytes, key_len, &ctx);
/* Create intermediate result. */
- sha512_finish_ctx (ctx, result);
+ sha512_finish_ctx (&ctx, alt_result);
}
- /* Now we can construct the result string. It consists of four
- parts, one of which is optional. We already know that buflen is
- at least sha512_hash_length, therefore none of the string bashing
- below can overflow the buffer. */
-
- memcpy (cp, sha512_salt_prefix, sizeof (sha512_salt_prefix) - 1);
- cp += sizeof (sha512_salt_prefix) - 1;
+ /* Now we can construct the result string. It consists of three
+ parts. */
+ cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
+ buflen -= sizeof (sha512_salt_prefix) - 1;
if (rounds_custom)
{
- int n = snprintf (cp,
- SHA512_HASH_LENGTH - (sizeof (sha512_salt_prefix) - 1),
- "%s%zu$", sha512_rounds_prefix, rounds);
+ int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
+ sha512_rounds_prefix, rounds);
cp += n;
+ buflen -= n;
}
- memcpy (cp, salt, salt_size);
- cp += salt_size;
- *cp++ = '$';
-
-#define b64_from_24bit(B2, B1, B0, N) \
- do { \
- unsigned int w = ((((unsigned int)(B2)) << 16) | \
- (((unsigned int)(B1)) << 8) | \
- ((unsigned int)(B0))); \
- int n = (N); \
- while (n-- > 0) \
- { \
- *cp++ = b64t[w & 0x3f]; \
- w >>= 6; \
- } \
+ cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
+ buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
+
+ if (buflen > 0)
+ {
+ *cp++ = '$';
+ --buflen;
+ }
+
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (n-- > 0 && buflen > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ --buflen; \
+ w >>= 6; \
+ } \
} while (0)
- b64_from_24bit (result[0], result[21], result[42], 4);
- b64_from_24bit (result[22], result[43], result[1], 4);
- b64_from_24bit (result[44], result[2], result[23], 4);
- b64_from_24bit (result[3], result[24], result[45], 4);
- b64_from_24bit (result[25], result[46], result[4], 4);
- b64_from_24bit (result[47], result[5], result[26], 4);
- b64_from_24bit (result[6], result[27], result[48], 4);
- b64_from_24bit (result[28], result[49], result[7], 4);
- b64_from_24bit (result[50], result[8], result[29], 4);
- b64_from_24bit (result[9], result[30], result[51], 4);
- b64_from_24bit (result[31], result[52], result[10], 4);
- b64_from_24bit (result[53], result[11], result[32], 4);
- b64_from_24bit (result[12], result[33], result[54], 4);
- b64_from_24bit (result[34], result[55], result[13], 4);
- b64_from_24bit (result[56], result[14], result[35], 4);
- b64_from_24bit (result[15], result[36], result[57], 4);
- b64_from_24bit (result[37], result[58], result[16], 4);
- b64_from_24bit (result[59], result[17], result[38], 4);
- b64_from_24bit (result[18], result[39], result[60], 4);
- b64_from_24bit (result[40], result[61], result[19], 4);
- b64_from_24bit (result[62], result[20], result[41], 4);
- b64_from_24bit (0, 0, result[63], 2);
-
- *cp = '\0';
+ b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
+ b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
+ b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
+ b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
+ b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
+ b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
+ b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
+ b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
+ b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
+ b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
+ b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
+ b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
+ b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
+ b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
+ b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
+ b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
+ b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
+ b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
+ b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
+ b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
+ b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
+ b64_from_24bit (0, 0, alt_result[63], 2);
+
+ if (buflen <= 0)
+ {
+ errno = ERANGE;
+ buffer = NULL;
+ }
+ else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. We do it in this way to clear correct_words[]
+ inside the SHA512 implementation as well. */
+ sha512_init_ctx (&ctx);
+ sha512_finish_ctx (&ctx, alt_result);
+ memset (temp_result, '\0', sizeof (temp_result));
+ memset (p_bytes, '\0', key_len);
+ memset (s_bytes, '\0', salt_len);
+ memset (&ctx, '\0', sizeof (ctx));
+ memset (&alt_ctx, '\0', sizeof (alt_ctx));
+ if (copied_key != NULL)
+ memset (copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset (copied_salt, '\0', salt_len);
+
+ return buffer;
}
void
From 16abeb10230f3762c2c820b43bdb262013f2e17a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 14 Jul 2018 21:44:21 +0200
Subject: [PATCH 06/10] crypt-sha512.c: Apply previous commits from Zack
Weinberg
This patch summarizes the changes from:
* 4a1152b4f9bc900d0488b473e20daed95025f4b0
* ccc833b4b2c60cefd74cb91a05f1ce7628179657
* 118abc2c5c08542fe528a1193328b161a756db90
* 9483c648978378a9cd128382049a88055d5b2a61
* 4856729bd75c78e4e1e4e35ab5afd7cef6c66afc
* a2d558581c3cd9b3d62f916825405cebd708f268
* b46a39a57e4801f5c41b1bac207239b6ed8e31a5
* cbdf27e254b0a113f0bea87071177f083e3f2545
* 00ec9369ac4875a8e3903d6e41ae785bbc8e8b26
* 114d4200eaa572525089795cf7990c3dafd5028c
* ed4be6afa7b34fe0d827cc3f7f9608de0d9325cd
* a7f9df50cecec46bb8176382faa685ce35ca72be
* 15d1e3bf3d259ea262f3d34e8c225a3abfabaa09
---
crypt-sha512.c | 356 ++++++++++++++++++++++++-------------------------
1 file changed, 178 insertions(+), 178 deletions(-)
diff --git a/crypt-sha512.c b/crypt-sha512.c
index f3798a0..39ec0b5 100644
--- a/crypt-sha512.c
+++ b/crypt-sha512.c
@@ -1,7 +1,9 @@
/* One way encryption based on the SHA512-based Unix crypt implementation.
*
* Written by Ulrich Drepper <drepper at redhat.com> in 2007 [1].
- * To the extent possible under law, Ulrich Drepper has waived all
+ * Modified by Zack Weinberg <zackw at panix.com> in 2017, 2018.
+ * Composed by Björn Esser <besser82 at fedoraproject.org> in 2018.
+ * To the extent possible under law, the named authors have waived all
* copyright and related or neighboring rights to this work.
*
* See https://creativecommons.org/publicdomain/zero/1.0/ for further
@@ -39,9 +41,36 @@ static const char sha512_rounds_prefix[] = "rounds=";
/* Maximum number of rounds. */
#define ROUNDS_MAX 999999999
+/* The maximum possible length of a SHA512-hashed password string,
+ including the terminating NUL character. Prefix (including its NUL)
+ + rounds tag ("rounds=$" = "rounds=\0") + strlen(ROUNDS_MAX)
+ + salt (up to SALT_LEN_MAX chars) + '$' + hash (86 chars). */
+
+#define LENGTH_OF_NUMBER(n) (sizeof #n - 1)
+
+#define SHA512_HASH_LENGTH \
+ (sizeof (sha512_salt_prefix) + sizeof (sha512_rounds_prefix) + \
+ LENGTH_OF_NUMBER (ROUNDS_MAX) + SALT_LEN_MAX + 1 + 86)
+
+static_assert (SHA512_HASH_LENGTH <= CRYPT_OUTPUT_SIZE,
+ "CRYPT_OUTPUT_SIZE is too small for SHA512");
+
+/* A sha512_buffer holds all of the sensitive intermediate data. */
+struct sha512_buffer
+{
+ struct sha512_ctx ctx;
+ uint8_t result[64];
+ uint8_t p_bytes[64];
+ uint8_t s_bytes[64];
+};
+
+static_assert (sizeof (struct sha512_buffer) <= ALG_SPECIFIC_SIZE,
+ "ALG_SPECIFIC_SIZE is too small for SHA512");
+
+
/* Table with characters for base64 transformation. */
-static const char b64t[64] =
-"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+static const char b64t[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
/* Subroutine of _xcrypt_crypt_sha512_rn: Feed CTX with LEN bytes of a
virtual byte sequence consisting of BLOCK repeated over and over
@@ -56,23 +85,30 @@ sha512_process_recycled_bytes (unsigned char block[64], size_t len,
sha512_process_bytes (block, cnt, ctx);
}
-static char *
-sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
+void
+crypt_sha512_rn (const char *phrase, size_t phr_size,
+ const char *setting, size_t ARG_UNUSED (set_size),
+ uint8_t *output, size_t out_size,
+ void *scratch, size_t scr_size)
{
- unsigned char alt_result[64]
- __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
- unsigned char temp_result[64]
- __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
- struct sha512_ctx ctx;
- struct sha512_ctx alt_ctx;
- size_t salt_len;
- size_t key_len;
+ /* This shouldn't ever happen, but... */
+ if (out_size < SHA512_HASH_LENGTH
+ || scr_size < sizeof (struct sha512_buffer))
+ {
+ errno = ERANGE;
+ return;
+ }
+
+ struct sha512_buffer *buf = scratch;
+ struct sha512_ctx *ctx = &buf->ctx;
+ uint8_t *result = buf->result;
+ uint8_t *p_bytes = buf->p_bytes;
+ uint8_t *s_bytes = buf->s_bytes;
+ char *cp = (char *)output;
+ const char *salt = setting;
+
+ size_t salt_size;
size_t cnt;
- char *cp;
- char *copied_key = NULL;
- char *copied_salt = NULL;
- char *p_bytes;
- char *s_bytes;
/* Default number of rounds. */
size_t rounds = ROUNDS_DEFAULT;
bool rounds_custom = false;
@@ -87,227 +123,191 @@ sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
== 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 == '$')
- {
- salt = endp + 1;
- rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
- rounds_custom = true;
- }
+ rounds = strtoul (num, &endp, 10);
+ if (endp == num || *endp != '$'
+ || rounds < ROUNDS_MIN
+ || rounds > ROUNDS_MAX
+ || errno)
+ {
+ errno = EINVAL;
+ return;
+ }
+ salt = endp + 1;
+ rounds_custom = true;
}
- salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
- key_len = strlen (key);
-
- if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
+ salt_size = strspn (salt, b64t);
+ if (salt[salt_size] && salt[salt_size] != '$')
{
- char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
- key = copied_key =
- memcpy (tmp + __alignof__ (uint64_t)
- - (tmp - (char *) 0) % __alignof__ (uint64_t),
- key, key_len);
+ errno = EINVAL;
+ return;
}
+ if (salt_size > SALT_LEN_MAX)
+ salt_size = SALT_LEN_MAX;
+ phr_size = strlen (phrase);
- if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
- {
- char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
- salt = copied_salt =
- memcpy (tmp + __alignof__ (uint64_t)
- - (tmp - (char *) 0) % __alignof__ (uint64_t),
- salt, salt_len);
- }
-
- /* Prepare for the real work. */
- sha512_init_ctx (&ctx);
-
- /* Add the key string. */
- sha512_process_bytes (key, key_len, &ctx);
-
- /* The last part is the salt string. This must be at most 16
- characters and it ends at the first `$' character (for
- compatibility with existing implementations). */
- sha512_process_bytes (salt, salt_len, &ctx);
-
-
- /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
+ /* Compute alternate SHA512 sum with input PHRASE, SALT, and PHRASE. The
final result will be added to the first context. */
- sha512_init_ctx (&alt_ctx);
+ sha512_init_ctx (ctx);
- /* Add key. */
- sha512_process_bytes (key, key_len, &alt_ctx);
+ /* Add phrase. */
+ sha512_process_bytes (phrase, phr_size, ctx);
/* Add salt. */
- sha512_process_bytes (salt, salt_len, &alt_ctx);
+ sha512_process_bytes (salt, salt_size, ctx);
- /* Add key again. */
- sha512_process_bytes (key, key_len, &alt_ctx);
+ /* Add phrase again. */
+ sha512_process_bytes (phrase, phr_size, ctx);
/* Now get result of this (64 bytes) and add it to the other
context. */
- sha512_finish_ctx (&alt_ctx, alt_result);
+ sha512_finish_ctx (ctx, result);
+
+ /* Prepare for the real work. */
+ sha512_init_ctx (ctx);
+
+ /* Add the phrase string. */
+ sha512_process_bytes (phrase, phr_size, ctx);
+
+ /* The last part is the salt string. This must be at most 8
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha512_process_bytes (salt, salt_size, ctx);
- /* Add for any character in the key one byte of the alternate sum. */
- for (cnt = key_len; cnt > 64; cnt -= 64)
- sha512_process_bytes (alt_result, 64, &ctx);
- sha512_process_bytes (alt_result, cnt, &ctx);
+ /* Add for any character in the phrase one byte of the alternate sum. */
+ for (cnt = phr_size; cnt > 64; cnt -= 64)
+ sha512_process_bytes (result, 64, ctx);
+ sha512_process_bytes (result, cnt, ctx);
- /* Take the binary representation of the length of the key and for every
- 1 add the alternate sum, for every 0 the key. */
- for (cnt = key_len; cnt > 0; cnt >>= 1)
+ /* Take the binary representation of the length of the phrase and for every
+ 1 add the alternate sum, for every 0 the phrase. */
+ for (cnt = phr_size; cnt > 0; cnt >>= 1)
if ((cnt & 1) != 0)
- sha512_process_bytes (alt_result, 64, &ctx);
+ sha512_process_bytes (result, 64, ctx);
else
- sha512_process_bytes (key, key_len, &ctx);
+ sha512_process_bytes (phrase, phr_size, ctx);
/* Create intermediate result. */
- sha512_finish_ctx (&ctx, alt_result);
+ sha512_finish_ctx (ctx, result);
/* Start computation of P byte sequence. */
- sha512_init_ctx (&alt_ctx);
+ sha512_init_ctx (ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < key_len; ++cnt)
- sha512_process_bytes (key, key_len, &alt_ctx);
+ for (cnt = 0; cnt < phr_size; ++cnt)
+ sha512_process_bytes (phrase, phr_size, ctx);
/* Finish the digest. */
- sha512_finish_ctx (&alt_ctx, temp_result);
-
- /* Create byte sequence P. */
- cp = p_bytes = alloca (key_len);
- for (cnt = key_len; cnt >= 64; cnt -= 64)
- cp = mempcpy (cp, temp_result, 64);
- memcpy (cp, temp_result, cnt);
+ sha512_finish_ctx (ctx, p_bytes);
/* Start computation of S byte sequence. */
- sha512_init_ctx (&alt_ctx);
+ sha512_init_ctx (ctx);
/* For every character in the password add the entire password. */
- for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
- sha512_process_bytes (salt, salt_len, &alt_ctx);
+ for (cnt = 0; cnt < (size_t) 16 + (size_t) result[0]; ++cnt)
+ sha512_process_bytes (salt, salt_size, ctx);
/* Finish the digest. */
- sha512_finish_ctx (&alt_ctx, temp_result);
-
- /* Create byte sequence S. */
- cp = s_bytes = alloca (salt_len);
- for (cnt = salt_len; cnt >= 64; cnt -= 64)
- cp = mempcpy (cp, temp_result, 64);
- memcpy (cp, temp_result, cnt);
+ sha512_finish_ctx (ctx, s_bytes);
/* Repeatedly run the collected hash value through SHA512 to burn
CPU cycles. */
for (cnt = 0; cnt < rounds; ++cnt)
{
/* New context. */
- sha512_init_ctx (&ctx);
+ sha512_init_ctx (ctx);
- /* Add key or last result. */
+ /* Add phrase or last result. */
if ((cnt & 1) != 0)
- sha512_process_bytes (p_bytes, key_len, &ctx);
+ sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
else
- sha512_process_bytes (alt_result, 64, &ctx);
+ sha512_process_bytes (result, 64, ctx);
/* Add salt for numbers not divisible by 3. */
if (cnt % 3 != 0)
- sha512_process_bytes (s_bytes, salt_len, &ctx);
+ sha512_process_recycled_bytes (s_bytes, salt_size, ctx);
- /* Add key for numbers not divisible by 7. */
+ /* Add phrase for numbers not divisible by 7. */
if (cnt % 7 != 0)
- sha512_process_bytes (p_bytes, key_len, &ctx);
+ sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
- /* Add key or last result. */
+ /* Add phrase or last result. */
if ((cnt & 1) != 0)
- sha512_process_bytes (alt_result, 64, &ctx);
+ sha512_process_bytes (result, 64, ctx);
else
- sha512_process_bytes (p_bytes, key_len, &ctx);
+ sha512_process_recycled_bytes (p_bytes, phr_size, ctx);
/* Create intermediate result. */
- sha512_finish_ctx (&ctx, alt_result);
+ sha512_finish_ctx (ctx, result);
}
- /* Now we can construct the result string. It consists of three
- parts. */
- cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
- buflen -= sizeof (sha512_salt_prefix) - 1;
+ /* Now we can construct the result string. It consists of four
+ parts, one of which is optional. We already know that buflen is
+ at least sha512_hash_length, therefore none of the string bashing
+ below can overflow the buffer. */
+
+ memcpy (cp, sha512_salt_prefix, sizeof (sha512_salt_prefix) - 1);
+ cp += sizeof (sha512_salt_prefix) - 1;
if (rounds_custom)
{
- int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
- sha512_rounds_prefix, rounds);
+ int n = snprintf (cp,
+ SHA512_HASH_LENGTH - (sizeof (sha512_salt_prefix) - 1),
+ "%s%zu$", sha512_rounds_prefix, rounds);
cp += n;
- buflen -= n;
- }
-
- cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
- buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
-
- if (buflen > 0)
- {
- *cp++ = '$';
- --buflen;
}
-#define b64_from_24bit(B2, B1, B0, N) \
- do { \
- unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
- int n = (N); \
- while (n-- > 0 && buflen > 0) \
- { \
- *cp++ = b64t[w & 0x3f]; \
- --buflen; \
- w >>= 6; \
- } \
+ memcpy (cp, salt, salt_size);
+ cp += salt_size;
+ *cp++ = '$';
+
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((((unsigned int)(B2)) << 16) | \
+ (((unsigned int)(B1)) << 8) | \
+ ((unsigned int)(B0))); \
+ int n = (N); \
+ while (n-- > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ w >>= 6; \
+ } \
} while (0)
- b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
- b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
- b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
- b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
- b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
- b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
- b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
- b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
- b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
- b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
- b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
- b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
- b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
- b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
- b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
- b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
- b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
- b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
- b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
- b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
- b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
- b64_from_24bit (0, 0, alt_result[63], 2);
-
- if (buflen <= 0)
- {
- errno = ERANGE;
- buffer = NULL;
- }
- else
- *cp = '\0'; /* Terminate the string. */
-
- /* Clear the buffer for the intermediate result so that people
- attaching to processes or reading core dumps cannot get any
- information. We do it in this way to clear correct_words[]
- inside the SHA512 implementation as well. */
- sha512_init_ctx (&ctx);
- sha512_finish_ctx (&ctx, alt_result);
- memset (temp_result, '\0', sizeof (temp_result));
- memset (p_bytes, '\0', key_len);
- memset (s_bytes, '\0', salt_len);
- memset (&ctx, '\0', sizeof (ctx));
- memset (&alt_ctx, '\0', sizeof (alt_ctx));
- if (copied_key != NULL)
- memset (copied_key, '\0', key_len);
- if (copied_salt != NULL)
- memset (copied_salt, '\0', salt_len);
-
- return buffer;
+ b64_from_24bit (result[0], result[21], result[42], 4);
+ b64_from_24bit (result[22], result[43], result[1], 4);
+ b64_from_24bit (result[44], result[2], result[23], 4);
+ b64_from_24bit (result[3], result[24], result[45], 4);
+ b64_from_24bit (result[25], result[46], result[4], 4);
+ b64_from_24bit (result[47], result[5], result[26], 4);
+ b64_from_24bit (result[6], result[27], result[48], 4);
+ b64_from_24bit (result[28], result[49], result[7], 4);
+ b64_from_24bit (result[50], result[8], result[29], 4);
+ b64_from_24bit (result[9], result[30], result[51], 4);
+ b64_from_24bit (result[31], result[52], result[10], 4);
+ b64_from_24bit (result[53], result[11], result[32], 4);
+ b64_from_24bit (result[12], result[33], result[54], 4);
+ b64_from_24bit (result[34], result[55], result[13], 4);
+ b64_from_24bit (result[56], result[14], result[35], 4);
+ b64_from_24bit (result[15], result[36], result[57], 4);
+ b64_from_24bit (result[37], result[58], result[16], 4);
+ b64_from_24bit (result[59], result[17], result[38], 4);
+ b64_from_24bit (result[18], result[39], result[60], 4);
+ b64_from_24bit (result[40], result[61], result[19], 4);
+ b64_from_24bit (result[62], result[20], result[41], 4);
+ b64_from_24bit (0, 0, result[63], 2);
+
+ *cp = '\0';
}
void
From c76847e3be40c4ac0d78bc8518502418c6207144 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Wed, 1 Aug 2018 19:34:53 +0200
Subject: [PATCH 07/10] Update LICENSING and NEWS for changes in previous
commits.
crypt-sha{256,512}.c have been replaced with an implementation
in the Public Domain.
---
LICENSING | 7 +++++--
NEWS | 2 ++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/LICENSING b/LICENSING
index b9df920..3efbed0 100644
--- a/LICENSING
+++ b/LICENSING
@@ -14,14 +14,17 @@ source tree. For specific licensing terms consult the files themselves.
* Copyright Free Software Foundation, Inc.; LGPL (v2.1 or later):
crypt-base.h, crypt-obsolete.h, crypt-private.h
alg-md5.h, alg-md5.c, crypt-md5.c,
- alg-sha256.h, alg-sha256.c, crypt-sha256.c,
- alg-sha512.h, alg-sha512.c, crypt-sha256.c,
+ alg-sha256.h, alg-sha256.c,
+ alg-sha512.h, alg-sha512.c,
test-crypt-badsalt, test-crypt-nonnull
* Copyright David Burren et al.; 3-clause BSD:
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 Ulrich Drepper et al.:
+ crypt-sha256.c, crypt-sha512.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
diff --git a/NEWS b/NEWS
index 77b556f..8acf032 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ Please send bug reports, questions and suggestions to
Version 4.1.2
* Add optional 'check-valgrind' target to the Makefile.
+* Replace crypt-sha{256,512}.c with an implementation in the Public
+ Domain.
Version 4.1.1
* --enable-hashes now supports additional groups of hashing methods:
From cc1806e214b89403152c2c53932d8d0b8aeb1e91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 4 Aug 2018 13:02:03 +0200
Subject: [PATCH 08/10] Add alias man-pages for other crypt functions.
---
Makefile.am | 3 ++-
crypt.3 | 1 +
crypt.5 | 2 ++
crypt_gensalt.3 | 2 ++
crypt_r.3 | 1 +
crypt_ra.3 | 1 +
6 files changed, 9 insertions(+), 1 deletion(-)
create mode 100644 crypt.3
create mode 100644 crypt_r.3
create mode 100644 crypt_ra.3
diff --git a/Makefile.am b/Makefile.am
index 874db12..41ca783 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,7 +18,8 @@ EXTRA_DIST = \
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_man3_MANS = crypt.3 crypt_r.3 crypt_ra.3 \
+ crypt_rn.3 crypt_gensalt.3
notrans_dist_man5_MANS = crypt.5
nodist_include_HEADERS = crypt.h
diff --git a/crypt.3 b/crypt.3
new file mode 100644
index 0000000..430e48f
--- /dev/null
+++ b/crypt.3
@@ -0,0 +1 @@
+.so man3/crypt_rn.3
diff --git a/crypt.5 b/crypt.5
index 5db9c92..7fe4609 100644
--- a/crypt.5
+++ b/crypt.5
@@ -279,6 +279,8 @@ 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_r (3),
+.BR crypt_ra (3),
.BR crypt_rn (3),
.BR crypt_gensalt (3),
.BR getpwent (3),
diff --git a/crypt_gensalt.3 b/crypt_gensalt.3
index ebfff28..3109740 100644
--- a/crypt_gensalt.3
+++ b/crypt_gensalt.3
@@ -223,6 +223,8 @@ T} Thread safety MT-Safe
.SH SEE ALSO
.ad l
.BR crypt (3),
+.BR crypt_r (3),
+.BR crypt_ra (3),
.BR crypt_rn (3),
.BR getpass (3),
.BR getpwent (3),
diff --git a/crypt_r.3 b/crypt_r.3
new file mode 100644
index 0000000..430e48f
--- /dev/null
+++ b/crypt_r.3
@@ -0,0 +1 @@
+.so man3/crypt_rn.3
diff --git a/crypt_ra.3 b/crypt_ra.3
new file mode 100644
index 0000000..430e48f
--- /dev/null
+++ b/crypt_ra.3
@@ -0,0 +1 @@
+.so man3/crypt_rn.3
From 6679d3427645da43140e5c5297f46985590b8e08 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= <besser82@fedoraproject.org>
Date: Sat, 4 Aug 2018 20:45:42 +0200
Subject: [PATCH 09/10] Update NEWS.
---
NEWS | 1 +
1 file changed, 1 insertion(+)
diff --git a/NEWS b/NEWS
index 8acf032..7e1d526 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Version 4.1.2
* Add optional 'check-valgrind' target to the Makefile.
* Replace crypt-sha{256,512}.c with an implementation in the Public
Domain.
+* Add alias man-pages for other crypt functions.
Version 4.1.1
* --enable-hashes now supports additional groups of hashing methods:
From 8596e298f761c32cecff45424f5242cd14269292 Mon Sep 17 00:00:00 2001
From: Zack Weinberg <zackw@panix.com>
Date: Tue, 7 Aug 2018 21:35:12 -0400
Subject: [PATCH 10/10] Add configure option --disable-failure-tokens.
When this option is given, crypt and crypt_r will return NULL on
failure, instead of a special "failure token" string that isn't the
hash of any passphrase. This was the historical behavior of glibc,
FreeBSD libc, and several other implementations.
---
NEWS | 8 ++++++
configure.ac | 20 +++++++++++++
crypt.c | 4 +++
crypt_rn.3 | 35 +++++++++++++----------
test-badsalt.c | 18 +++++++++++-
test-crypt-badargs.c | 68 +++++++++++++++++++++++++-------------------
test-crypt-bcrypt.c | 6 +++-
7 files changed, 112 insertions(+), 47 deletions(-)
diff --git a/NEWS b/NEWS
index 7e1d526..de91957 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,14 @@ Version 4.1.2
* Replace crypt-sha{256,512}.c with an implementation in the Public
Domain.
* Add alias man-pages for other crypt functions.
+* Add configure option --disable-failure-tokens, which causes crypt
+ and crypt_r to return NULL on failure, as crypt_rn and crypt_ra do,
+ instead of a special "failure token". Using this option improves
+ compatibility with programs written on the assumption that, like
+ most C library functions, crypt and crypt_r will return NULL on
+ failure; but it breaks compatibility with programs that assume these
+ functions never return NULL. We're not sure which type of program
+ is more common. Please let us know if you encounter either.
Version 4.1.1
* --enable-hashes now supports additional groups of hashing methods:
diff --git a/configure.ac b/configure.ac
index 9ea30f6..84d3ad9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,6 +162,26 @@ AX_VALGRIND_DFLT([sgcheck], [off])
AX_VALGRIND_CHECK()
# Configure options.
+AC_ARG_ENABLE([failure-tokens],
+ AS_HELP_STRING(
+ [--disable-failure-tokens],
+ [Make crypt and crypt_r return NULL on failure, instead of a
+ special "failure token" string that isn't the hash of any
+ passphrase. This matches the behavior of several other
+ crypt implementations, but will break programs that assume these
+ functions never return NULL. crypt_rn and crypt_ra are not affected
+ by this option, and will always return NULL on failure.]
+ ),
+ [case "$enableval" in
+ yes) enable_failure_tokens=1;;
+ no) enable_failure_tokens=0;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-failure-tokens]);;
+ esac],
+ [enable_failure_tokens=1])
+AC_DEFINE_UNQUOTED([ENABLE_FAILURE_TOKENS], [$enable_failure_tokens],
+ [Define to 1 if crypt and crypt_r should return a "failure token" on
+ failure, or 0 if they should return NULL.])
+
AC_ARG_ENABLE([obsolete-api],
AS_HELP_STRING(
[--enable-obsolete-api[=ARG]],
diff --git a/crypt.c b/crypt.c
index 9a3e192..839763a 100644
--- a/crypt.c
+++ b/crypt.c
@@ -235,7 +235,11 @@ crypt_r (const char *phrase, const char *setting, struct crypt_data *data)
{
make_failure_token (setting, data->output, sizeof data->output);
do_crypt (phrase, setting, data);
+#if ENABLE_FAILURE_TOKENS
return data->output;
+#else
+ return data->output[0] == '*' ? 0 : data->output;
+#endif
}
SYMVER_crypt_r;
#endif
diff --git a/crypt_rn.3 b/crypt_rn.3
index 24da44c..d021c4e 100644
--- a/crypt_rn.3
+++ b/crypt_rn.3
@@ -204,17 +204,31 @@ multiple threads simultaneously, as long as a separate
object is used for each thread.
.PP
Upon error,
-.B crypt
-and
-.B crypt_r
-return a pointer to an
+.BR crypt_r ", " crypt_rn ", and " crypt_ra
+write an
.I invalid
-hashed passphrase.
+hashed passphrase to the
+.I output
+field of their
+.I crypt_data
+object, and
+.B crypt
+writes an invalid hash to its static storage area.
This string will be shorter than 13 characters,
will begin with a \(oq\fB*\fR\(cq,
and will not compare equal to
.IR setting .
-(This peculiar behavior is for compatibility
+.PP
+Upon error,
+.BR crypt_rn " and " crypt_ra
+return a null pointer.
+.BR crypt_r " and " crypt
+may also return a null pointer,
+or they may return a pointer to the invalid hash,
+depending on how
+.I libcrypt
+was configured.
+(The option to return the invalid hash is for compatibility
with old applications that assume that
.B crypt
cannot return a null pointer.
@@ -222,15 +236,6 @@ See
.B "PORTABILITY NOTES"
below.)
.PP
-.B crypt_rn
-and
-.B crypt_ra
-also write an invalid hashed passphrase to the
-.I output
-field of their
-.I crypt_data
-object when they fail, but they return a null pointer.
-.PP
All four functions set
.I errno
when they fail.
diff --git a/test-badsalt.c b/test-badsalt.c
index b274337..3d2e47a 100644
--- a/test-badsalt.c
+++ b/test-badsalt.c
@@ -222,12 +222,28 @@ 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 ENABLE_FAILURE_TOKENS
+ /* crypt/crypt_r never return null when failure tokens are enabled */
if (!retval)
{
printf ("FAIL: %s/%s/%s: returned NULL\n", label, setting, fn);
return false;
}
+#else
+ if (expected_to_succeed && !retval)
+ {
+ printf ("FAIL: %s/%s/%s: returned NULL\n", label, setting, fn);
+ return false;
+ }
+ else if (!expected_to_succeed && retval)
+ {
+ printf ("FAIL: %s/%s/%s: returned %p, should be NULL\n",
+ label, setting, fn, (const void *)retval);
+ return false;
+ }
+ else if (!expected_to_succeed && !retval)
+ return true;
+#endif
if (!check_results (label, fn, retval, setting,
expected_to_succeed))
return false;
diff --git a/test-crypt-badargs.c b/test-crypt-badargs.c
index 0e6af16..6be24a9 100644
--- a/test-crypt-badargs.c
+++ b/test-crypt-badargs.c
@@ -169,6 +169,14 @@ test_crypt_ra (const char *tag,
check (tag, expect, got);
}
+#if ENABLE_FAILURE_TOKENS
+# define FT0 "*0"
+# define FT1 "*1"
+#else
+# define FT0 0
+# define FT1 0
+#endif
+
/* PAGE should point to PAGESIZE bytes of read-write memory followed
by another PAGESIZE bytes of inaccessible memory. */
@@ -187,55 +195,55 @@ do_tests(char *page, size_t pagesize)
size_t i;
/* When SETTING is null, it shouldn't matter what PHRASE is. */
- expect_no_fault ("0.0.crypt", 0, 0, "*0", test_crypt);
- expect_no_fault ("0.0.crypt_r", 0, 0, "*0", test_crypt_r);
+ expect_no_fault ("0.0.crypt", 0, 0, FT0, test_crypt);
+ expect_no_fault ("0.0.crypt_r", 0, 0, FT0, test_crypt_r);
expect_no_fault ("0.0.crypt_rn", 0, 0, 0, test_crypt_rn);
expect_no_fault ("0.0.crypt_ra", 0, 0, 0, test_crypt_ra);
- expect_no_fault ("''.0.crypt", "", 0, "*0", test_crypt);
- expect_no_fault ("''.0.crypt_r", "", 0, "*0", test_crypt_r);
+ expect_no_fault ("''.0.crypt", "", 0, FT0, test_crypt);
+ expect_no_fault ("''.0.crypt_r", "", 0, FT0, test_crypt_r);
expect_no_fault ("''.0.crypt_rn", "", 0, 0, test_crypt_rn);
expect_no_fault ("''.0.crypt_ra", "", 0, 0, test_crypt_ra);
- expect_no_fault ("ph.0.crypt", phrase, 0, "*0", test_crypt);
- expect_no_fault ("ph.0.crypt_r", phrase, 0, "*0", test_crypt_r);
+ expect_no_fault ("ph.0.crypt", phrase, 0, FT0, test_crypt);
+ expect_no_fault ("ph.0.crypt_r", phrase, 0, FT0, test_crypt_r);
expect_no_fault ("ph.0.crypt_rn", phrase, 0, 0, test_crypt_rn);
expect_no_fault ("ph.0.crypt_ra", phrase, 0, 0, test_crypt_ra);
- expect_no_fault ("p1.0.crypt", p1, 0, "*0", test_crypt);
- expect_no_fault ("p1.0.crypt_r", p1, 0, "*0", test_crypt_r);
+ expect_no_fault ("p1.0.crypt", p1, 0, FT0, test_crypt);
+ expect_no_fault ("p1.0.crypt_r", p1, 0, FT0, test_crypt_r);
expect_no_fault ("p1.0.crypt_rn", p1, 0, 0, test_crypt_rn);
expect_no_fault ("p1.0.crypt_ra", p1, 0, 0, test_crypt_ra);
- expect_no_fault ("p2.0.crypt", p2, 0, "*0", test_crypt);
- expect_no_fault ("p2.0.crypt_r", p2, 0, "*0", test_crypt_r);
+ expect_no_fault ("p2.0.crypt", p2, 0, FT0, test_crypt);
+ expect_no_fault ("p2.0.crypt_r", p2, 0, FT0, test_crypt_r);
expect_no_fault ("p2.0.crypt_rn", p2, 0, 0, test_crypt_rn);
expect_no_fault ("p2.0.crypt_ra", p2, 0, 0, test_crypt_ra);
/* Conversely, when PHRASE is null,
it shouldn't matter what SETTING is... */
- expect_no_fault ("0.''.crypt", 0, "", "*0", test_crypt);
- expect_no_fault ("0.''.crypt_r", 0, "", "*0", test_crypt_r);
+ expect_no_fault ("0.''.crypt", 0, "", FT0, test_crypt);
+ expect_no_fault ("0.''.crypt_r", 0, "", FT0, test_crypt_r);
expect_no_fault ("0.''.crypt_rn", 0, "", 0, test_crypt_rn);
expect_no_fault ("0.''.crypt_ra", 0, "", 0, test_crypt_ra);
- expect_no_fault ("0.'*'.crypt", 0, "*", "*0", test_crypt);
- expect_no_fault ("0.'*'.crypt_r", 0, "*", "*0", test_crypt_r);
+ expect_no_fault ("0.'*'.crypt", 0, "*", FT0, test_crypt);
+ expect_no_fault ("0.'*'.crypt_r", 0, "*", FT0, test_crypt_r);
expect_no_fault ("0.'*'.crypt_rn", 0, "*", 0, test_crypt_rn);
expect_no_fault ("0.'*'.crypt_ra", 0, "*", 0, test_crypt_ra);
- expect_no_fault ("0.'*0'.crypt", 0, "*0", "*1", test_crypt);
- expect_no_fault ("0.'*0'.crypt_r", 0, "*0", "*1", test_crypt_r);
+ expect_no_fault ("0.'*0'.crypt", 0, "*0", FT1, test_crypt);
+ expect_no_fault ("0.'*0'.crypt_r", 0, "*0", FT1, test_crypt_r);
expect_no_fault ("0.'*0'.crypt_rn", 0, "*0", 0, test_crypt_rn);
expect_no_fault ("0.'*0'.crypt_ra", 0, "*0", 0, test_crypt_ra);
- expect_no_fault ("0.'*1'.crypt", 0, "*1", "*0", test_crypt);
- expect_no_fault ("0.'*1'.crypt_r", 0, "*1", "*0", test_crypt_r);
+ expect_no_fault ("0.'*1'.crypt", 0, "*1", FT0, test_crypt);
+ expect_no_fault ("0.'*1'.crypt_r", 0, "*1", FT0, test_crypt_r);
expect_no_fault ("0.'*1'.crypt_rn", 0, "*1", 0, test_crypt_rn);
expect_no_fault ("0.'*1'.crypt_ra", 0, "*1", 0, test_crypt_ra);
- expect_no_fault ("0.p1.crypt", 0, p1, "*0", test_crypt);
- expect_no_fault ("0.p1.crypt_r", 0, p1, "*0", test_crypt_r);
+ expect_no_fault ("0.p1.crypt", 0, p1, FT0, test_crypt);
+ expect_no_fault ("0.p1.crypt_r", 0, p1, FT0, test_crypt_r);
expect_no_fault ("0.p1.crypt_rn", 0, p1, 0, test_crypt_rn);
expect_no_fault ("0.p1.crypt_ra", 0, p1, 0, test_crypt_ra);
@@ -245,8 +253,8 @@ do_tests(char *page, size_t pagesize)
bug, but it's impractical to fix without breaking the property
that 'crypt' _never_ creates a failure token that is equal to the
setting string, which is more important than this corner case. */
- expect_a_fault ("0.p2.crypt", 0, p2, "*0", test_crypt);
- expect_a_fault ("0.p2.crypt_r", 0, p2, "*0", test_crypt_r);
+ expect_a_fault ("0.p2.crypt", 0, p2, FT0, test_crypt);
+ expect_a_fault ("0.p2.crypt_r", 0, p2, FT0, test_crypt_r);
expect_a_fault ("0.p2.crypt_rn", 0, p2, 0, test_crypt_rn);
expect_a_fault ("0.p2.crypt_ra", 0, p2, 0, test_crypt_ra);
@@ -257,9 +265,9 @@ do_tests(char *page, size_t pagesize)
strcpy (page, "p1.'");
strcat (page, settings[i]);
strcat (page, "'.crypt");
- expect_a_fault (page, p1, settings[i], "*0", test_crypt);
+ expect_a_fault (page, p1, settings[i], FT0, test_crypt);
strcat (page, "_r");
- expect_a_fault (page, p1, settings[i], "*0", test_crypt_r);
+ expect_a_fault (page, p1, settings[i], FT0, test_crypt_r);
strcat (page, "n");
expect_a_fault (page, p1, settings[i], 0, test_crypt_rn);
page [strlen (page) - 1] = 'a';
@@ -268,9 +276,9 @@ do_tests(char *page, size_t pagesize)
strcpy (page, "p2.'");
strcat (page, settings[i]);
strcat (page, "'.crypt");
- expect_a_fault (page, p2, settings[i], "*0", test_crypt);
+ expect_a_fault (page, p2, settings[i], FT0, test_crypt);
strcat (page, "_r");
- expect_a_fault (page, p2, settings[i], "*0", test_crypt_r);
+ expect_a_fault (page, p2, settings[i], FT0, test_crypt_r);
strcat (page, "n");
expect_a_fault (page, p2, settings[i], 0, test_crypt_rn);
page [strlen (page) - 1] = 'a';
@@ -279,8 +287,8 @@ do_tests(char *page, size_t pagesize)
/* Conversely, when PHRASE is valid, passing an invalid string as SETTING
should crash reliably. */
- expect_a_fault ("ph.p2.crypt", phrase, p2, "*0", test_crypt);
- expect_a_fault ("ph.p2.crypt_r", phrase, p2, "*0", test_crypt_r);
+ expect_a_fault ("ph.p2.crypt", phrase, p2, FT0, test_crypt);
+ expect_a_fault ("ph.p2.crypt_r", phrase, p2, FT0, test_crypt_r);
expect_a_fault ("ph.p2.crypt_rn", phrase, p2, 0, test_crypt_rn);
expect_a_fault ("ph.p2.crypt_ra", phrase, p2, 0, test_crypt_ra);
@@ -292,9 +300,9 @@ do_tests(char *page, size_t pagesize)
strcpy (page, "ph.'");
strcat (page, settings[i]);
strcat (page, ".crypt");
- expect_a_fault (page, phrase, p1, "*0", test_crypt);
+ expect_a_fault (page, phrase, p1, FT0, test_crypt);
strcat (page, "_r");
- expect_a_fault (page, phrase, p1, "*0", test_crypt_r);
+ expect_a_fault (page, phrase, p1, FT0, test_crypt_r);
strcat (page, "n");
expect_a_fault (page, phrase, p1, 0, test_crypt_rn);
page [strlen (page) - 1] = 'a';
diff --git a/test-crypt-bcrypt.c b/test-crypt-bcrypt.c
index c984e4d..bf149b4 100644
--- a/test-crypt-bcrypt.c
+++ b/test-crypt-bcrypt.c
@@ -194,8 +194,12 @@ main (void)
errno = 0;
p = crypt (key, setting);
errnm = errno;
+#if ENABLE_FAILURE_TOKENS
match = strcmp (p, hash);
- if ((!ok && !errno) || strcmp (p, hash))
+#else
+ match = (ok ? strcmp (p, hash) : p != 0);
+#endif
+ if ((!ok && !errno) || match)
{
printf ("FAIL: %d/crypt.1: key=%s setting=%s: xhash=%s xerr=%d, "
"p=%s match=%d err=%s\n",