├── TODO ├── README ├── doc ├── crypt_r.3 ├── crypt_ra.3 ├── crypt_rn.3 ├── crypt_gensalt_ra.3 ├── crypt_gensalt_rn.3 ├── crypt_preferred_method.3 └── crypt_checksalt.3 ├── rpkg.conf ├── codecov.yml ├── .perltidyrc ├── lib ├── libxcrypt.pc.in ├── alg-sha1.h ├── util-base64.c ├── alg-gost3411-2012-core.h ├── alg-md4.h ├── alg-md5.h ├── crypt-static.c ├── crypt-gensalt-static.c ├── crypt-obsolete.h ├── util-make-failure-token.c ├── util-xstrcpy.c ├── alg-hmac-sha1.h ├── alg-sm3-hmac.h ├── alg-gost3411-2012-hmac.h ├── alg-sm3.h ├── util-xbzero.c ├── alg-gost3411-2012-ref.h ├── libcrypt.map.in ├── xcrypt.h.in ├── util-gensalt-sha.c ├── alg-gost3411-2012-hmac.c ├── alg-sha512.h ├── alg-des.h ├── hashes.conf ├── alg-yescrypt-platform.c ├── alg-sm3-hmac.c ├── alg-hmac-sha1.c ├── libcrypt.minver ├── alg-sha256.h ├── crypt-nthash.c ├── util-get-random-bytes.c └── crypt-yescrypt.c ├── THANKS ├── .packit.yaml ├── autogen.sh ├── test ├── compile-strong-alias.c ├── gensalt-bcrypt_x.c ├── alg-des.c ├── gensalt-nthash.c ├── symbols-static.pl ├── alg-gost3411-2012-hmac.c ├── alg-md4.c ├── alg-sha1.c ├── symbols-renames.pl ├── gensalt-nested-call.c ├── short-outbuf.c ├── alg-md5.c ├── alg-sha256.c ├── preferred-method.c ├── crypt-sm3-yescrypt.c ├── crypt-gost-yescrypt.c ├── symbols-compat.pl ├── crypt-too-long-phrase.c ├── crypt-nested-call.c ├── des-obsolete.c ├── des-obsolete_r.c ├── alg-sm3-hmac.c └── alg-sm3.c ├── AUTHORS ├── rpkg.macros ├── .gitignore ├── .github └── workflows │ ├── distcheck.yml │ ├── codeql.yml │ ├── codecov.yml │ ├── memcheck.yml │ └── config-matrix.yml └── TODO.md /TODO: -------------------------------------------------------------------------------- 1 | TODO.md -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /doc/crypt_r.3: -------------------------------------------------------------------------------- 1 | .so man3/crypt.3 2 | -------------------------------------------------------------------------------- /doc/crypt_ra.3: -------------------------------------------------------------------------------- 1 | .so man3/crypt.3 2 | -------------------------------------------------------------------------------- /doc/crypt_rn.3: -------------------------------------------------------------------------------- 1 | .so man3/crypt.3 2 | -------------------------------------------------------------------------------- /doc/crypt_gensalt_ra.3: -------------------------------------------------------------------------------- 1 | .so man3/crypt_gensalt.3 2 | -------------------------------------------------------------------------------- /doc/crypt_gensalt_rn.3: -------------------------------------------------------------------------------- 1 | .so man3/crypt_gensalt.3 2 | -------------------------------------------------------------------------------- /rpkg.conf: -------------------------------------------------------------------------------- 1 | [rpkg] 2 | user_macros = "${git_props:root}/rpkg.macros" 3 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "lib/gen-des-tables.c" 3 | - "test" 4 | - "/usr/**/*" 5 | -------------------------------------------------------------------------------- /.perltidyrc: -------------------------------------------------------------------------------- 1 | # perltidy configuration 2 | 3 | --standard-error-output 4 | --warning-output 5 | --character-encoding=utf8 6 | --converge 7 | 8 | --continuation-indentation=4 9 | 10 | --cuddled-else 11 | --noblanks-before-comments 12 | --noblanks-before-blocks 13 | --paren-tightness=2 # no spaces inside parens 14 | --brace-tightness=2 # no spaces inside braces 15 | --square-bracket-tightness=2 # no spaces inside brackets 16 | -------------------------------------------------------------------------------- /lib/libxcrypt.pc.in: -------------------------------------------------------------------------------- 1 | ############################################# 2 | ##### Pkg-Config file for libxcrypt ##### 3 | ############################################# 4 | 5 | prefix=@prefix@ 6 | exec_prefix=${prefix} 7 | 8 | libdir=@libdir@ 9 | includedir=@includedir@ 10 | 11 | Name: @PACKAGE@ 12 | Version: @VERSION@ 13 | Description: Extended crypt library for DES, MD5, Blowfish and others 14 | Libs: -L${libdir} -lcrypt 15 | Cflags: -I${includedir} 16 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | As mentioned in the README, many people have contributed to the code 2 | making up libxcrypt, often under the aegis of a different project. Of 3 | the past contributors, we particularly wish to credit David Burren, 4 | Ulrich Drepper, Alec Muffett, Colin Percival, Alexey Degtyarev, and 5 | Thorsten Kukuk. 6 | 7 | As well as the present maintainers, active contributors to the library 8 | include Solar Designer, Dmitry V. Levin, and . 9 | 10 | We would also like to extend our thanks in advance to everyone who 11 | will, in the future, send us bug reports, suggestions, and contributions. 12 | 13 | -- The Authors. 14 | -------------------------------------------------------------------------------- /.packit.yaml: -------------------------------------------------------------------------------- 1 | specfile_path: libxcrypt.spec 2 | 3 | files_to_sync: 4 | - libxcrypt.spec 5 | - .packit.yaml 6 | 7 | upstream_package_name: libxcrypt 8 | upstream_project_url: https://github.com/besser82/libxcrypt 9 | upstream_tag_template: v{version} 10 | downstream_package_name: libxcrypt 11 | dist_git_namespace: rpms 12 | create_pr: True 13 | 14 | actions: 15 | post-upstream-clone: "wget https://src.fedoraproject.org/rpms/libxcrypt/raw/main/f/libxcrypt.spec -O libxcrypt.spec" 16 | post-modifications: "sed -i -e 's!%bcond_with bootstrap!%bcond_without bootstrap!g' -e 's!^Patch!#&!g' libxcrypt.spec" 17 | 18 | jobs: 19 | - job: upstream_koji_build 20 | trigger: commit 21 | metadata: 22 | branch: develop 23 | scratch: true 24 | targets: fedora-all 25 | 26 | - job: upstream_koji_build 27 | trigger: pull_request 28 | metadata: 29 | scratch: true 30 | targets: fedora-all 31 | 32 | - job: propose_downstream 33 | trigger: release 34 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (C) 2018 Björn Esser 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted. 7 | # 8 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 9 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 10 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 11 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 12 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 13 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 14 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 15 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 16 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 17 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 18 | # SUCH DAMAGE. 19 | 20 | set -efu 21 | LANG=C 22 | 23 | run_cmd() 24 | { 25 | echo "autogen: running: $@" 26 | "$@" 27 | } 28 | 29 | if [ -d .git ]; then 30 | run_cmd git clean -dfX 31 | fi 32 | 33 | run_cmd autoreconf -fiv -Wall,error 34 | -------------------------------------------------------------------------------- /lib/alg-sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an implementation of the National Institute of Standards 3 | * and Technology US Secure Hash Algorithm 1 (SHA1). 4 | * 5 | * Public api for steve reid's public domain SHA-1 implementation. 6 | * This file is in the public domain. 7 | */ 8 | 9 | #ifndef _CRYPT_ALG_SHA1_H 10 | #define _CRYPT_ALG_SHA1_H 1 11 | 12 | /* Structure to save state of computation between the single steps. */ 13 | struct sha1_ctx 14 | { 15 | uint32_t state[5]; 16 | uint32_t count[2]; 17 | uint8_t buffer[64]; 18 | }; 19 | 20 | /* Initialize structure containing state of computation. 21 | (RFC 3174, 6.1) */ 22 | extern void sha1_init_ctx (struct sha1_ctx *ctx); 23 | 24 | /* Starting with the result of former calls of this function (or the 25 | initialization function) update the context for the next LEN bytes 26 | starting at BUFFER. LEN does not need to be a multiple of 64. */ 27 | extern void sha1_process_bytes (const void *buffer, struct sha1_ctx *ctx, size_t size); 28 | 29 | /* Process the remaining bytes in the buffer and write the finalized 30 | hash to RESBUF, which should point to 20 bytes of storage. All 31 | data written to CTX is erased before returning from the function. */ 32 | extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /lib/util-base64.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-2021 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | /* Base64-related utility functions and data. */ 20 | 21 | #include "crypt-port.h" 22 | 23 | const unsigned char ascii64[65] = 24 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 25 | /* 0000000000111111111122222222223333333333444444444455555555556666 */ 26 | /* 0123456789012345678901234567890123456789012345678901234567890123 */ 27 | -------------------------------------------------------------------------------- /lib/alg-gost3411-2012-core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Alexey Degtyarev . 3 | * All rights reserved. 4 | * 5 | * $Id$ 6 | */ 7 | 8 | #ifndef _CRYPT_ALG_GOST3411_2012_CORE_H 9 | #define _CRYPT_ALG_GOST3411_2012_CORE_H 10 | 11 | #if defined __GOST3411_HAS_SSE41__ 12 | #include "alg-gost3411-2012-sse41.h" 13 | #elif defined __GOST3411_HAS_SSE2__ 14 | #include "alg-gost3411-2012-sse2.h" 15 | #elif defined __GOST3411_HAS_MMX__ 16 | #include "alg-gost3411-2012-mmx.h" 17 | #else 18 | #include "alg-gost3411-2012-ref.h" 19 | #endif 20 | 21 | typedef union uint512_u 22 | { 23 | unsigned long long QWORD[8]; 24 | } uint512_u; 25 | 26 | #include "alg-gost3411-2012-const.h" 27 | #include "alg-gost3411-2012-precalc.h" 28 | 29 | typedef struct GOST34112012Context 30 | { 31 | unsigned char buffer[64]; 32 | uint512_u hash; 33 | uint512_u h; 34 | uint512_u N; 35 | uint512_u Sigma; 36 | size_t bufsize; 37 | unsigned int digest_size; 38 | } GOST34112012Context; 39 | 40 | extern void GOST34112012Init(GOST34112012Context *CTX, 41 | const unsigned int digest_size); 42 | 43 | extern void GOST34112012Update(GOST34112012Context *CTX, 44 | const unsigned char *data, size_t len); 45 | 46 | extern void GOST34112012Final(GOST34112012Context *CTX, 47 | unsigned char *digest); 48 | 49 | extern void GOST34112012Cleanup(GOST34112012Context *CTX); 50 | 51 | #endif /* alg-gost3411-2012-core.h */ 52 | -------------------------------------------------------------------------------- /lib/alg-md4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. 3 | * MD4 Message-Digest Algorithm (RFC 1320). 4 | * 5 | * Homepage: 6 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 7 | * 8 | * Author: 9 | * Alexander Peslyak, better known as Solar Designer 10 | * 11 | * This software was written by Alexander Peslyak in 2001. No copyright is 12 | * claimed, and the software is hereby placed in the public domain. 13 | * In case this attempt to disclaim copyright and place the software in the 14 | * public domain is deemed null and void, then the software is 15 | * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the 16 | * general public under the following terms: 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted. 20 | * 21 | * There's ABSOLUTELY NO WARRANTY, express or implied. 22 | * 23 | * See md4.c for more information. 24 | */ 25 | 26 | #ifndef _CRYPT_ALG_MD4_H 27 | #define _CRYPT_ALG_MD4_H 1 28 | 29 | /* Any 32-bit or wider unsigned integer data type will do */ 30 | typedef uint32_t MD4_u32plus; 31 | 32 | typedef struct { 33 | MD4_u32plus lo, hi; 34 | MD4_u32plus a, b, c, d; 35 | uint8_t buffer[64]; 36 | MD4_u32plus block[16]; 37 | } MD4_CTX; 38 | 39 | extern void MD4_Init(MD4_CTX *ctx); 40 | extern void MD4_Update(MD4_CTX *ctx, const void *data, size_t size); 41 | extern void MD4_Final(uint8_t result[16], MD4_CTX *ctx); 42 | 43 | #endif /* alg-md4.h */ 44 | -------------------------------------------------------------------------------- /lib/alg-md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. 3 | * MD5 Message-Digest Algorithm (RFC 1321). 4 | * 5 | * Homepage: 6 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 7 | * 8 | * Author: 9 | * Alexander Peslyak, better known as Solar Designer 10 | * 11 | * This software was written by Alexander Peslyak in 2001. No copyright is 12 | * claimed, and the software is hereby placed in the public domain. 13 | * In case this attempt to disclaim copyright and place the software in the 14 | * public domain is deemed null and void, then the software is 15 | * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the 16 | * general public under the following terms: 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted. 20 | * 21 | * There's ABSOLUTELY NO WARRANTY, express or implied. 22 | * 23 | * See md5.c for more information. 24 | */ 25 | 26 | #ifndef _CRYPT_ALG_MD5_H 27 | #define _CRYPT_ALG_MD5_H 1 28 | 29 | /* Any 32-bit or wider unsigned integer data type will do */ 30 | typedef uint32_t MD5_u32plus; 31 | 32 | typedef struct { 33 | MD5_u32plus lo, hi; 34 | MD5_u32plus a, b, c, d; 35 | uint8_t buffer[64]; 36 | MD5_u32plus block[16]; 37 | } MD5_CTX; 38 | 39 | extern void MD5_Init(MD5_CTX *ctx); 40 | extern void MD5_Update(MD5_CTX *ctx, const void *data, size_t size); 41 | extern void MD5_Final(uint8_t result[16], MD5_CTX *ctx); 42 | 43 | #endif /* alg-md5.h */ 44 | -------------------------------------------------------------------------------- /lib/crypt-static.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2017 Thorsten Kukuk 2 | Copyright (C) 2019 Björn Esser 3 | 4 | This library is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Lesser General Public License 6 | as published by the Free Software Foundation; either version 2.1 of 7 | the License, or (at your option) any later version. 8 | 9 | This library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, see 16 | . */ 17 | 18 | #include "crypt-port.h" 19 | 20 | /* The functions that use global state objects are isolated in their 21 | own files so that a statically-linked program that doesn't use them 22 | will not have the state objects in its data segment. */ 23 | 24 | #if INCLUDE_crypt 25 | char * 26 | crypt (const char *key, const char *setting) 27 | { 28 | static struct crypt_data nr_crypt_ctx; 29 | return crypt_r (key, setting, &nr_crypt_ctx); 30 | } 31 | SYMVER_crypt; 32 | #endif 33 | 34 | /* For code compatibility with old glibc. */ 35 | #if INCLUDE_fcrypt 36 | strong_alias (crypt, fcrypt); 37 | SYMVER_fcrypt; 38 | #endif 39 | 40 | /* For code compatibility with older versions (v3.1.1 and earlier). */ 41 | #if INCLUDE_crypt && INCLUDE_xcrypt 42 | strong_alias (crypt, xcrypt); 43 | SYMVER_xcrypt; 44 | #endif 45 | -------------------------------------------------------------------------------- /lib/crypt-gensalt-static.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2017 Thorsten Kukuk 2 | 3 | This library is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU Lesser General Public License 5 | as published by the Free Software Foundation; either version 2.1 of 6 | the License, or (at your option) any later version. 7 | 8 | This library is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public 14 | License along with this library; if not, see 15 | . */ 16 | 17 | #include "crypt-port.h" 18 | 19 | /* The functions that use global state objects are isolated in their 20 | own files so that a statically-linked program that doesn't use them 21 | will not have the state objects in its data segment. */ 22 | 23 | #if INCLUDE_crypt_gensalt 24 | char * 25 | crypt_gensalt (const char *prefix, unsigned long count, 26 | const char *rbytes, int nrbytes) 27 | { 28 | static char output[CRYPT_GENSALT_OUTPUT_SIZE]; 29 | 30 | return crypt_gensalt_rn (prefix, count, 31 | rbytes, nrbytes, output, sizeof (output)); 32 | } 33 | SYMVER_crypt_gensalt; 34 | #endif 35 | 36 | /* For code compatibility with older versions (v3.1.1 and earlier). */ 37 | #if INCLUDE_crypt_gensalt && INCLUDE_xcrypt_gensalt 38 | strong_alias (crypt_gensalt, xcrypt_gensalt); 39 | SYMVER_xcrypt_gensalt; 40 | #endif 41 | -------------------------------------------------------------------------------- /test/compile-strong-alias.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | /* Simple compile test for our macro definition of strong_alias(). 20 | The sole purpose of this test is the fact some platforms do not 21 | support strong aliases, some don't support aliases at all. 22 | We test it just in case we may need this macro on those platforms 23 | some time in the future. */ 24 | 25 | #include "crypt-port.h" 26 | 27 | /* Prototype */ 28 | int addition (int, int); 29 | 30 | int addition (int a, int b) 31 | { 32 | return a + b; 33 | } 34 | strong_alias (addition, add); 35 | 36 | int 37 | main (void) 38 | { 39 | int a = 1; 40 | int b = -1; 41 | 42 | return add (a, b); 43 | } 44 | -------------------------------------------------------------------------------- /lib/crypt-obsolete.h: -------------------------------------------------------------------------------- 1 | /* Prototypes for obsolete functions in libcrypt. 2 | 3 | Copyright (C) 1991-2017 Free Software Foundation, Inc. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public License 7 | as published by the Free Software Foundation; either version 2.1 of 8 | the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, see 17 | . */ 18 | 19 | #ifndef _CRYPT_OBSOLETE_H 20 | #define _CRYPT_OBSOLETE_H 1 21 | 22 | /* These API functions are obsolete and provided for binary backward 23 | compatibility only. New programs cannot be linked against them, 24 | and we do not install this header, but we still need it to build the 25 | library itself. */ 26 | 27 | /* Prepare to encrypt or decrypt data with DES, using KEY. */ 28 | extern void setkey (const char *key); 29 | 30 | extern void setkey_r (const char *key, 31 | struct crypt_data *restrict data); 32 | 33 | /* Encrypt data in BLOCK in place if EDFLAG is zero; otherwise decrypt 34 | block in place. */ 35 | extern void encrypt (char *block, int edflag); 36 | 37 | extern void encrypt_r (char *block, int edflag, 38 | struct crypt_data *restrict data); 39 | 40 | #endif /* crypt-obsolete.h */ 41 | -------------------------------------------------------------------------------- /test/gensalt-bcrypt_x.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2025 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | #if INCLUDE_bcrypt_x 22 | 23 | #include 24 | #include 25 | 26 | int 27 | main (void) 28 | { 29 | char *retval; 30 | 31 | errno = 0; 32 | retval = crypt_gensalt ("$2x$", 0, NULL, 0); 33 | 34 | if (retval || errno != EINVAL) 35 | { 36 | fprintf (stderr, "gensalt: expected \"NULL\", got \"%s\" " 37 | "with errno == %i, instead of %i.\n", 38 | retval ? retval : "NULL", errno, EINVAL); 39 | 40 | return 1; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | #else 47 | 48 | int 49 | main (void) 50 | { 51 | return 77; /* UNSUPPORTED */ 52 | } 53 | 54 | #endif /* INCLUDE_bcrypt_x */ 55 | -------------------------------------------------------------------------------- /lib/util-make-failure-token.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-2019 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | /* Fill the output buffer with a failure token. */ 22 | void 23 | make_failure_token (const char *setting, char *output, int size) 24 | { 25 | if (size >= 3) 26 | { 27 | char token[3] = "*0"; 28 | 29 | if (setting && setting[0] == '*' && setting[1] == '0') 30 | token[1] = '1'; 31 | 32 | output[0] = token[0]; 33 | output[1] = token[1]; 34 | output[2] = '\0'; 35 | } 36 | 37 | /* If there's not enough space for the full failure token, do the 38 | best we can. */ 39 | else if (size == 2) 40 | { 41 | output[0] = '*'; 42 | output[1] = '\0'; 43 | } 44 | else if (size == 1) 45 | { 46 | output[0] = '\0'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/util-xstrcpy.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-2019 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | /* Simple commonly used helper functions. */ 20 | 21 | #include "crypt-port.h" 22 | 23 | #include 24 | 25 | /* Provide a safe way to copy strings with the guarantee src, 26 | including its terminating '\0', will fit d_size bytes. 27 | The trailing bytes of d_size will be filled with '\0'. 28 | dst and src must not be NULL. Returns strlen (src). */ 29 | size_t 30 | strcpy_or_abort (void *dst, size_t d_size, const void *src) 31 | { 32 | assert (dst != NULL); 33 | assert (src != NULL); 34 | size_t s_size = strlen ((const char *)src); 35 | assert (d_size > s_size); 36 | if (!(d_size > s_size)) /* for NDEBUG builds */ 37 | abort(); 38 | 39 | memcpy (dst, src, s_size); 40 | memset (((char *)dst) + s_size, 0, d_size - s_size); 41 | return s_size; 42 | } 43 | -------------------------------------------------------------------------------- /lib/alg-hmac-sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Björn Esser 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /* Generate the keyed-hash message authentication code of TEXT and KEY. 30 | The resulting HMAC is written into RESBUF, which should point to 20 31 | bytes of storage. */ 32 | extern void 33 | hmac_sha1_process_data (const uint8_t *text, size_t text_len, 34 | const uint8_t *key, size_t key_len, 35 | void *resbuf); 36 | -------------------------------------------------------------------------------- /lib/alg-sm3-hmac.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2024 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #ifndef _CRYPT_ALG_SM3_HMAC_H 20 | #define _CRYPT_ALG_SM3_HMAC_H 21 | 22 | #include "alg-sm3.h" 23 | 24 | typedef struct 25 | { 26 | sm3_ctx sm3_ctx; 27 | uint8_t key[64]; 28 | } sm3_hmac_ctx_t; 29 | 30 | void sm3_hmac_init (sm3_hmac_ctx_t * ctx, const uint8_t * key, 31 | size_t key_len); 32 | void sm3_hmac_update (sm3_hmac_ctx_t * ctx, const uint8_t * data, 33 | size_t data_len); 34 | void sm3_hmac_final (sm3_hmac_ctx_t * ctx, uint8_t mac[32]); 35 | void sm3_hmac (const uint8_t * data, size_t data_len, 36 | const uint8_t * key, size_t key_len, 37 | uint8_t mac[32], sm3_hmac_ctx_t * ctx); 38 | void sm3_hmac_buf (const uint8_t * data, size_t data_len, 39 | const uint8_t * key, size_t key_len, 40 | uint8_t mac[32]); 41 | 42 | #endif /* _CRYPT_ALG_SM3_HMAC_H */ 43 | -------------------------------------------------------------------------------- /doc/crypt_preferred_method.3: -------------------------------------------------------------------------------- 1 | .\" Written by Björn Esser in 2018. 2 | .\" 3 | .\" To the extent possible under law, the authors have waived 4 | .\" all copyright and related or neighboring rights to this work. 5 | .\" See https://creativecommons.org/publicdomain/zero/1.0/ for further 6 | .\" details. 7 | .\" 8 | .Dd November 16, 2018 9 | .Dt CRYPT_PREFERRED_METHOD 3 10 | .Os libxcrypt 11 | .Sh NAME 12 | .Nm crypt_preferred_method 13 | .Nd get the prefix of the preferred hash method 14 | .Sh LIBRARY 15 | .Lb libcrypt 16 | .Sh SYNOPSIS 17 | .In crypt.h 18 | .Ft const char* 19 | .Fo crypt_preferred_method 20 | .Fa void 21 | .Fc 22 | .Sh DESCRIPTION 23 | .Nm 24 | is a convenience function to get the prefix of the preferred hash 25 | method. If a preferred method is available, 26 | it is the same as the one also used by the 27 | .Nm crypt_gensalt functions , 28 | if their given 29 | .Ar prefix 30 | parameter is NULL. 31 | .Sh RETURN VALUES 32 | The string returned equals the prefix of the preferred hash method. 33 | If no preferred hash method is available it is NULL. 34 | It 35 | .Em is 36 | safe to pass the string returned by 37 | .Nm crypt_preferred_method 38 | directly to 39 | .Nm crypt_gensalt 40 | without prior string-sanitizing nor NULL-pointer checks. 41 | .Sh FEATURE TEST MACROS 42 | .In crypt.h 43 | will define the macro 44 | .Dv CRYPT_PREFERRED_METHOD_AVAILABLE 45 | if 46 | .Nm 47 | is available in the current version of libxcrypt. 48 | .Sh PORTABILITY NOTES 49 | The function 50 | .Nm 51 | is not part of any standard. 52 | It was added to libxcrypt in version 4.4.0. 53 | .Sh ATTRIBUTES 54 | For an explanation of the terms used in this section, 55 | see 56 | .Xr attributes 7 . 57 | .TS 58 | allbox; 59 | lb lb lb 60 | lw(22n) l l. 61 | Interface Attribute Value 62 | T{ 63 | .Nm 64 | T} Thread safety MT-Safe 65 | .TE 66 | .sp 67 | .Sh SEE ALSO 68 | .Xr crypt_gensalt 3 69 | -------------------------------------------------------------------------------- /test/alg-des.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This crypt(3) validation program shipped with UFC-crypt 3 | * is derived from one distributed with Phil Karns PD DES package. 4 | * 5 | * @(#)cert.c 1.8 11 Aug 1996 6 | */ 7 | 8 | #include "crypt-port.h" 9 | #include "alg-des.h" 10 | #include "des-cases.h" 11 | 12 | #include 13 | 14 | #if INCLUDE_descrypt || INCLUDE_bsdicrypt || INCLUDE_bigcrypt 15 | 16 | static void 17 | v_print (const unsigned char v[8]) 18 | { 19 | for (int i = 0; i < 8; i++) 20 | printf ("%02x", (unsigned int)v[i]); 21 | } 22 | 23 | static void 24 | report_failure (size_t n, bool decrypt, 25 | const struct des_testcase *tc, const unsigned char got[8]) 26 | { 27 | printf ("FAIL: %zu/%s: k=", n, decrypt ? "de" : "en"); 28 | v_print (tc->key); 29 | fputs (" exp ", stdout); 30 | if (decrypt) 31 | v_print (tc->plain); 32 | else 33 | v_print (tc->answer); 34 | fputs (" got ", stdout); 35 | v_print (got); 36 | putchar ('\n'); 37 | } 38 | 39 | int 40 | main (void) 41 | { 42 | struct des_ctx ctx; 43 | const struct des_testcase *tc; 44 | unsigned char got[8]; 45 | size_t t; 46 | int status = 0; 47 | 48 | des_set_salt (&ctx, 0); 49 | 50 | for (t = 0; t < N_DES_TESTCASES; t++) 51 | { 52 | tc = &des_testcases[t]; 53 | des_set_key (&ctx, tc->key); 54 | des_crypt_block (&ctx, got, tc->plain, 0, false); 55 | if (memcmp (got, tc->answer, 8) != 0) 56 | { 57 | status = 1; 58 | report_failure (t, false, tc, got); 59 | } 60 | 61 | des_crypt_block (&ctx, got, tc->answer, 0, true); 62 | if (memcmp (got, tc->plain, 8) != 0) 63 | { 64 | status = 1; 65 | report_failure (t, true, tc, got); 66 | } 67 | } 68 | 69 | return status; 70 | } 71 | 72 | #else 73 | 74 | int 75 | main (void) 76 | { 77 | return 77; /* UNSUPPORTED */ 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The yescrypt code comes from yescrypt by Solar Designer . It builds upon Colin Percival's scrypt. 3 | See: http://openwall.com/yescrypt/ for reference. 4 | 5 | The bcrypt hash module comes from crypt_blowfish, originally written 6 | by Solar Designer and based on algorithms and 7 | ideas by Niels Provos and David Mazieres 8 | . 9 | 10 | The MD5, SHA256, and SHA512 hash modules, and the underlying 11 | secure-hash primitives, were originally written by Ulrich Drepper 12 | as part of the GNU C Library. Other people 13 | may also have contributed to them; our records are incomplete. 14 | 15 | The DES hash module was originally FreeSec, written by David Burren 16 | for the NetBSD project, and since extensively 17 | modified by Geoffrey M. Rehmet, Mark R V Murray, and Zack Weinberg. 18 | 19 | The NTHASH module comes from FreeBSD, originally written by Michael 20 | Bretterklieber and based on the password hashing algorithm used by 21 | the Windows NT LAN Manager (NTLM) from Microsoft Corporation to 22 | provide easier compatibility with NT accounts. 23 | 24 | The SUNMD5 hash module is a clean-room reimplementation by Zack Weinberg, 25 | based on a specification written by Eli Collins for the Passlib project, 26 | of an algorithm originally developed by Alec Muffett for use in Solaris 9. 27 | 28 | The crypt and gensalt backends for yescrypt and gost-yescrypt are by 29 | Vitaly Chikunov. 30 | 31 | The implementation of the public interface (crypt, crypt_r, etc) is a 32 | mashup of code from the GNU C Library with code from crypt_blowfish, 33 | originally put together by Thorsten Kukuk and since completely 34 | rewritten by Björn Esser and Zack Weinberg. 35 | 36 | The above components were assembled into this library by Thorsten Kukuk 37 | , Björn Esser , and 38 | Zack Weinberg . 39 | -------------------------------------------------------------------------------- /lib/alg-gost3411-2012-hmac.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * Copyright (C) 2018 Björn Esser 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 8 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 11 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 14 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 16 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 17 | * SUCH DAMAGE. 18 | */ 19 | 20 | #ifndef _CRYPT_ALG_GOST3411_2012_HMAC_H 21 | #define _CRYPT_ALG_GOST3411_2012_HMAC_H 22 | 23 | #include "alg-gost3411-2012-core.h" 24 | 25 | /* Constants for HMAC_GOSTR3411_2012_256 */ 26 | #define GOSTR3411_2012_L 32 /* hash output len */ 27 | #define GOSTR3411_2012_B 64 /* hash input len (512) */ 28 | #define GOSTR3411_2012_BITS GOSTR3411_2012_L * 8 /* 256 */ 29 | 30 | typedef struct 31 | { 32 | GOST34112012Context ctx; 33 | unsigned char pad[GOSTR3411_2012_B]; /* ipad and opad */ 34 | unsigned char kstar[GOSTR3411_2012_B]; /* derived key */ 35 | unsigned char digest[GOSTR3411_2012_L]; 36 | } gost_hmac_256_t; 37 | 38 | extern void 39 | gost_hash256 (const uint8_t *t, size_t n, uint8_t *out32, 40 | GOST34112012Context *ctx); 41 | 42 | extern void 43 | gost_hmac256 (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 44 | uint8_t *out32, gost_hmac_256_t *gostbuf); 45 | 46 | #endif /* alg-gost3411-2012-hmac.h */ 47 | -------------------------------------------------------------------------------- /lib/alg-sm3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Björn Esser 3 | * All rights reserved. 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted. 7 | * 8 | * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef _CRYPT_ALG_SM3_H 18 | #define _CRYPT_ALG_SM3_H 19 | 20 | #include "crypt-port.h" 21 | 22 | #include 23 | 24 | /* Context structure for SM3 operations. */ 25 | typedef struct 26 | { 27 | uint32_t state[8]; 28 | uint64_t count; 29 | uint8_t buf[64]; 30 | } sm3_ctx; 31 | 32 | /** 33 | * sm3_init(ctx): 34 | * Initialize the SM3 context ${ctx}. 35 | */ 36 | extern void sm3_init(sm3_ctx *); 37 | 38 | /** 39 | * sm3_update(ctx, in, len): 40 | * Input ${len} bytes from ${in} into the SM3 context ${ctx}. 41 | */ 42 | extern void sm3_update(sm3_ctx *, const void *, size_t); 43 | 44 | /** 45 | * sm3_final(digest, ctx): 46 | * Output the SM3 hash of the data input to the context ${ctx} into the 47 | * buffer ${digest}. 48 | */ 49 | extern void sm3_final(uint8_t[32], sm3_ctx *); 50 | 51 | /** 52 | * sm3_hash(in, len, digest, ctx): 53 | * Compute the SM3 hash of ${len} bytes from ${in} and write it to ${digest}, 54 | * using the prepared context ${ctx}. 55 | */ 56 | extern void sm3_hash(const void *, size_t, uint8_t[32], sm3_ctx *); 57 | 58 | /** 59 | * sm3_buf(in, len, digest): 60 | * Compute the SM3 hash of ${len} bytes from ${in} and write it to ${digest}. 61 | */ 62 | extern void sm3_buf(const void *, size_t, uint8_t[32]); 63 | #endif /* _CRYPT_ALG_SM3_H */ 64 | -------------------------------------------------------------------------------- /test/gensalt-nthash.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | #include 22 | 23 | #if INCLUDE_nt 24 | 25 | int 26 | main (void) 27 | { 28 | const char *prefix = "$3$"; 29 | const char *crypt_exp = "$3$$be8cb5d74036075bbe5344cb8ad248b0"; 30 | char output[CRYPT_GENSALT_OUTPUT_SIZE]; 31 | struct crypt_data cd; 32 | int retval = 0; 33 | 34 | crypt_gensalt_rn (prefix, 0, NULL, 0, 35 | output, CRYPT_GENSALT_OUTPUT_SIZE); 36 | 37 | if (strcmp (prefix, output)) 38 | retval = 1; 39 | 40 | fprintf (stderr, "%s: gensalt: expected \"%s\", got \"%s\"\n", 41 | retval == 0 ? "PASS" : "FAIL", prefix, output); 42 | 43 | if (retval != 0) 44 | return retval; 45 | 46 | crypt_r ("top secret", output, &cd); 47 | 48 | if (strcmp (crypt_exp, cd.output)) 49 | retval = 1; 50 | 51 | fprintf (stderr, "%s: crypt: expected \"%s\", got \"%s\"\n", 52 | retval == 0 ? "PASS" : "FAIL", crypt_exp, cd.output); 53 | 54 | return retval; 55 | } 56 | 57 | #else 58 | 59 | int 60 | main (void) 61 | { 62 | return 77; /* UNSUPPORTED */ 63 | } 64 | 65 | #endif /* INCLUDE_nt */ 66 | -------------------------------------------------------------------------------- /lib/util-xbzero.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018-2019 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | #if INCLUDE_explicit_bzero 22 | /* As long as this function is defined in a translation unit all by 23 | itself, and we aren't doing LTO, it would be enough for it to just 24 | call memset. While compiling _this_ translation unit, the compiler 25 | has no information about what the callers do with the buffer, so it 26 | cannot eliminate the memset. While compiling code that _calls_ 27 | this function, the compiler doesn't know what it does, so it cannot 28 | eliminate the call (if it has special knowledge of a function with 29 | this name, we would hope that it knows _not_ to optimize it out!) 30 | 31 | However, in anticipation of doing LTO on this library one day, we 32 | add two more defensive measures, when we know how: the function is 33 | marked no-inline, and there is a no-op assembly insert immediately 34 | after the memset call, declared to read the memory that the memset 35 | writes. */ 36 | 37 | NO_INLINE void 38 | explicit_bzero (void *s, size_t len) 39 | { 40 | s = memset (s, 0, len); 41 | asm volatile ("" : : "g" (s) : "memory"); 42 | } 43 | #endif 44 | -------------------------------------------------------------------------------- /lib/alg-gost3411-2012-ref.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Alexey Degtyarev . 3 | * All rights reserved. 4 | * 5 | * Portable and simple (thus sometimes slow) implementation of core functions. 6 | * 7 | * $Id$ 8 | */ 9 | 10 | #ifdef __GOST3411_HAS_SSE2__ 11 | #error "portable implementation disabled in config.h" 12 | #endif 13 | 14 | #ifdef __GOST3411_HAS_MMX__ 15 | #error "portable implementation disabled in config.h" 16 | #endif 17 | 18 | #define X(x, y, z) { \ 19 | z->QWORD[0] = x->QWORD[0] ^ y->QWORD[0]; \ 20 | z->QWORD[1] = x->QWORD[1] ^ y->QWORD[1]; \ 21 | z->QWORD[2] = x->QWORD[2] ^ y->QWORD[2]; \ 22 | z->QWORD[3] = x->QWORD[3] ^ y->QWORD[3]; \ 23 | z->QWORD[4] = x->QWORD[4] ^ y->QWORD[4]; \ 24 | z->QWORD[5] = x->QWORD[5] ^ y->QWORD[5]; \ 25 | z->QWORD[6] = x->QWORD[6] ^ y->QWORD[6]; \ 26 | z->QWORD[7] = x->QWORD[7] ^ y->QWORD[7]; \ 27 | } 28 | 29 | #ifndef __GOST3411_BIG_ENDIAN__ 30 | #define __XLPS_FOR for (_i = 0; _i <= 7; _i++) 31 | #define _datai _i 32 | #else 33 | #define __XLPS_FOR for (_i = 7; _i >= 0; _i--) 34 | #define _datai 7 - _i 35 | #endif 36 | 37 | #define XLPS(x, y, data) { \ 38 | register unsigned long long r0, r1, r2, r3, r4, r5, r6, r7; \ 39 | int _i; \ 40 | \ 41 | r0 = x->QWORD[0] ^ y->QWORD[0]; \ 42 | r1 = x->QWORD[1] ^ y->QWORD[1]; \ 43 | r2 = x->QWORD[2] ^ y->QWORD[2]; \ 44 | r3 = x->QWORD[3] ^ y->QWORD[3]; \ 45 | r4 = x->QWORD[4] ^ y->QWORD[4]; \ 46 | r5 = x->QWORD[5] ^ y->QWORD[5]; \ 47 | r6 = x->QWORD[6] ^ y->QWORD[6]; \ 48 | r7 = x->QWORD[7] ^ y->QWORD[7]; \ 49 | \ 50 | \ 51 | __XLPS_FOR \ 52 | {\ 53 | data->QWORD[_datai] = Ax[0][(r0 >> (_i << 3)) & 0xFF]; \ 54 | data->QWORD[_datai] ^= Ax[1][(r1 >> (_i << 3)) & 0xFF]; \ 55 | data->QWORD[_datai] ^= Ax[2][(r2 >> (_i << 3)) & 0xFF]; \ 56 | data->QWORD[_datai] ^= Ax[3][(r3 >> (_i << 3)) & 0xFF]; \ 57 | data->QWORD[_datai] ^= Ax[4][(r4 >> (_i << 3)) & 0xFF]; \ 58 | data->QWORD[_datai] ^= Ax[5][(r5 >> (_i << 3)) & 0xFF]; \ 59 | data->QWORD[_datai] ^= Ax[6][(r6 >> (_i << 3)) & 0xFF]; \ 60 | data->QWORD[_datai] ^= Ax[7][(r7 >> (_i << 3)) & 0xFF]; \ 61 | }\ 62 | } 63 | 64 | #define ROUND(i, Ki, data) { \ 65 | XLPS(Ki, (&C[i]), Ki); \ 66 | XLPS(Ki, data, data); \ 67 | } 68 | -------------------------------------------------------------------------------- /lib/libcrypt.map.in: -------------------------------------------------------------------------------- 1 | # This file is processed by gen-libcrypt-map to produce the versions 2 | # map file for libxcrypt. 3 | # symbol default_version compat_version [compat_version ...] 4 | 5 | # Actively supported POSIX interfaces; in GNU libc since 2.0 6 | crypt XCRYPT_2.0 GLIBC_2.0 7 | crypt_r XCRYPT_2.0 GLIBC_2.0 8 | 9 | # Actively supported Openwall extensions; never actually added to 10 | # upstream GNU libc, but present in at least Openwall, ALT, and SUSE 11 | # Linux distributions with one or more of these symbol versions 12 | crypt_rn XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt 13 | crypt_gensalt XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt OW_CRYPT_1.0:suse 14 | crypt_gensalt_rn XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.1:alt OW_CRYPT_1.0:suse 15 | 16 | crypt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt 17 | crypt_gensalt_ra XCRYPT_2.0 GLIBC_2.0:owl:suse GLIBC_2.2.2:alt OW_CRYPT_1.0:suse 18 | 19 | # Actively supported interfaces from libxcrypt. 20 | crypt_checksalt XCRYPT_4.3 21 | crypt_preferred_method XCRYPT_4.4 22 | 23 | # Interfaces for code compatibility with libxcrypt v3.1.1 and earlier. 24 | # No longer available to new binaries. Include in version-script, only 25 | # if one of the compatibility interfaces is enabled. 26 | crypt_gensalt_r - XCRYPT_2.0:alt:glibc:owl:suse:yes 27 | xcrypt - XCRYPT_2.0:alt:glibc:owl:suse:yes 28 | xcrypt_r - XCRYPT_2.0:alt:glibc:owl:suse:yes 29 | xcrypt_gensalt - XCRYPT_2.0:alt:glibc:owl:suse:yes 30 | xcrypt_gensalt_r - XCRYPT_2.0:alt:glibc:owl:suse:yes 31 | 32 | # Deprecated interfaces, POSIX and otherwise; also present in GNU libc 33 | # since 2.0 34 | encrypt - GLIBC_2.0 35 | encrypt_r - GLIBC_2.0 36 | setkey - GLIBC_2.0 37 | setkey_r - GLIBC_2.0 38 | fcrypt - GLIBC_2.0 39 | 40 | # This determines the ordering of the version chain. Each symbol 41 | # version that appears above must also appear in this list, and to 42 | # simplify gen-libcrypt-map, so must all of the versions listed in 43 | # libcrypt.minver. The ordering is left to right, top to bottom. 44 | %chain GLIBC_2.0 GLIBC_2.2 GLIBC_2.2.1 GLIBC_2.2.2 GLIBC_2.2.5 GLIBC_2.2.6 45 | %chain GLIBC_2.3 GLIBC_2.4 GLIBC_2.12 GLIBC_2.16 GLIBC_2.17 GLIBC_2.18 46 | %chain GLIBC_2.21 GLIBC_2.27 GLIBC_2.29 GLIBC_2.32 GLIBC_2.33 GLIBC_2.35 47 | %chain GLIBC_2.36 GLIBC_2.38 48 | %chain OW_CRYPT_1.0 XCRYPT_2.0 XCRYPT_4.3 XCRYPT_4.4 49 | -------------------------------------------------------------------------------- /lib/xcrypt.h.in: -------------------------------------------------------------------------------- 1 | /* libxcrypt interfaces for code compatibility. 2 | 3 | Copyright (C) 2018 Björn Esser 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted. 7 | 8 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 9 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 10 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 11 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 12 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 13 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 14 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 15 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 16 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 17 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 18 | SUCH DAMAGE. */ 19 | 20 | #ifndef _XCRYPT_H 21 | #define _XCRYPT_H 1 22 | 23 | #include 24 | 25 | @BEGIN_DECLS@ 26 | 27 | /* For backward compatibility with older versions (v3.1.1 and earlier) 28 | of libcrypt, this header declares xcrypt, xcrypt_r, xcrypt_gensalt, 29 | and xcrypt_gensalt_r as alternative names for crypt, crypt_r, 30 | crypt_gensalt, and crypt_gensalt_rn, respectively. If glibc's 31 | macro __REDIRECT_NTH (which declares an alternative 32 | name at the object-file level) is available, we use it. */ 33 | #ifdef __REDIRECT_NTH 34 | extern char * __REDIRECT_NTH (xcrypt, (const char *__phrase, 35 | const char *__setting), crypt); 36 | 37 | extern char * __REDIRECT_NTH (xcrypt_r, (const char *__phrase, 38 | const char *__setting, 39 | struct crypt_data *__restrict __data), crypt_r); 40 | 41 | extern char * __REDIRECT_NTH (xcrypt_gensalt, (const char *__prefix, 42 | unsigned long __count, const char *__rbytes, 43 | int __nrbytes), crypt_gensalt); 44 | 45 | extern char * __REDIRECT_NTH (xcrypt_gensalt_r, (const char *__prefix, 46 | unsigned long __count, const char *__rbytes, 47 | int __nrbytes, char *__output, 48 | int __output_size), crypt_gensalt_rn); 49 | #else 50 | # define xcrypt crypt 51 | # define xcrypt_r crypt_r 52 | # define xcrypt_gensalt crypt_gensalt 53 | # define xcrypt_gensalt_r crypt_gensalt_rn 54 | #endif 55 | 56 | @END_DECLS@ 57 | 58 | #endif /* xcrypt.h */ 59 | -------------------------------------------------------------------------------- /rpkg.macros: -------------------------------------------------------------------------------- 1 | function filter_tags { 2 | grep -E "^$1[^-]+$" 3 | } 4 | 5 | function latest_merged_tag { 6 | if [ "$LEGACY_GIT" ]; then 7 | git for-each-ref --sort=-v:refname refs/tags | cut -f2 | 8 | while read tag; do 9 | if [ -z "$(basename "$tag" | filter_tags "$1")" ]; then 10 | continue 11 | fi 12 | if [ "$(git merge-base "$tag" HEAD)"="$(git rev-parse "$tag"^{commit})" ]; then 13 | echo "$(basename "$tag")" 14 | return 15 | fi 16 | done 17 | else 18 | git tag --list --sort=-v:refname "$1*" --merged 2> /dev/null | filter_tags "$1" | head -n 1 19 | fi 20 | } 21 | 22 | function git_version { 23 | declare name="v" lead=0 follow= "$@" 24 | 25 | if [ -z "$name" ]; then 26 | log_error "name cannot be empty." 27 | return 1 28 | fi 29 | 30 | if echo "$lead.$follow" | grep -q '-'; then 31 | log_error "lead and follow cannot contain dashes." 32 | return 1 33 | fi 34 | 35 | if echo "$follow" | grep -q '\.'; then 36 | log_error "follow cannot contain dots." 37 | return 1 38 | fi 39 | 40 | latest_tag="$(latest_merged_tag "$name")" 41 | latest_tag_version="$(echo $latest_tag | sed -E -n "s/^$name([^-]+)$/\1/p")" 42 | 43 | if [ -n "$latest_tag" ]; then 44 | commit_count="$(git rev-list "$latest_tag"..HEAD | wc -l)" 45 | else 46 | commit_count="$(git rev-list HEAD 2> /dev/null | wc -l || printf 0)" 47 | fi 48 | 49 | if [ "$commit_count" -eq 0 ]; then 50 | commit_count_appendix= 51 | else 52 | commit_count_appendix=".git.$commit_count.$(git rev-parse --short HEAD)" 53 | fi 54 | 55 | latest_ctime="$(git_latest_ctime)" 56 | if [ "$latest_ctime" -eq 0 ]; then 57 | wtree_appendix= 58 | else 59 | wtree_appendix=".wtree.$(encode_decimal "$latest_ctime")" 60 | fi 61 | 62 | if [ -z "$follow" ]; then 63 | follow="$(echo "$latest_tag_version" | sed -E -n "s/^.*\.([^.]*)$/\1/p")" 64 | fi 65 | 66 | if [ "$lead" = 0 ]; then 67 | lead="$(echo "$latest_tag_version" | sed -E -n "s/\.$follow$//p")" 68 | fi 69 | 70 | follow=$((follow+1)) 71 | 72 | output "${lead}.${follow:-0}${commit_count_appendix}${wtree_appendix}" 73 | } 74 | 75 | function git_real_version { 76 | real_version="$(git_version "$@" | sed -e "s/\.git.*$//")" 77 | output "${real_version}" 78 | } 79 | 80 | function git_real_release { 81 | git_version > /dev/null 82 | commit_sha="$(echo ${commit_count_appendix} | sed -e "s/^.*\.//")" 83 | commit_count_no="$(echo ${commit_count_appendix} | sed -e "s/^\.git\.//")" 84 | commit_count_no="$(echo ${commit_count_no} | sed -e "s/\.${commit_sha}//")" 85 | output "${commit_count_no}.git${commit_sha}${wtree_appendix}" 86 | } 87 | -------------------------------------------------------------------------------- /test/symbols-static.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # Written by Zack Weinberg in 2017 and 2020. 3 | # To the extent possible under law, Zack Weinberg has waived all 4 | # copyright and related or neighboring rights to this work. 5 | # 6 | # See https://creativecommons.org/publicdomain/zero/1.0/ for further 7 | # details. 8 | 9 | # Test that all global symbols in the static version of the library 10 | # (libcrypt.a) are either listed as global and supported for new code 11 | # in libcrypt.map.in, or begin with a _crypt prefix. Also test that 12 | # all of the global, supported for new code, symbols mentioned in 13 | # libcrypt.map.in are in fact defined. 14 | # 15 | # Due to limitations in Automake, this program takes parameters from 16 | # the environment: 17 | # $lib_la - full pathname of libcrypt.la 18 | # $lib_map - full pathname of libcrypt.map.in 19 | # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C 20 | # $NM, $CPP, $CPPFLAGS - nm utility, C preprocessor, and parameters 21 | 22 | use v5.14; # implicit use strict, use feature ':5.14' 23 | use warnings FATAL => 'all'; 24 | use utf8; 25 | use open qw(:std :utf8); 26 | no if $] >= 5.022, warnings => 'experimental::re_strict'; 27 | use if $] >= 5.022, re => 'strict'; 28 | 29 | use FindBin (); 30 | use lib $FindBin::Bin; 31 | use TestCommon qw( 32 | error 33 | ensure_C_locale 34 | find_real_library 35 | get_symbols 36 | compare_symbol_lists 37 | ); 38 | 39 | my $symbol_prefix = $ENV{SYMBOL_PREFIX} || q{}; 40 | 41 | sub list_library_globals { 42 | # Symbols that begin with _crypt_ are private to the library. 43 | # Symbols that begin with _[_A-Y] are private to the C 44 | # implementation. All other symbols (including any that begin 45 | # with _Z, which are C++ mangled names) are part of the library's 46 | # public interface. 47 | return get_symbols( 48 | find_real_library(shift, 'static'), 49 | sub { $_[0] !~ /^_(?:[_A-Y]|crypt_)/ }, 50 | ); 51 | } 52 | 53 | sub list_expected_globals { 54 | my ($lib_map) = @_; 55 | open my $fh, '<', $lib_map 56 | or error("$lib_map: $!"); 57 | 58 | local $_; 59 | my %symbols; 60 | while (<$fh>) { 61 | chomp; 62 | s/\s+$//; 63 | next if /^($|#|%chain\b)/; 64 | 65 | my @fields = split; 66 | $symbols{$fields[0]} = 1 if $fields[1] ne '-'; 67 | } 68 | return \%symbols; 69 | } 70 | 71 | # 72 | # Main 73 | # 74 | my $lib_la = $ENV{lib_la} || '/nonexistent'; 75 | my $lib_map = $ENV{lib_map} || '/nonexistent'; 76 | if (!-f $lib_la || !-f $lib_map) { 77 | print {*STDERR} "usage: lib_la=/p/lib.la lib_map=/p/lib.map $0"; 78 | exit 1; 79 | } 80 | 81 | ensure_C_locale(); 82 | exit compare_symbol_lists( 83 | list_library_globals($lib_la), 84 | list_expected_globals($lib_map), 85 | 'globals', 86 | 0, # extra symbols not allowed 87 | ); 88 | -------------------------------------------------------------------------------- /lib/util-gensalt-sha.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Written by Solar Designer and placed in the public domain. 3 | * See crypt-bcrypt.c for more information. 4 | * 5 | * This file contains setting-string generation code shared among the 6 | * MD5, SHA256, and SHA512 hash algorithms, which use very similar 7 | * setting formats. Setting-string generation for bcrypt and DES is 8 | * entirely in crypt-bcrypt.c and crypt-des.c respectively. 9 | */ 10 | 11 | #include "crypt-port.h" 12 | 13 | #include 14 | #include 15 | 16 | #if INCLUDE_md5crypt || INCLUDE_sha256crypt || INCLUDE_sha512crypt || INCLUDE_sm3crypt 17 | 18 | void 19 | gensalt_sha_rn (const char *tag, size_t maxsalt, unsigned long defcount, 20 | unsigned long mincount, unsigned long maxcount, 21 | unsigned long count, 22 | const uint8_t *rbytes, size_t nrbytes, 23 | uint8_t *output, size_t output_size) 24 | { 25 | /* We will use more rbytes if available, but at least this much is 26 | required. */ 27 | if (nrbytes < 3) 28 | { 29 | errno = EINVAL; 30 | return; 31 | } 32 | 33 | if (count == 0) 34 | count = defcount; 35 | if (count < mincount) 36 | count = mincount; 37 | if (count > maxcount) 38 | count = maxcount; 39 | 40 | /* Compute how much space we need. */ 41 | size_t output_len = 8; /* $x$ssss\0 */ 42 | if (count != defcount) 43 | { 44 | output_len += 9; /* rounds=1$ */ 45 | for (unsigned long ceiling = 10; ceiling < count; ceiling *= 10) 46 | output_len += 1; 47 | } 48 | if (output_size < output_len) 49 | { 50 | errno = ERANGE; 51 | return; 52 | } 53 | 54 | size_t written; 55 | if (count == defcount) 56 | { 57 | written = (size_t) snprintf ((char *)output, output_size, "$%s$", tag); 58 | } 59 | else 60 | written = (size_t) snprintf ((char *)output, output_size, 61 | "$%s$rounds=%lu$", tag, count); 62 | 63 | /* The length calculation above should ensure that this is always true. */ 64 | assert (written + 5 < output_size); 65 | 66 | size_t used_rbytes = 0; 67 | while (written + 5 < output_size && 68 | used_rbytes + 3 < nrbytes && 69 | (used_rbytes * 4 / 3) < maxsalt) 70 | { 71 | unsigned long value = 72 | ((unsigned long) (unsigned char) rbytes[used_rbytes + 0] << 0) | 73 | ((unsigned long) (unsigned char) rbytes[used_rbytes + 1] << 8) | 74 | ((unsigned long) (unsigned char) rbytes[used_rbytes + 2] << 16); 75 | 76 | output[written + 0] = ascii64[value & 0x3f]; 77 | output[written + 1] = ascii64[(value >> 6) & 0x3f]; 78 | output[written + 2] = ascii64[(value >> 12) & 0x3f]; 79 | output[written + 3] = ascii64[(value >> 18) & 0x3f]; 80 | 81 | written += 4; 82 | used_rbytes += 3; 83 | } 84 | 85 | output[written] = '\0'; 86 | } 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /test/alg-gost3411-2012-hmac.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * Copyright (C) 2018 Björn Esser besser82@fedoraproject.org 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 8 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 11 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 14 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 16 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 17 | * SUCH DAMAGE. 18 | */ 19 | 20 | #include "crypt-port.h" 21 | 22 | #if INCLUDE_gost_yescrypt 23 | 24 | #include "alg-gost3411-2012-hmac.h" 25 | 26 | #include 27 | 28 | static void 29 | dumphex(const void *ptr, size_t size) 30 | { 31 | size_t i; 32 | 33 | for (i = 0; i < size; i++) 34 | printf("%02x", ((const unsigned char *)ptr)[i]); 35 | printf("\n"); 36 | } 37 | 38 | static int 39 | test_gost2012_hmac(const char *subject, const char *k, size_t ksize, 40 | const char *t, size_t tlen, const char *match) 41 | { 42 | uint8_t digest[32]; 43 | gost_hmac_256_t gostbuf; 44 | 45 | gost_hmac256((const uint8_t *)k, ksize, 46 | (const uint8_t *)t, tlen, digest, &gostbuf); 47 | 48 | if (memcmp(digest, match, sizeof(digest))) 49 | { 50 | fprintf(stderr, "ERROR: %s\n", subject); 51 | printf(" key: "); 52 | dumphex(k, ksize); 53 | printf(" t: "); 54 | dumphex(t, tlen); 55 | printf(" hmac="); 56 | dumphex(digest, sizeof(digest)); 57 | return 1; 58 | } 59 | else 60 | fprintf(stderr, " ok: %s\n", subject); 61 | 62 | return 0; 63 | } 64 | 65 | int 66 | main (void) 67 | { 68 | int result = 0; 69 | 70 | result |= test_gost2012_hmac( 71 | "HMAC_GOSTR3411_2012_256 test vector from P 50.1.113-2016", 72 | "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 73 | "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 32, 74 | "\x01\x26\xbd\xb8\x78\x00\xaf\x21\x43\x41\x45\x65\x63\x78\x01\x00", 16, 75 | "\xa1\xaa\x5f\x7d\xe4\x02\xd7\xb3\xd3\x23\xf2\x99\x1c\x8d\x45\x34" 76 | "\x01\x31\x37\x01\x0a\x83\x75\x4f\xd0\xaf\x6d\x7c\xd4\x92\x2e\xd9" 77 | ); 78 | 79 | return result; 80 | } 81 | 82 | #else 83 | 84 | int 85 | main (void) 86 | { 87 | return 77; /* UNSUPPORTED */ 88 | } 89 | 90 | #endif /* INCLUDE_gost_yescrypt */ 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # http://www.gnu.org/software/automake 2 | /Makefile 3 | /Makefile.deps 4 | /Makefile.in 5 | .deps/ 6 | .dirstamp 7 | .libs/ 8 | /INSTALL 9 | 10 | # http://www.gnu.org/software/autoconf 11 | /aclocal.m4 12 | /autom4te.cache 13 | /config.cache 14 | /config.h 15 | /config.h.in 16 | /config.log 17 | /config.status 18 | /configure 19 | /crypt.h.in 20 | /libtool 21 | /libxcrypt.pc 22 | /stamp-h1 23 | /build-aux/m4/libtool.m4 24 | /build-aux/m4/ltoptions.m4 25 | /build-aux/m4/ltsugar.m4 26 | /build-aux/m4/ltversion.m4 27 | /build-aux/m4/lt~obsolete.m4 28 | /build-aux/m4-autogen/* 29 | 30 | 31 | # compiler output 32 | *.gcda 33 | *.gcno 34 | *.la 35 | *.lo 36 | *.log 37 | *.o 38 | *.so 39 | *.trs 40 | *.T 41 | /crypt.h 42 | /crypt.h.stamp 43 | /crypt-hashes.h 44 | /crypt-hashes.h.stamp 45 | /crypt-symbol-vers.h 46 | /crypt-symbol-vers.h.stamp 47 | /libcrypt.map 48 | /libcrypt.map.stamp 49 | gen-des-tables 50 | test/alg-des 51 | test/alg-gost3411-2012 52 | test/alg-gost3411-2012-hmac 53 | test/alg-hmac-sha1 54 | test/alg-md4 55 | test/alg-md5 56 | test/alg-pbkdf-hmac-sha256 57 | test/alg-sha1 58 | test/alg-sha256 59 | test/alg-sha512 60 | test/alg-sm3 61 | test/alg-sm3-hmac 62 | test/alg-yescrypt 63 | test/badsalt 64 | test/badsetting 65 | test/bigcrypt 66 | test/byteorder 67 | test/checksalt 68 | test/compile-strong-alias 69 | test/crypt-badargs 70 | test/crypt-bcrypt 71 | test/crypt-des 72 | test/crypt-gost-yescrypt 73 | test/crypt-kat 74 | test/crypt-md5 75 | test/crypt-nested-call 76 | test/crypt-nthash 77 | test/crypt-pbkdf1-sha1 78 | test/crypt-scrypt 79 | test/crypt-sha256 80 | test/crypt-sha512 81 | test/crypt-sm3-yescrypt 82 | test/crypt-sunmd5 83 | test/crypt-too-long-phrase 84 | test/crypt-yescrypt 85 | test/des-obsolete 86 | test/des-obsolete_r 87 | test/explicit-bzero 88 | test/fcrypt-enosys 89 | test/gensalt 90 | test/gensalt-bcrypt_x 91 | test/gensalt-nested-call 92 | test/gensalt-nthash 93 | test/gensalt-extradata 94 | test/getrandom-fallbacks 95 | test/getrandom-interface 96 | test/ka-bcrypt 97 | test/ka-bcrypt-a 98 | test/ka-bcrypt-x 99 | test/ka-bcrypt-y 100 | test/ka-bigcrypt 101 | test/ka-bsdicrypt 102 | test/ka-descrypt 103 | test/ka-gost-yescrypt 104 | test/ka-md5crypt 105 | test/ka-nt 106 | test/ka-scrypt 107 | test/ka-sha1crypt 108 | test/ka-sha256crypt 109 | test/ka-sha512crypt 110 | test/ka-sm3crypt 111 | test/ka-sm3-yescrypt 112 | test/ka-sunmd5 113 | test/ka-yescrypt 114 | test/preferred-method 115 | test/short-outbuf 116 | test/special-char-salt 117 | /xcrypt.h 118 | /xcrypt.h.stamp 119 | 120 | # backup-files 121 | *~ 122 | 123 | # archives 124 | *.tar* 125 | 126 | # GnuPG keyrings 127 | *.asc 128 | *.gpg 129 | 130 | # Valgrind 131 | vgcore.* 132 | 133 | # Patch 134 | *.orig 135 | *.rej 136 | 137 | # Coverage 138 | all_coverage.info 139 | coverage.info 140 | 141 | # Packit 142 | libxcrypt.spec 143 | libxcrypt-*.rpm 144 | libxcrypt-*.srpm 145 | libxcrypt-*.src.rpm 146 | libxcrypt-*/ 147 | */libxcrypt-*.rpm 148 | -------------------------------------------------------------------------------- /lib/alg-gost3411-2012-hmac.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * Copyright (C) 2018 Björn Esser 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 8 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 11 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 14 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 16 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 17 | * SUCH DAMAGE. 18 | */ 19 | 20 | 21 | #include "crypt-port.h" 22 | 23 | #if INCLUDE_gost_yescrypt 24 | 25 | #include "alg-gost3411-2012-hmac.h" 26 | 27 | /* GOST2012_256 */ 28 | void 29 | gost_hash256 (const uint8_t *t, size_t n, uint8_t *out32, 30 | GOST34112012Context *ctx) 31 | { 32 | GOST34112012Init (ctx, GOSTR3411_2012_BITS); 33 | GOST34112012Update (ctx, t, n); 34 | GOST34112012Final (ctx, out32); 35 | } 36 | 37 | /* HMAC_GOSTR3411_2012_256 */ 38 | void 39 | gost_hmac256 (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 40 | uint8_t *out32, gost_hmac_256_t *gostbuf) 41 | { 42 | size_t i; 43 | 44 | /* R 50.1.113-2016 only allowed N to be in range 256..512 bits */ 45 | assert (n >= GOSTR3411_2012_L && n <= GOSTR3411_2012_B); 46 | 47 | for (i = 0; i < sizeof (gostbuf->pad); i++) 48 | gostbuf->kstar[i] = i < n ? k[i] : 0; 49 | 50 | GOST34112012Init (&gostbuf->ctx, GOSTR3411_2012_BITS); 51 | 52 | for (i = 0; i < sizeof (gostbuf->pad); i++) 53 | gostbuf->pad[i] = gostbuf->kstar[i] ^ 0x36; /* ipad */ 54 | 55 | GOST34112012Update (&gostbuf->ctx, gostbuf->pad, 56 | sizeof (gostbuf->pad)); 57 | GOST34112012Update (&gostbuf->ctx, t, len); 58 | GOST34112012Final (&gostbuf->ctx, gostbuf->digest); 59 | 60 | /* Clear the context state. */ 61 | explicit_bzero (&gostbuf->ctx, sizeof (GOST34112012Context)); 62 | 63 | GOST34112012Init (&gostbuf->ctx, GOSTR3411_2012_BITS); 64 | 65 | for (i = 0; i < sizeof (gostbuf->pad); i++) 66 | gostbuf->pad[i] = gostbuf->kstar[i] ^ 0x5c; /* opad */ 67 | 68 | GOST34112012Update (&gostbuf->ctx, gostbuf->pad, 69 | sizeof (gostbuf->pad)); 70 | GOST34112012Update (&gostbuf->ctx, gostbuf->digest, 71 | sizeof (gostbuf->digest)); 72 | GOST34112012Final (&gostbuf->ctx, out32); 73 | 74 | /* Clear the context state. */ 75 | explicit_bzero (gostbuf, sizeof (gost_hmac_256_t)); 76 | } 77 | 78 | #endif /* INCLUDE_gost_yescrypt */ 79 | -------------------------------------------------------------------------------- /test/alg-md4.c: -------------------------------------------------------------------------------- 1 | #include "crypt-port.h" 2 | #include "alg-md4.h" 3 | 4 | #include 5 | 6 | #if INCLUDE_nt 7 | 8 | static const struct 9 | { 10 | const char *input; 11 | const char result[16 + 1] ; 12 | } tests[] = 13 | { 14 | /* Test vectors as defined in RFC 1320, appendix A, section 5. 15 | https://tools.ietf.org/html/rfc1320#appendix-A.5 */ 16 | { 17 | "", 18 | "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0" 19 | }, 20 | { 21 | "a", 22 | "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24" 23 | }, 24 | { 25 | "abc", 26 | "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d" 27 | }, 28 | { 29 | "message digest", 30 | "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b" 31 | }, 32 | { 33 | "abcdefghijklmnopqrstuvwxyz", 34 | "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d\xa9" 35 | }, 36 | { 37 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 38 | "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4" 39 | }, 40 | { 41 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 42 | "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05\x36" 43 | } 44 | }; 45 | 46 | static void 47 | report_failure(int n, const char *tag, 48 | const char expected[16], uint8_t actual[16]) 49 | { 50 | int i; 51 | printf ("FAIL: test %d (%s):\n exp:", n, tag); 52 | for (i = 0; i < 16; i++) 53 | { 54 | if (i % 4 == 0) 55 | putchar (' '); 56 | printf ("%02x", (unsigned int)(unsigned char)expected[i]); 57 | } 58 | printf ("\n got:"); 59 | for (i = 0; i < 16; i++) 60 | { 61 | if (i % 4 == 0) 62 | putchar (' '); 63 | printf ("%02x", (unsigned int)(unsigned char)actual[i]); 64 | } 65 | putchar ('\n'); 66 | putchar ('\n'); 67 | } 68 | 69 | int 70 | main (void) 71 | { 72 | MD4_CTX ctx; 73 | uint8_t sum[16]; 74 | int result = 0; 75 | int cnt; 76 | int i; 77 | 78 | for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) 79 | { 80 | MD4_Init (&ctx); 81 | MD4_Update (&ctx, tests[cnt].input, strlen (tests[cnt].input)); 82 | MD4_Final (sum, &ctx); 83 | if (memcmp (tests[cnt].result, sum, 16)) 84 | { 85 | report_failure (cnt, "all at once", tests[cnt].result, sum); 86 | result = 1; 87 | } 88 | 89 | MD4_Init (&ctx); 90 | for (i = 0; tests[cnt].input[i] != '\0'; ++i) 91 | MD4_Update (&ctx, &tests[cnt].input[i], 1); 92 | MD4_Final (sum, &ctx); 93 | if (memcmp (tests[cnt].result, sum, 16)) 94 | { 95 | report_failure (cnt, "byte by byte", tests[cnt].result, sum); 96 | result = 1; 97 | } 98 | } 99 | 100 | return result; 101 | } 102 | 103 | #else 104 | 105 | int 106 | main (void) 107 | { 108 | return 77; /* UNSUPPORTED */ 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /lib/alg-sha512.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _SHA512_H_ 28 | #define _SHA512_H_ 29 | 30 | #include 31 | #include 32 | 33 | /* 34 | * Use #defines in order to avoid namespace collisions with anyone else's 35 | * SHA512 code (e.g., the code in OpenSSL). 36 | */ 37 | #define SHA512_Init libcperciva_SHA512_Init 38 | #define SHA512_Update libcperciva_SHA512_Update 39 | #define SHA512_Final libcperciva_SHA512_Final 40 | #define SHA512_Buf libcperciva_SHA512_Buf 41 | #define SHA512_CTX libcperciva_SHA512_CTX 42 | 43 | /* Common constants. */ 44 | #define SHA512_BLOCK_LENGTH 128 45 | #define SHA512_DIGEST_LENGTH 64 46 | 47 | /* Context structure for SHA512 operations. */ 48 | typedef struct { 49 | uint64_t state[8]; 50 | uint64_t count[2]; 51 | uint8_t buf[SHA512_BLOCK_LENGTH]; 52 | } SHA512_CTX; 53 | 54 | /** 55 | * SHA512_Init(ctx): 56 | * Initialize the SHA512 context ${ctx}. 57 | */ 58 | extern void SHA512_Init(SHA512_CTX *); 59 | 60 | /** 61 | * SHA512_Update(ctx, in, len): 62 | * Input ${len} bytes from ${in} into the SHA512 context ${ctx}. 63 | */ 64 | extern void SHA512_Update(SHA512_CTX *, const void *, size_t); 65 | 66 | /** 67 | * SHA512_Final(digest, ctx): 68 | * Output the SHA512 hash of the data input to the context ${ctx} into the 69 | * buffer ${digest}. 70 | */ 71 | extern void SHA512_Final(unsigned char[MIN_SIZE(SHA512_DIGEST_LENGTH)], 72 | SHA512_CTX *); 73 | 74 | /** 75 | * SHA512_Buf(in, len, digest): 76 | * Compute the SHA512 hash of ${len} bytes from ${in} and write it to ${digest}. 77 | */ 78 | extern void SHA512_Buf(const void *, size_t, 79 | unsigned char[MIN_SIZE(SHA512_DIGEST_LENGTH)]); 80 | 81 | #endif /* !_SHA512_H_ */ 82 | -------------------------------------------------------------------------------- /test/alg-sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SHA-1 in C 3 | * By Steve Reid 4 | * 100% Public Domain 5 | */ 6 | 7 | #include "crypt-port.h" 8 | #include "alg-sha1.h" 9 | 10 | #include 11 | 12 | #if INCLUDE_sha1crypt 13 | 14 | /* Test Vectors (from FIPS PUB 180-1) */ 15 | const char *test_data[3] = 16 | { 17 | "abc", 18 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 19 | "A million repetitions of 'a'" 20 | }; 21 | 22 | const char *test_results[3] = 23 | { 24 | "a9993e364706816aba3e25717850c26c9cd0d89d", 25 | "84983e441c3bd26ebaae4aa1f95129e5e54670f1", 26 | "34aa973cd4c4daa4f61eeb2bdbad27316534016f" 27 | }; 28 | 29 | 30 | static void 31 | bin_to_hex (uint8_t *digest, char *output) 32 | { 33 | for (uint8_t i = 0; i < 20; ++i) 34 | { 35 | sprintf (output, "%02x", *digest); 36 | ++digest; 37 | output += 2; 38 | } 39 | } 40 | 41 | 42 | int 43 | main (void) 44 | { 45 | int k; 46 | struct sha1_ctx ctx; 47 | uint8_t digest[20]; 48 | char output[80]; 49 | uint8_t retval = 0; 50 | 51 | for (k = 0; k < 2; k++) 52 | { 53 | sha1_init_ctx (&ctx); 54 | sha1_process_bytes ((const uint8_t*)test_data[k], &ctx, strlen(test_data[k])); 55 | sha1_finish_ctx (&ctx, digest); 56 | bin_to_hex(digest, output); 57 | 58 | if (strcmp(output, test_results[k])) 59 | { 60 | fprintf(stdout, "FAIL\n"); 61 | fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]); 62 | fprintf(stderr,"\t%s returned\n", output); 63 | fprintf(stderr,"\t%s is correct\n", test_results[k]); 64 | retval = 1; 65 | } 66 | } 67 | /* million 'a' vector we feed separately */ 68 | sha1_init_ctx (&ctx); 69 | for (k = 0; k < 1000000; k++) 70 | sha1_process_bytes ((const uint8_t*)"a", &ctx, 1); 71 | sha1_finish_ctx (&ctx, digest); 72 | bin_to_hex(digest, output); 73 | if (strcmp(output, test_results[2])) 74 | { 75 | fprintf(stdout, "FAIL\n"); 76 | fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]); 77 | fprintf(stderr,"\t%s returned\n", output); 78 | fprintf(stderr,"\t%s is correct\n", test_results[2]); 79 | retval = 1; 80 | } 81 | 82 | /* The same test as above, but with 1000 blocks of 1000 bytes. */ 83 | char buf[1000]; 84 | memset (buf, 'a', sizeof (buf)); 85 | sha1_init_ctx (&ctx); 86 | for (k = 0; k < 1000; ++k) 87 | sha1_process_bytes ((const uint8_t*)buf, &ctx, sizeof (buf)); 88 | sha1_finish_ctx (&ctx, digest); 89 | bin_to_hex(digest, output); 90 | if (strcmp(output, test_results[2])) 91 | { 92 | fprintf(stdout, "FAIL\n"); 93 | fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]); 94 | fprintf(stderr,"\t%s returned\n", output); 95 | fprintf(stderr,"\t%s is correct\n", test_results[2]); 96 | retval = 1; 97 | } 98 | 99 | /* success */ 100 | return retval; 101 | } 102 | 103 | #else 104 | 105 | int 106 | main (void) 107 | { 108 | return 77; /* UNSUPPORTED */ 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /test/symbols-renames.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # Written by Zack Weinberg in 2017 and 2020. 3 | # To the extent possible under law, Zack Weinberg has waived all 4 | # copyright and related or neighboring rights to this work. 5 | # 6 | # See https://creativecommons.org/publicdomain/zero/1.0/ for further 7 | # details. 8 | 9 | # Check that all of the symbols renamed by crypt-port.h 10 | # still appear somewhere in the source code. This test does not attempt 11 | # to parse the source code, so it can get false negatives (e.g. a word used 12 | # in a comment will be enough). 13 | # 14 | # Due to limitations in Automake, this program takes parameters from 15 | # the environment: 16 | # $lib_la - full pathname of libcrypt.la 17 | # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C 18 | # $NM, $CPP, $CPPFLAGS - nm utility, C preprocessor, and parameters 19 | 20 | use v5.14; # implicit use strict, use feature ':5.14' 21 | use warnings FATAL => 'all'; 22 | use utf8; 23 | use open qw(:std :utf8); 24 | no if $] >= 5.022, warnings => 'experimental::re_strict'; 25 | use if $] >= 5.022, re => 'strict'; 26 | 27 | use File::Temp (); 28 | 29 | use FindBin (); 30 | use lib $FindBin::Bin; 31 | use TestCommon qw( 32 | compare_symbol_lists 33 | ensure_C_locale 34 | find_real_library 35 | get_symbols 36 | popen 37 | sh_split 38 | skip 39 | subprocess_error 40 | which 41 | ); 42 | 43 | sub list_library_internals { 44 | # We are only interested in symbols with the internal prefix, 45 | # _crypt_. 46 | return get_symbols(find_real_library(shift, 'static'), 47 | sub { $_[0] =~ /^_crypt_/ }); 48 | } 49 | 50 | sub list_symbol_renames { 51 | state @CPP; 52 | if (!@CPP) { 53 | @CPP = which($ENV{CPP} || 'cc -E'); 54 | skip('C compiler not available') unless @CPP; 55 | } 56 | state @CPPFLAGS; 57 | if (!@CPPFLAGS) { 58 | @CPPFLAGS = sh_split($ENV{CPPFLAGS} || q{}); 59 | } 60 | 61 | my $tmp = File::Temp->new( 62 | DIR => '.', 63 | TEMPLATE => 'symbols-renames-XXXXXX', 64 | SUFFIX => '.c', 65 | EXLOCK => 0, 66 | ); 67 | print {$tmp} qq{#include "crypt-port.h"\n}; 68 | 69 | my $fh = popen('-|', @CPP, @CPPFLAGS, '-dD', $tmp->filename); 70 | local $_; 71 | my %symbols; 72 | my $pp_define = qr{ 73 | ^\#define \s+ 74 | [a-zA-Z_][a-zA-Z0-9_(),]* \s+ 75 | (_crypt_[a-zA-Z0-9_]*) \b 76 | }x; 77 | while (<$fh>) { 78 | chomp; 79 | s/\s+$//; 80 | if ($_ =~ $pp_define) { 81 | print {*STDERR} "| $1\n"; 82 | $symbols{$1} = 1; 83 | } 84 | } 85 | close $fh or subprocess_error($CPP[0]); 86 | return \%symbols; 87 | } 88 | 89 | # 90 | # Main 91 | # 92 | my $lib_la = $ENV{lib_la} || '/nonexistent'; 93 | if (!-f $lib_la) { 94 | print {*STDERR} "usage: lib_la=/path/to/library.la $0"; 95 | exit 1; 96 | } 97 | if (($ENV{HAVE_CPP_dD} // 'yes') eq 'no') { 98 | skip('cpp -dD not available'); 99 | } 100 | 101 | ensure_C_locale(); 102 | exit compare_symbol_lists( 103 | list_library_internals($lib_la), 104 | list_symbol_renames(), 105 | 'renames', 106 | 0, # extra symbols not allowed 107 | ); 108 | -------------------------------------------------------------------------------- /lib/alg-des.h: -------------------------------------------------------------------------------- 1 | /* 2 | * FreeSec: libcrypt for NetBSD 3 | * 4 | * Copyright (c) 1994 David Burren 5 | * All rights reserved. 6 | * 7 | * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet 8 | * this file should now *only* export crypt(), in order to make 9 | * binaries of libcrypt exportable from the USA 10 | * 11 | * Adapted for FreeBSD-4.0 by Mark R V Murray 12 | * this file should now *only* export crypt_des(), in order to make 13 | * a module that can be optionally included in libcrypt. 14 | * 15 | * Adapted for libxcrypt by Zack Weinberg, 2017 16 | * see notes in des.c 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted provided that the following conditions 20 | * are met: 21 | * 1. Redistributions of source code must retain the above copyright 22 | * notice, this list of conditions and the following disclaimer. 23 | * 2. Redistributions in binary form must reproduce the above copyright 24 | * notice, this list of conditions and the following disclaimer in the 25 | * documentation and/or other materials provided with the distribution. 26 | * 3. Neither the name of the author nor the names of other contributors 27 | * may be used to endorse or promote products derived from this software 28 | * without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 31 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 34 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 | * SUCH DAMAGE. 41 | * 42 | * This is an original implementation of the DES and the crypt(3) interfaces 43 | * by David Burren . 44 | */ 45 | 46 | #ifndef _CRYPT_ALG_DES_H 47 | #define _CRYPT_ALG_DES_H 1 48 | 49 | /* des.c */ 50 | 51 | struct des_ctx 52 | { 53 | uint32_t keysl[16]; 54 | uint32_t keysr[16]; 55 | uint32_t saltbits; 56 | }; 57 | 58 | extern void des_set_key (struct des_ctx *restrict ctx, 59 | const unsigned char key[MIN_SIZE(8)]); 60 | extern void des_set_salt (struct des_ctx *restrict ctx, 61 | uint32_t salt); 62 | extern void des_crypt_block (struct des_ctx *restrict ctx, 63 | unsigned char *out, const unsigned char *in, 64 | unsigned int count, bool decrypt); 65 | 66 | /* des-tables.c (generated by des-mktables) */ 67 | extern const uint8_t m_sbox[4][4096]; 68 | extern const uint32_t ip_maskl[8][256], ip_maskr[8][256]; 69 | extern const uint32_t fp_maskl[8][256], fp_maskr[8][256]; 70 | extern const uint32_t key_perm_maskl[8][128], key_perm_maskr[8][128]; 71 | extern const uint32_t comp_maskl[8][128], comp_maskr[8][128]; 72 | extern const uint32_t psbox[4][256]; 73 | 74 | #endif /* alg-des.h */ 75 | -------------------------------------------------------------------------------- /doc/crypt_checksalt.3: -------------------------------------------------------------------------------- 1 | .\" Written by Zack Weinberg in 2018. 2 | .\" 3 | .\" To the extent possible under law, the authors have waived 4 | .\" all copyright and related or neighboring rights to this work. 5 | .\" See https://creativecommons.org/publicdomain/zero/1.0/ for further 6 | .\" details. 7 | .\" 8 | .Dd November 8, 2018 9 | .Dt CRYPT_CHECKSALT 3 10 | .Os "libxcrypt" 11 | .Sh NAME 12 | .Nm crypt_checksalt 13 | .Nd validate a crypt setting string 14 | .Sh LIBRARY 15 | .Lb libcrypt 16 | .Sh SYNOPSIS 17 | .In crypt.h 18 | .Ft int 19 | .Fo crypt_checksalt 20 | .Fa "const char *setting" 21 | .Fc 22 | .Sh DESCRIPTION 23 | .Nm 24 | checks the 25 | .Ar setting 26 | string against the system configuration 27 | and reports whether the hashing method and parameters it specifies 28 | are acceptable. 29 | It is intended to be used by programs 30 | such as 31 | .Xr login 1 32 | to determine whether the user's passphrase should be re-hashed 33 | using the currently preferred hashing method. 34 | .Sh RETURN VALUES 35 | The return value is 0 if there is nothing wrong with this setting. 36 | Otherwise, it is one of the following constants: 37 | .Bl -tag -width 4n 38 | .It Dv CRYPT_SALT_OK 39 | .Ar setting 40 | is a fully correct setting string. 41 | This constant is guaranteed to equal 0. 42 | .It Dv CRYPT_SALT_INVALID 43 | .Ar setting 44 | is not a valid setting string; either it specifies a hashing method 45 | that is not known to this version of libxcrypt, 46 | or it specifies invalid parameters for the method. 47 | .It Dv CRYPT_SALT_METHOD_DISABLED (Not implemented, yet) 48 | .Ar setting 49 | specifies a hashing method that is no longer allowed to be used at all; 50 | .Nm crypt 51 | will fail if passed this 52 | .Ar setting . 53 | Manual intervention will be required to reactivate the user's account. 54 | .It Dv CRYPT_SALT_METHOD_LEGACY 55 | .Ar setting 56 | specifies a hashing method that is no longer considered strong enough 57 | for use with new passphrases. 58 | .Nm crypt 59 | will still authenticate a passphrase against this setting, 60 | but if authentication succeeds, 61 | the passphrase should be re-hashed using the currently preferred method. 62 | .It Dv CRYPT_SALT_TOO_CHEAP (Not implemented, yet) 63 | .Ar setting 64 | specifies cost parameters that are considered too cheap for use with 65 | new passphrases. 66 | .Nm crypt 67 | will still authenticate a passphrase against this setting, 68 | but if authentication succeeds, 69 | the passphrase should be re-hashed using the currently preferred method. 70 | .El 71 | .Sh FEATURE TEST MACROS 72 | .In crypt.h 73 | will define the macro 74 | .Dv CRYPT_CHECKSALT_AVAILABLE 75 | if 76 | .Nm 77 | is available in the current version of libxcrypt. 78 | .Sh BUGS 79 | Since full configurability is not yet implemented, the current 80 | implementation will only ever return 81 | .Nm CRYPT_SALT_OK (0) 82 | or 83 | .Nm CRYPT_SALT_INVALID 84 | when invoked. 85 | .Sh PORTABILITY NOTES 86 | The function 87 | .Nm 88 | is not part of any standard. 89 | It was added to libxcrypt in version 4.3.0. 90 | .Sh ATTRIBUTES 91 | For an explanation of the terms used in this section, see 92 | .Xr attributes 7 . 93 | .TS 94 | allbox; 95 | lb lb lb 96 | l l l. 97 | Interface Attribute Value 98 | T{ 99 | .Nm 100 | T} Thread safety MT-Safe 101 | .TE 102 | .sp 103 | .Sh SEE ALSO 104 | .Xr crypt 3 , 105 | .Xr crypt_gensalt 3 , 106 | .Xr crypt 5 107 | -------------------------------------------------------------------------------- /lib/hashes.conf: -------------------------------------------------------------------------------- 1 | # This file is read by expand-selected-hashes and gen-crypt-hashes-h. 2 | # It lists, for each supported hash algorithm, the name to be used to 3 | # enable or disable it at configure time, which is also part of the 4 | # name used for the 'crypt_fn' and 'gensalt_fn' entry points to the 5 | # relevant algorithm module; the prefix used to identify the algorithm 6 | # in hash strings; the number of bytes of random data that 7 | # crypt_gensalt should draw from the OS when its caller doesn't supply 8 | # any; and a comma-separated list of flags. 9 | # 10 | # The current set of possible flags is: STRONG means the hash is still 11 | # considered strong enough to use for newly hashed passwords; this is 12 | # the set of hashes that will be enabled when the library is 13 | # configured with --enable-hashes=strong. DEFAULT means that this 14 | # hash may be used as the default for newly hashed passwords; 15 | # when crypt_gensalt is called with a null pointer for its prefix 16 | # argument, it will use the first hash in this file that was enabled 17 | # and has a DEFAULT flag. Hashes that are not STRONG should never be 18 | # marked DEFAULT. If you change the set of DEFAULT hashes you must also 19 | # update test-gensalt.c to match. 20 | # 21 | # ALT, FREEBSD, GLIBC, NETBSD, OPENBSD, OSX, OWL, SOLARIS, and SUSE 22 | # mean that the hash was historically supported by crypt() as provided 23 | # by that operating system / C library. These are also recognized by 24 | # --enable-hashes as sets of hashes that can be enabled. 25 | # 26 | # Fields are separated by whitespace. Lines beginning with # are 27 | # ignored; # is not otherwise significant. Multiple flags are 28 | # separated by commas. A field whose contents are a single colon (:) 29 | # is actually understood as an empty string; colon is used for this 30 | # purpose because it cannot be part of a hash prefix or a C identifier. 31 | # 32 | # Because the first DEFAULT entry that's enabled is used for new 33 | # hashes when crypt_gensalt() is called with a null prefix, the list 34 | # should be kept in decreasing order of cryptographic strength overall 35 | # (this only *matters* for DEFAULT entries, but it's easier to keep 36 | # the whole list sorted that way). Because of how crypt() checks 37 | # prefixes, the hashes that use an empty prefix (bigcrypt and 38 | # descrypt) must be last (conveniently, these are also the weakest 39 | # supported hashes). 40 | # 41 | #name h_prefix nrbytes flags 42 | yescrypt $y$ 16 STRONG,DEFAULT,ALT,DEBIAN,FEDORA 43 | gost_yescrypt $gy$ 16 STRONG,ALT 44 | sm3_yescrypt $sm3y$ 16 STRONG,EULER,KYLIN 45 | scrypt $7$ 16 STRONG 46 | bcrypt $2b$ 16 STRONG,DEFAULT,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE 47 | bcrypt_y $2y$ 16 STRONG,ALT,OWL,SUSE 48 | bcrypt_a $2a$ 16 STRONG,ALT,FREEBSD,NETBSD,OPENBSD,OWL,SOLARIS,SUSE 49 | bcrypt_x $2x$ 16 ALT,OWL,SUSE 50 | sm3crypt $sm3$ 16 EULER,KYLIN 51 | sha512crypt $6$ 15 STRONG,DEFAULT,GLIBC,FREEBSD,SOLARIS 52 | sha256crypt $5$ 15 GLIBC,FREEBSD,SOLARIS 53 | sha1crypt $sha1 20 NETBSD 54 | sunmd5 $md5 8 SOLARIS 55 | md5crypt $1$ 9 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS 56 | nt $3$ 1 FREEBSD 57 | bsdicrypt _ 3 FREEBSD,NETBSD,OPENBSD,OSX 58 | bigcrypt : 2 : 59 | descrypt : 2 GLIBC,FREEBSD,NETBSD,OPENBSD,SOLARIS,OSX 60 | -------------------------------------------------------------------------------- /.github/workflows/distcheck.yml: -------------------------------------------------------------------------------- 1 | name: Distcheck 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '31 3 * * 1' # Monday at 3h31 UTC 8 | 9 | jobs: 10 | skip_duplicates: 11 | # continue-on-error: true # Uncomment once integration is finished 12 | runs-on: ubuntu-24.04 13 | outputs: 14 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 15 | steps: 16 | - id: skip_check 17 | uses: fkirc/skip-duplicate-actions@v5 18 | with: 19 | concurrent_skipping: 'same_content_newer' 20 | skip_after_successful_duplicate: 'true' 21 | paths_ignore: '[]' # changes in any file can affect distcheck 22 | do_not_skip: '["workflow_dispatch", "schedule"]' 23 | 24 | Distcheck: 25 | needs: skip_duplicates 26 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 27 | 28 | runs-on: ubuntu-24.04 29 | 30 | strategy: 31 | fail-fast: false 32 | 33 | env: 34 | ac_cv_func_arc4random_buf: "no" 35 | VERBOSE: 1 36 | 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v4 40 | 41 | - name: Install packages 42 | run: sudo apt-get install libltdl-dev 43 | 44 | # The distcheck build is run with the oldest version of perl we support, 45 | # in order to verify that we still support it. 46 | - name: Install Perl 5.14 47 | uses: shogo82148/actions-setup-perl@v1 48 | with: 49 | perl-version: '5.14' 50 | 51 | # 'make distcheck' runs perlcritic on all our Perl code. 52 | # Install exactly the set of critic-related CPAN distributions 53 | # documented in .perlcriticrc. 54 | # One perlcritic policy has a stealth dependency on aspell. 55 | - name: Install perlcritic and perltidy 56 | run: | 57 | sudo apt-get install aspell 58 | cpanm -S -M https://cpan.metacpan.org/ -n -i $(sed -Ene ' 59 | s/^#[[:space:]]+([A-Z0-9]+\/.+\.tar\.gz)$/\1/p 60 | /^$/q 61 | ' .perlcriticrc) 62 | 63 | - name: Versions of build tools 64 | id: build-tools 65 | run: ./build-aux/ci/ci-log-dependency-versions 66 | 67 | - name: Get nprocs 68 | run: echo "NPROCS=$((`nproc --all 2>/dev/null || sysctl -n hw.ncpu` * 2))" | tee $GITHUB_ENV 69 | 70 | - name: Cache bootstrap 71 | id: cache 72 | uses: actions/cache@v4 73 | with: 74 | path: | 75 | INSTALL 76 | Makefile.in 77 | aclocal.m4 78 | config.h.in 79 | configure 80 | autom4te.cache/** 81 | build-aux/m4/libtool.m4 82 | build-aux/m4/ltoptions.m4 83 | build-aux/m4/ltsugar.m4 84 | build-aux/m4/ltversion.m4 85 | build-aux/m4/lt~obsolete.m4 86 | build-aux/m4-autogen/** 87 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 88 | 89 | - name: Bootstrap 90 | if: steps.cache.outputs.cache-hit != 'true' 91 | run: ./autogen.sh 92 | 93 | # The configure options used in this step do not matter, we just need 94 | # the makefile to exist. 95 | - name: Configure 96 | run: ./configure 97 | 98 | - name: Test 99 | run: make -j${{ env.NPROCS }} distcheck 100 | 101 | - name: Detailed error logs 102 | if: failure() 103 | run: ./build-aux/ci/ci-log-logfiles 104 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL static analysis" 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '31 3 * * 1' # Monday at 3h31 UTC 8 | 9 | jobs: 10 | skip_duplicates: 11 | continue-on-error: true 12 | runs-on: ubuntu-24.04 13 | outputs: 14 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 15 | steps: 16 | - id: skip_check 17 | uses: fkirc/skip-duplicate-actions@v5 18 | with: 19 | concurrent_skipping: 'same_content_newer' 20 | skip_after_successful_duplicate: 'true' 21 | paths_ignore: '["doc/**", "**/*.md", ".gitignore", "libxcrypt.spec.rpkg", ".packit.yaml", "rpkg.macros", "AUTHORS", "ChangeLog", "COPYING.LIB", "LICENSING", "NEWS", "README", "THANKS", "TODO"]' 22 | do_not_skip: '["workflow_dispatch", "schedule"]' 23 | 24 | CodeQL: 25 | needs: skip_duplicates 26 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 27 | 28 | runs-on: ubuntu-24.04 29 | permissions: 30 | actions: read 31 | contents: read 32 | security-events: write 33 | 34 | env: 35 | ac_cv_func_arc4random_buf: "no" 36 | 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v4 40 | 41 | - name: Install packages 42 | run: sudo apt-get install libltdl-dev 43 | 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | # CodeQL lumps C with C++. Perl is not currently supported. 48 | languages: cpp, python 49 | 50 | # If you wish to specify custom queries, you can do so here or in a 51 | # config file. By default, queries listed here will override any 52 | # specified in a config file. Prefix the list here with "+" to use 53 | # these queries and those in the config file. 54 | #queries: 55 | # - ./path/to/local/query 56 | # - your-org/your-repo/queries@main 57 | 58 | - name: Versions of build tools 59 | id: build-tools 60 | run: ./build-aux/ci/ci-log-dependency-versions 61 | 62 | - name: Get nprocs 63 | run: echo "NPROCS=$((`nproc --all 2>/dev/null || sysctl -n hw.ncpu` * 2))" | tee $GITHUB_ENV 64 | 65 | - name: Cache bootstrap 66 | id: cache 67 | uses: actions/cache@v4 68 | with: 69 | path: | 70 | INSTALL 71 | Makefile.in 72 | aclocal.m4 73 | config.h.in 74 | configure 75 | autom4te.cache/** 76 | build-aux/m4/libtool.m4 77 | build-aux/m4/ltoptions.m4 78 | build-aux/m4/ltsugar.m4 79 | build-aux/m4/ltversion.m4 80 | build-aux/m4/lt~obsolete.m4 81 | build-aux/m4-autogen/** 82 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 83 | 84 | - name: Bootstrap 85 | if: steps.cache.outputs.cache-hit != 'true' 86 | run: ./autogen.sh 87 | 88 | - name: Configure 89 | run: ./configure --enable-obsolete-api --enable-hashes=all 90 | 91 | - name: Build 92 | run: | 93 | make -j${{ env.NPROCS }} all 94 | make -j${{ env.NPROCS }} test-programs 95 | 96 | - name: Perform CodeQL Analysis 97 | uses: github/codeql-action/analyze@v3 98 | 99 | - name: Detailed error logs 100 | if: failure() 101 | run: ./build-aux/ci/ci-log-logfiles 102 | -------------------------------------------------------------------------------- /test/gensalt-nested-call.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Björn Esser 3 | * All rights reserved. 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted. 7 | * 8 | * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "crypt-port.h" 18 | 19 | #if INCLUDE_bcrypt || INCLUDE_bcrypt_a || INCLUDE_bcrypt_y || \ 20 | INCLUDE_bigcrypt || INCLUDE_bsdicrypt || INCLUDE_descrypt || \ 21 | INCLUDE_gost_yescrypt || INCLUDE_md5crypt || INCLUDE_nt || \ 22 | INCLUDE_scrypt || INCLUDE_sha1crypt || INCLUDE_sha256crypt || \ 23 | INCLUDE_sha512crypt || INCLUDE_sm3_yescrypt || INCLUDE_sm3crypt || \ 24 | INCLUDE_sunmd5 || INCLUDE_yescrypt 25 | 26 | #include 27 | 28 | static const char *prefixes[] = 29 | { 30 | #if INCLUDE_descrypt 31 | "Mp", 32 | #endif 33 | #if INCLUDE_bigcrypt 34 | "Mp............", 35 | #endif 36 | #if INCLUDE_bsdicrypt 37 | "_", 38 | #endif 39 | #if INCLUDE_md5crypt 40 | "$1$", 41 | #endif 42 | #if INCLUDE_nt 43 | "$3$", 44 | #endif 45 | #if INCLUDE_sunmd5 46 | "$md5$", 47 | #endif 48 | #if INCLUDE_sm3crypt 49 | "$sm3$", 50 | #endif 51 | #if INCLUDE_sha1crypt 52 | "$sha1$", 53 | #endif 54 | #if INCLUDE_sha256crypt 55 | "$5$", 56 | #endif 57 | #if INCLUDE_sha512crypt 58 | "$6$", 59 | #endif 60 | #if INCLUDE_bcrypt_a 61 | "$2a$", 62 | #endif 63 | #if INCLUDE_bcrypt 64 | "$2b$", 65 | #endif 66 | #if INCLUDE_bcrypt_y 67 | "$2y$", 68 | #endif 69 | #if INCLUDE_yescrypt 70 | "$y$", 71 | #endif 72 | #if INCLUDE_scrypt 73 | "$7$", 74 | #endif 75 | #if INCLUDE_gost_yescrypt 76 | "$gy$", 77 | #endif 78 | #if INCLUDE_sm3_yescrypt 79 | "$sm3y$", 80 | #endif 81 | }; 82 | 83 | int 84 | main (void) 85 | { 86 | char output[CRYPT_GENSALT_OUTPUT_SIZE]; 87 | char *retval = NULL; 88 | int status = 0; 89 | 90 | for (size_t i = 0; i < ARRAY_SIZE (prefixes); i++) 91 | { 92 | retval = crypt_gensalt (prefixes[i], 0, NULL, 0); 93 | retval = !retval ? 0 : crypt_gensalt (retval, 0, NULL, 0); 94 | 95 | if (!retval) 96 | { 97 | printf ("Subsequent call to crypt_gensalt(3) failed for prefix \"%s\".\n", 98 | prefixes[i]); 99 | status = 1; 100 | } 101 | 102 | retval = crypt_gensalt_rn (prefixes[i], 0, NULL, 0, 103 | output, sizeof output); 104 | retval = !retval ? 0 : crypt_gensalt_rn (retval, 0, NULL, 0, 105 | output, sizeof output); 106 | 107 | if (!retval) 108 | { 109 | printf ("Subsequent call to crypt_gensalt_rn(3) failed for prefix \"%s\".\n", 110 | prefixes[i]); 111 | status = 1; 112 | } 113 | } 114 | 115 | return status; 116 | } 117 | 118 | #else 119 | 120 | int 121 | main (void) 122 | { 123 | return 77; /* UNSUPPORTED */ 124 | } 125 | 126 | #endif /* all, but bcrypt_x only */ 127 | -------------------------------------------------------------------------------- /lib/alg-yescrypt-platform.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2013-2018,2022 Alexander Peslyak 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted. 7 | * 8 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 9 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 10 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 11 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 12 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 13 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 14 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 15 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 16 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 17 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 18 | * SUCH DAMAGE. 19 | */ 20 | 21 | #ifdef __unix__ 22 | #include 23 | #endif 24 | #ifdef __linux__ 25 | #include /* for MAP_HUGE_2MB */ 26 | #endif 27 | 28 | #define HUGEPAGE_THRESHOLD (32 * 1024 * 1024) 29 | 30 | #ifdef __x86_64__ 31 | #define HUGEPAGE_SIZE (2 * 1024 * 1024) 32 | #else 33 | #undef HUGEPAGE_SIZE 34 | #endif 35 | 36 | static void *alloc_region(yescrypt_region_t *region, size_t size) 37 | { 38 | size_t base_size = size; 39 | uint8_t *base, *aligned; 40 | #ifdef MAP_ANON 41 | unsigned int flags = 42 | #ifdef MAP_NOCORE 43 | MAP_NOCORE | 44 | #endif 45 | MAP_ANON | MAP_PRIVATE; 46 | #if defined(MAP_HUGETLB) && defined(MAP_HUGE_2MB) && defined(HUGEPAGE_SIZE) 47 | size_t new_size = size; 48 | const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1; 49 | if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) { 50 | flags |= MAP_HUGETLB | MAP_HUGE_2MB; 51 | /* 52 | * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of 53 | * huge page size, so let's round up to huge page size here. 54 | */ 55 | new_size = size + hugepage_mask; 56 | new_size &= ~hugepage_mask; 57 | } 58 | base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, (int)flags, -1, 0); 59 | if (base != MAP_FAILED) { 60 | base_size = new_size; 61 | } else if (flags & MAP_HUGETLB) { 62 | flags &= ~(unsigned int)(MAP_HUGETLB | MAP_HUGE_2MB); 63 | base = mmap(NULL, size, PROT_READ | PROT_WRITE, (int)flags, -1, 0); 64 | } 65 | 66 | #else 67 | base = mmap(NULL, size, PROT_READ | PROT_WRITE, (int)flags, -1, 0); 68 | #endif 69 | if (base == MAP_FAILED) 70 | base = NULL; 71 | aligned = base; 72 | #else /* mmap not available */ 73 | base = aligned = NULL; 74 | if (size + 63 < size) { 75 | errno = ENOMEM; 76 | } else if ((base = malloc(size + 63)) != NULL) { 77 | aligned = base + 63; 78 | aligned -= (uintptr_t)aligned & 63; 79 | } 80 | #endif 81 | region->base = base; 82 | region->aligned = aligned; 83 | region->base_size = base ? base_size : 0; 84 | region->aligned_size = base ? size : 0; 85 | return aligned; 86 | } 87 | 88 | static inline void init_region(yescrypt_region_t *region) 89 | { 90 | region->base = region->aligned = NULL; 91 | region->base_size = region->aligned_size = 0; 92 | } 93 | 94 | static int free_region(yescrypt_region_t *region) 95 | { 96 | if (region->base) { 97 | #ifdef MAP_ANON 98 | if (munmap(region->base, region->base_size)) 99 | return -1; 100 | #else 101 | free(region->base); 102 | #endif 103 | } 104 | init_region(region); 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /lib/alg-sm3-hmac.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2024 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | #if INCLUDE_sm3_yescrypt 22 | 23 | #include 24 | #include "alg-sm3-hmac.h" 25 | 26 | /** 27 | * HMAC_k(m) = H((k ^ opad), H((k ^ ipad), m)) 28 | * pseudo-code: 29 | * function hmac(key, message) 30 | * opad = [0x5c * blocksize] 31 | * ipad = [0x36 * blocksize] 32 | * if (length(key) > blocksize) then 33 | * key = hash(key) 34 | * end if 35 | * for i from 0 to length(key) - 1 step 1 36 | * ipad[i] = ipad[i] XOR key[i] 37 | * opad[i] = opad[i] XOR key[i] 38 | * end for 39 | * return hash(opad || hash(ipad || message)) 40 | * end function 41 | */ 42 | 43 | #define IPAD 0x36 44 | #define OPAD 0x5C 45 | 46 | void 47 | sm3_hmac_init (sm3_hmac_ctx_t *ctx, const uint8_t *key, size_t key_len) 48 | { 49 | /* Initialize */ 50 | memset (ctx, 0, sizeof (sm3_hmac_ctx_t)); 51 | 52 | if (key_len > 64) 53 | { 54 | sm3_init (&ctx->sm3_ctx); 55 | sm3_update (&ctx->sm3_ctx, key, key_len); 56 | sm3_final (ctx->key, &ctx->sm3_ctx); 57 | goto end; 58 | } 59 | 60 | memcpy (ctx->key, key, key_len); 61 | 62 | end: 63 | for (int i = 0; i < 64; i++) 64 | { 65 | ctx->key[i] ^= IPAD; 66 | } 67 | sm3_init (&ctx->sm3_ctx); 68 | sm3_update (&ctx->sm3_ctx, ctx->key, 64); 69 | } 70 | 71 | void 72 | sm3_hmac_update (sm3_hmac_ctx_t *ctx, const uint8_t *data, size_t data_len) 73 | { 74 | sm3_update (&ctx->sm3_ctx, data, data_len); 75 | } 76 | 77 | void 78 | sm3_hmac_final (sm3_hmac_ctx_t *ctx, uint8_t mac[32]) 79 | { 80 | for (int i = 0; i < 64; i++) 81 | { 82 | ctx->key[i] ^= (IPAD ^ OPAD); 83 | } 84 | sm3_final (mac, &ctx->sm3_ctx); 85 | sm3_init (&ctx->sm3_ctx); 86 | sm3_update (&ctx->sm3_ctx, ctx->key, 64); 87 | sm3_update (&ctx->sm3_ctx, mac, 32); 88 | sm3_final (mac, &ctx->sm3_ctx); 89 | 90 | /* Zeroize sensitive information. */ 91 | explicit_bzero (ctx, sizeof (sm3_hmac_ctx_t)); 92 | } 93 | 94 | void 95 | sm3_hmac (const unsigned char *data, size_t data_len, 96 | const uint8_t *key, size_t key_len, 97 | uint8_t mac[32], sm3_hmac_ctx_t *ctx) 98 | { 99 | sm3_hmac_init (ctx, key, key_len); 100 | sm3_hmac_update (ctx, data, data_len); 101 | sm3_hmac_final (ctx, mac); 102 | } 103 | 104 | void 105 | sm3_hmac_buf (const unsigned char *data, size_t data_len, 106 | const uint8_t *key, size_t key_len, 107 | uint8_t mac[32]) 108 | { 109 | sm3_hmac_ctx_t ctx; 110 | sm3_hmac (data, data_len, key, key_len, mac, &ctx); 111 | } 112 | 113 | #endif /* INCLUDE_sm3_yescrypt */ 114 | -------------------------------------------------------------------------------- /test/short-outbuf.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | #include 21 | #include 22 | #include 23 | 24 | struct testcase 25 | { 26 | const char *exp_rn; 27 | const char *exp_ra; 28 | }; 29 | 30 | static const struct testcase testcases[] = 31 | { 32 | { "", "*0" }, 33 | { "*", "*0" }, 34 | { "*0", "*0" }, 35 | }; 36 | 37 | int 38 | main (void) 39 | { 40 | bool ok = true; 41 | char result[5]; 42 | 43 | for (size_t i = 0; i < ARRAY_SIZE (testcases); i++) 44 | { 45 | size_t s = i + 1; 46 | int j = (int) s; 47 | char *outbuf = malloc (sizeof (char) * s); 48 | 49 | crypt_rn ("@@", "@@", outbuf, j); 50 | 51 | if (!strncmp (testcases[i].exp_rn, outbuf, s)) 52 | { 53 | strcpy (result, "PASS"); 54 | } 55 | else 56 | { 57 | strcpy (result, "FAIL"); 58 | ok = false; 59 | } 60 | 61 | printf ("Test %zu.0: %s, expected: \"%-2s\", got: \"%-2s\"\n", 62 | s, result, testcases[i].exp_rn, outbuf); 63 | 64 | crypt_ra ("@@", "@@", (void **) &outbuf, &j); 65 | 66 | if (!strncmp (testcases[i].exp_ra, outbuf, strlen(outbuf))) 67 | { 68 | strcpy (result, "PASS"); 69 | } 70 | else 71 | { 72 | strcpy (result, "FAIL"); 73 | ok = false; 74 | } 75 | 76 | printf ("Test %zu.1: %s, expected: \"%-2s\", got: \"%-2s\"\n", 77 | s, result, testcases[i].exp_ra, outbuf); 78 | 79 | j = -1; 80 | 81 | crypt_ra ("@@", "@@", (void **) &outbuf, &j); 82 | 83 | if (!strncmp (testcases[i].exp_ra, outbuf, strlen(outbuf))) 84 | { 85 | strcpy (result, "PASS"); 86 | } 87 | else 88 | { 89 | strcpy (result, "FAIL"); 90 | ok = false; 91 | } 92 | 93 | printf ("Test %zu.2: %s, expected: \"%-2s\", got: \"%-2s\"\n", 94 | s, result, testcases[i].exp_ra, outbuf); 95 | 96 | free (outbuf); 97 | outbuf = NULL; 98 | j = sizeof (struct crypt_data); 99 | 100 | crypt_ra ("@@", "@@", (void **) &outbuf, &j); 101 | 102 | if (!strncmp (testcases[i].exp_ra, outbuf, strlen(outbuf))) 103 | { 104 | strcpy (result, "PASS"); 105 | } 106 | else 107 | { 108 | strcpy (result, "FAIL"); 109 | ok = false; 110 | } 111 | 112 | printf ("Test %zu.3: %s, expected: \"%-2s\", got: \"%-2s\"\n", 113 | s, result, testcases[i].exp_ra, outbuf); 114 | 115 | free (outbuf); 116 | } 117 | 118 | return ok ? 0 : 1; 119 | } 120 | -------------------------------------------------------------------------------- /test/alg-md5.c: -------------------------------------------------------------------------------- 1 | #include "crypt-port.h" 2 | #include "alg-md5.h" 3 | 4 | #include 5 | 6 | #if INCLUDE_md5crypt || INCLUDE_sunmd5 7 | 8 | static const struct 9 | { 10 | const char *input; 11 | const char result[16 + 1]; 12 | } tests[] = 13 | { 14 | /* "Informal" test vectors from 15 | https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data 16 | (these were once in FIPS 180-2, but MD5 has been withdrawn). */ 17 | { 18 | "abc", 19 | "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72" 20 | }, 21 | { 22 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 23 | "\x82\x15\xef\x07\x96\xa2\x0b\xca\xaa\xe1\x16\xd3\x87\x6c\x66\x4a" 24 | }, 25 | /* Test vectors from the NESSIE project. */ 26 | { 27 | "", 28 | "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e" 29 | }, 30 | { 31 | "a", 32 | "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8\x31\xc3\x99\xe2\x69\x77\x26\x61" 33 | }, 34 | { 35 | "message digest", 36 | "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61\xd0" 37 | }, 38 | { 39 | "abcdefghijklmnopqrstuvwxyz", 40 | "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b" 41 | }, 42 | { 43 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 44 | "\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f" 45 | }, 46 | { 47 | "123456789012345678901234567890123456789012345678901234567890" 48 | "12345678901234567890", 49 | "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55\xac\x49\xda\x2e\x21\x07\xb6\x7a" 50 | } 51 | }; 52 | 53 | static void 54 | report_failure(int n, const char *tag, 55 | const char expected[16], uint8_t actual[16]) 56 | { 57 | int i; 58 | printf ("FAIL: test %d (%s):\n exp:", n, tag); 59 | for (i = 0; i < 16; i++) 60 | { 61 | if (i % 4 == 0) 62 | putchar (' '); 63 | printf ("%02x", (unsigned int)(unsigned char)expected[i]); 64 | } 65 | printf ("\n got:"); 66 | for (i = 0; i < 16; i++) 67 | { 68 | if (i % 4 == 0) 69 | putchar (' '); 70 | printf ("%02x", (unsigned int)(unsigned char)actual[i]); 71 | } 72 | putchar ('\n'); 73 | putchar ('\n'); 74 | } 75 | 76 | int 77 | main (void) 78 | { 79 | MD5_CTX ctx; 80 | uint8_t sum[16]; 81 | int result = 0; 82 | int cnt; 83 | int i; 84 | 85 | for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) 86 | { 87 | MD5_Init (&ctx); 88 | MD5_Update (&ctx, tests[cnt].input, strlen (tests[cnt].input)); 89 | MD5_Final (sum, &ctx); 90 | if (memcmp (tests[cnt].result, sum, 16)) 91 | { 92 | report_failure (cnt, "all at once", tests[cnt].result, sum); 93 | result = 1; 94 | } 95 | 96 | MD5_Init (&ctx); 97 | for (i = 0; tests[cnt].input[i] != '\0'; ++i) 98 | MD5_Update (&ctx, &tests[cnt].input[i], 1); 99 | MD5_Final (sum, &ctx); 100 | if (memcmp (tests[cnt].result, sum, 16)) 101 | { 102 | report_failure (cnt, "byte by byte", tests[cnt].result, sum); 103 | result = 1; 104 | } 105 | } 106 | 107 | /* The third "informal" test vector from 108 | . */ 109 | char buf[1000]; 110 | memset (buf, 'a', sizeof (buf)); 111 | MD5_Init (&ctx); 112 | for (i = 0; i < 1000; ++i) 113 | MD5_Update (&ctx, buf, sizeof (buf)); 114 | MD5_Final (sum, &ctx); 115 | static const char expected[64] = 116 | "\x77\x07\xd6\xae\x4e\x02\x7c\x70\xee\xa2\xa9\x35\xc2\x29\x6f\x21"; 117 | if (memcmp (expected, sum, 16) != 0) 118 | { 119 | report_failure (cnt, "block by block", expected, sum); 120 | result = 1; 121 | } 122 | 123 | return result; 124 | } 125 | 126 | #else 127 | 128 | int 129 | main (void) 130 | { 131 | return 77; /* UNSUPPORTED */ 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /test/alg-sha256.c: -------------------------------------------------------------------------------- 1 | #include "crypt-port.h" 2 | #include "alg-sha256.h" 3 | 4 | #include 5 | 6 | #if INCLUDE_sha256crypt || INCLUDE_scrypt || INCLUDE_yescrypt || \ 7 | INCLUDE_gost_yescrypt 8 | 9 | static const struct 10 | { 11 | const char *input; 12 | const char result[32 + 1]; 13 | } tests[] = 14 | { 15 | /* Test vectors from FIPS 180-2: appendix B.1. */ 16 | { 17 | "abc", 18 | "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23" 19 | "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" 20 | }, 21 | /* Test vectors from FIPS 180-2: appendix B.2. */ 22 | { 23 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 24 | "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39" 25 | "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" 26 | }, 27 | /* Test vectors from the NESSIE project. */ 28 | { 29 | "", 30 | "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" 31 | "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55" 32 | }, 33 | { 34 | "a", 35 | "\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d" 36 | "\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb" 37 | }, 38 | { 39 | "message digest", 40 | "\xf7\x84\x6f\x55\xcf\x23\xe1\x4e\xeb\xea\xb5\xb4\xe1\x55\x0c\xad" 41 | "\x5b\x50\x9e\x33\x48\xfb\xc4\xef\xa3\xa1\x41\x3d\x39\x3c\xb6\x50" 42 | }, 43 | { 44 | "abcdefghijklmnopqrstuvwxyz", 45 | "\x71\xc4\x80\xdf\x93\xd6\xae\x2f\x1e\xfa\xd1\x44\x7c\x66\xc9\x52" 46 | "\x5e\x31\x62\x18\xcf\x51\xfc\x8d\x9e\xd8\x32\xf2\xda\xf1\x8b\x73" 47 | }, 48 | { 49 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 50 | "\xdb\x4b\xfc\xbd\x4d\xa0\xcd\x85\xa6\x0c\x3c\x37\xd3\xfb\xd8\x80" 51 | "\x5c\x77\xf1\x5f\xc6\xb1\xfd\xfe\x61\x4e\xe0\xa7\xc8\xfd\xb4\xc0" 52 | }, 53 | { 54 | "123456789012345678901234567890123456789012345678901234567890" 55 | "12345678901234567890", 56 | "\xf3\x71\xbc\x4a\x31\x1f\x2b\x00\x9e\xef\x95\x2d\xd8\x3c\xa8\x0e" 57 | "\x2b\x60\x02\x6c\x8e\x93\x55\x92\xd0\xf9\xc3\x08\x45\x3c\x81\x3e" 58 | } 59 | }; 60 | 61 | 62 | static void 63 | report_failure(int n, const char *tag, 64 | const char expected[32], uint8_t actual[32]) 65 | { 66 | int i; 67 | printf ("FAIL: test %d (%s):\n exp:", n, tag); 68 | for (i = 0; i < 32; i++) 69 | { 70 | if (i % 4 == 0) 71 | putchar (' '); 72 | printf ("%02x", (unsigned int)(unsigned char)expected[i]); 73 | } 74 | printf ("\n got:"); 75 | for (i = 0; i < 32; i++) 76 | { 77 | if (i % 4 == 0) 78 | putchar (' '); 79 | printf ("%02x", (unsigned int)(unsigned char)actual[i]); 80 | } 81 | putchar ('\n'); 82 | putchar ('\n'); 83 | } 84 | 85 | int 86 | main (void) 87 | { 88 | SHA256_CTX ctx; 89 | uint8_t sum[32]; 90 | int result = 0; 91 | int cnt; 92 | int i; 93 | 94 | for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) 95 | { 96 | SHA256_Buf (tests[cnt].input, strlen (tests[cnt].input), sum); 97 | if (memcmp (tests[cnt].result, sum, 32) != 0) 98 | { 99 | report_failure (cnt, "all at once", tests[cnt].result, sum); 100 | result = 1; 101 | } 102 | 103 | SHA256_Init (&ctx); 104 | for (i = 0; tests[cnt].input[i] != '\0'; ++i) 105 | SHA256_Update (&ctx, &tests[cnt].input[i], 1); 106 | SHA256_Final (sum, &ctx); 107 | if (memcmp (tests[cnt].result, sum, 32) != 0) 108 | { 109 | report_failure (cnt, "byte by byte", tests[cnt].result, sum); 110 | result = 1; 111 | } 112 | } 113 | 114 | /* Test vector from FIPS 180-2: appendix B.3. */ 115 | char buf[1000]; 116 | memset (buf, 'a', sizeof (buf)); 117 | SHA256_Init (&ctx); 118 | for (i = 0; i < 1000; ++i) 119 | SHA256_Update (&ctx, buf, sizeof (buf)); 120 | SHA256_Final (sum, &ctx); 121 | static const char expected[32 + 1] = 122 | "\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67" 123 | "\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0"; 124 | if (memcmp (expected, sum, 32) != 0) 125 | { 126 | report_failure (cnt, "block by block", expected, sum); 127 | result = 1; 128 | } 129 | 130 | return result; 131 | } 132 | 133 | #else 134 | 135 | int 136 | main (void) 137 | { 138 | return 77; /* UNSUPPORTED */ 139 | } 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /.github/workflows/codecov.yml: -------------------------------------------------------------------------------- 1 | name: "Code coverage" 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | skip_duplicates: 9 | continue-on-error: true 10 | runs-on: ubuntu-24.04 11 | outputs: 12 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 13 | steps: 14 | - id: skip_check 15 | uses: fkirc/skip-duplicate-actions@v5 16 | with: 17 | concurrent_skipping: 'same_content_newer' 18 | skip_after_successful_duplicate: 'true' 19 | paths_ignore: '["doc/**", "**/*.md", ".gitignore", "libxcrypt.spec.rpkg", ".packit.yaml", "rpkg.macros", "AUTHORS", "ChangeLog", "COPYING.LIB", "LICENSING", "NEWS", "README", "THANKS", "TODO"]' 20 | do_not_skip: '["workflow_dispatch", "schedule"]' 21 | 22 | O0-Buildflags: 23 | needs: skip_duplicates 24 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 25 | 26 | runs-on: ubuntu-24.04 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | compiler: [gcc, clang] 32 | config_opts: 33 | - "--enable-obsolete-api --enable-hashes=all --enable-failure-tokens" 34 | - "--enable-obsolete-api --enable-obsolete-api-enosys --enable-hashes=all --enable-failure-tokens" 35 | - "--disable-obsolete-api --enable-hashes=all --enable-failure-tokens" 36 | # --enable-hashes=strong can only be used with --disable-obsolete-api 37 | - "--disable-obsolete-api --enable-failure-tokens --enable-hashes=strong" 38 | # failure tokens only affect the generic code so there's no point 39 | # testing with all of the hashes; use descrypt only, to get coverage 40 | # of the --enable-obsolete-api code in this mode, and to get coverage 41 | # of an "only one hash enabled" configuration. 42 | - "--enable-obsolete-api --disable-failure-tokens --enable-hashes=descrypt" 43 | 44 | env: 45 | ac_cv_func_arc4random_buf: "no" 46 | CC: ${{ matrix.compiler }} 47 | CONFIG_OPTS: ${{ matrix.config_opts }} 48 | CFLAGS: "-O0 -g -fprofile-arcs -ftest-coverage" 49 | CXXFLAGS: "-O0 -g -fprofile-arcs -ftest-coverage" 50 | LDFLAGS: "--coverage" 51 | VERBOSE: 1 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v4 56 | 57 | - name: Install packages 58 | run: | 59 | packages="lcov libltdl-dev" 60 | if [ "$CC" = clang ]; then 61 | # need 'llvm' for llvm-cov, as well as clang 62 | packages="$packages clang llvm" 63 | fi 64 | sudo apt-get install $packages 65 | 66 | - name: Versions of build tools 67 | id: build-tools 68 | run: ./build-aux/ci/ci-log-dependency-versions 69 | 70 | - name: Get nprocs 71 | run: echo "NPROCS=$((`nproc --all 2>/dev/null || sysctl -n hw.ncpu` * 2))" | tee $GITHUB_ENV 72 | 73 | - name: Cache bootstrap 74 | id: cache 75 | uses: actions/cache@v4 76 | with: 77 | path: | 78 | INSTALL 79 | Makefile.in 80 | aclocal.m4 81 | config.h.in 82 | configure 83 | autom4te.cache/** 84 | build-aux/m4/libtool.m4 85 | build-aux/m4/ltoptions.m4 86 | build-aux/m4/ltsugar.m4 87 | build-aux/m4/ltversion.m4 88 | build-aux/m4/lt~obsolete.m4 89 | build-aux/m4-autogen/** 90 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 91 | 92 | - name: Bootstrap 93 | if: steps.cache.outputs.cache-hit != 'true' 94 | run: ./autogen.sh 95 | 96 | - name: Configure 97 | run: ./configure $CONFIG_OPTS 98 | 99 | - name: Build 100 | run: | 101 | make -j${{ env.NPROCS }} all 102 | make -j${{ env.NPROCS }} test-programs 103 | 104 | - name: Test 105 | run: make -j${{ env.NPROCS }} check 106 | 107 | - name: Summarize coverage data 108 | run: ./build-aux/ci/summarize-coverage coverage.info 109 | 110 | - name: Upload coverage data to Codecov 111 | uses: codecov/codecov-action@v5 112 | with: 113 | fail_ci_if_error: true 114 | files: coverage.info 115 | token: ${{ secrets.CODECOV_TOKEN }} 116 | verbose: true 117 | 118 | - name: Detailed error logs 119 | if: failure() 120 | run: ./build-aux/ci/ci-log-logfiles 121 | -------------------------------------------------------------------------------- /lib/alg-hmac-sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017, Björn Esser 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | /* 30 | * Implement HMAC as described in RFC 2104 31 | * 32 | */ 33 | 34 | #include "crypt-port.h" 35 | #include "alg-hmac-sha1.h" 36 | #include "alg-sha1.h" 37 | 38 | #include 39 | 40 | #if INCLUDE_sha1crypt 41 | 42 | /* Don't change these */ 43 | #define HMAC_IPAD 0x36 44 | #define HMAC_OPAD 0x5c 45 | 46 | /* Nor this */ 47 | #ifndef HMAC_BLOCKSZ 48 | # define HMAC_BLOCKSZ 64 49 | # define HASH_LENGTH 20 50 | #endif 51 | 52 | /* 53 | * The logic here is lifted straight from RFC 2104 except that 54 | * rather than filling the pads with 0, copying in the key and then 55 | * XOR with the pad byte, we just fill with the pad byte and 56 | * XOR with the key. 57 | */ 58 | void 59 | hmac_sha1_process_data (const uint8_t *text, size_t text_len, 60 | const uint8_t *key, size_t key_len, 61 | void *resbuf) 62 | { 63 | struct sha1_ctx ctx; 64 | /* Inner padding key XOR'd with ipad */ 65 | uint8_t k_ipad[HMAC_BLOCKSZ]; 66 | /* Outer padding key XOR'd with opad */ 67 | uint8_t k_opad[HMAC_BLOCKSZ]; 68 | /* HASH(key) if needed */ 69 | unsigned char tk[HASH_LENGTH]; 70 | size_t i; 71 | 72 | /* 73 | * If key is longer than HMAC_BLOCKSZ bytes 74 | * reset it to key=HASH(key) 75 | */ 76 | if (key_len > HMAC_BLOCKSZ) 77 | { 78 | struct sha1_ctx tctx; 79 | 80 | sha1_init_ctx (&tctx); 81 | sha1_process_bytes (key, &tctx, key_len); 82 | sha1_finish_ctx(&tctx, &tk); 83 | 84 | key = tk; 85 | key_len = HASH_LENGTH; 86 | } 87 | 88 | /* 89 | * The HMAC_ transform looks like: 90 | * 91 | * HASH(K XOR opad, HASH(K XOR ipad, text)) 92 | * 93 | * where K is an n byte key 94 | * ipad is the byte HMAC_IPAD repeated HMAC_BLOCKSZ times 95 | * opad is the byte HMAC_OPAD repeated HMAC_BLOCKSZ times 96 | * and text is the data being protected 97 | */ 98 | 99 | /* 100 | * Fill the pads and XOR in the key 101 | */ 102 | memset (k_ipad, HMAC_IPAD, sizeof k_ipad); 103 | memset (k_opad, HMAC_OPAD, sizeof k_opad); 104 | for (i = 0; i < key_len; i++) 105 | { 106 | k_ipad[i] ^= key[i]; 107 | k_opad[i] ^= key[i]; 108 | } 109 | 110 | /* Clean the stack. */ 111 | explicit_bzero (tk, HASH_LENGTH); 112 | 113 | /* 114 | * Perform inner HASH. 115 | * Start with inner pad, 116 | * then the text. 117 | */ 118 | sha1_init_ctx (&ctx); 119 | sha1_process_bytes (k_ipad, &ctx, HMAC_BLOCKSZ); 120 | sha1_process_bytes (text, &ctx, text_len); 121 | sha1_finish_ctx(&ctx, resbuf); 122 | 123 | /* Clean the stack. */ 124 | explicit_bzero (k_ipad, HMAC_BLOCKSZ); 125 | 126 | /* 127 | * Perform outer HASH. 128 | * Start with the outer pad, 129 | * then the result of the inner hash. 130 | */ 131 | sha1_init_ctx (&ctx); 132 | sha1_process_bytes (k_opad, &ctx, HMAC_BLOCKSZ); 133 | sha1_process_bytes (resbuf, &ctx, HASH_LENGTH); 134 | sha1_finish_ctx(&ctx, resbuf); 135 | 136 | /* Clean the stack. */ 137 | explicit_bzero (k_opad, HMAC_BLOCKSZ); 138 | } 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /lib/libcrypt.minver: -------------------------------------------------------------------------------- 1 | # This file defines the minimum symbol version number used by the 2 | # system-provided libcrypt, for each CPU and OS where libxcrypt can be 3 | # binary backward compatible with it. See also lib/libcrypt.map.in, 4 | # build-aux/scripts/compute-symver-floor, and 5 | # build-aux/scripts/gen-libcrypt-map. 6 | # 7 | # Lines in this file that start with '#' are comments; # is not 8 | # otherwise significant. Blank lines are ignored. All other lines 9 | # must have three or four columns: VERSION, SYSTEM, CPU_FAMILY, 10 | # and PREPROCESSOR_CHECK, in that order. 11 | # 12 | # VERSION is the minimum symbol version to use on hosts where SYSTEM 13 | # and CPU_FAMILY match autoconf's $host_os and $host_cpu values, 14 | # respectively, when interpreted as (Perl) regexes. There is an implicit 15 | # ^ at the beginning of each regex (that is, they must match starting 16 | # at the beginning of the string) but there is no implicit $ at the end 17 | # (that is, they do not have to match the entire string). Use '.' 18 | # to accept any string. 19 | # 20 | # If there is anything more on the line after the CPU_FAMILY field, 21 | # all of it is taken as a preprocessor #if expression which must be 22 | # true for this line's version number to be used. The macros defined 23 | # in are available to this expression. This mechanism is 24 | # for subarchitectures that do not change $host_cpu, e.g. x32 (I wish 25 | # they wouldn't do that...) 26 | # 27 | # The symbol version XCRYPT_2.0 is special; if this file selects that 28 | # version as the minimum for some platform, configure will 29 | # automatically switch into --disable-obsolete-api mode. This is used 30 | # for platforms where either we have not yet implemented binary 31 | # backward compatibility with the system-provided libcrypt, or we know 32 | # there is no system-provided libcrypt to be compatible with. 33 | # 34 | # The symbol version ERROR is special; if this file selects that 35 | # version as the minimum for some platform, configuration will fail. 36 | # This is used for platforms where we know we ought to support 37 | # backward binary compatibility and the library shouldn't be allowed 38 | # to be used until someone's set this up properly. 39 | # 40 | # More specific regexes must be sorted below less specific ones, and 41 | # empty PREPROCESSOR_CHECK must be sorted below non-empty. If neither 42 | # constraint applies, sort entries in descending order of symbol 43 | # version within one SYSTEM, and in alphabetical order of CPU_FAMILY 44 | # within each symbol version. 45 | # 46 | # Future cleanup: the ERROR lines for 'gnu*', 'kfreebsd*gnu*', and 47 | # 'linux*gnu*' can be removed once GNU libc stops shipping libcrypt. 48 | # It will be correct to use XCRYPT_2.0 as the minimum symbol version 49 | # for any platform added to glibc after that release. 50 | 51 | #VERSION SYSTEM CPU_FAMILY PREPROCESSOR_CHECK 52 | 53 | # GNU Hurd 54 | GLIBC_2.38 gnu x86_64 55 | GLIBC_2.2.6 gnu i[3-9]86 56 | ERROR gnu . 57 | 58 | # FreeBSD kernel with GNU libc 59 | GLIBC_2.3 kfreebsd.*gnu x86_64 !(defined __x86_64__ && ULONG_MAX == UINT_MAX) /* not x32 */ 60 | GLIBC_2.3 kfreebsd.*gnu i[3-9]86 61 | ERROR kfreebsd.*gnu . 62 | 63 | # Linux with GNU libc 64 | GLIBC_2.36 linux.*gnu loongarch64 __WORDSIZE == 64 && ULONG_MAX != UINT_MAX /* lp64* ABI */ 65 | GLIBC_2.35 linux.*gnu or1k 66 | GLIBC_2.33 linux.*gnu riscv32 67 | GLIBC_2.32 linux.*gnu arc 68 | GLIBC_2.29 linux.*gnu csky 69 | GLIBC_2.27 linux.*gnu riscv64 70 | GLIBC_2.21 linux.*gnu nios2 71 | GLIBC_2.18 linux.*gnu microblaze 72 | GLIBC_2.17 linux.*gnu aarch64 73 | GLIBC_2.17 linux.*gnu powerpc64le 74 | GLIBC_2.16 linux.*gnu x86_64 defined __x86_64__ && ULONG_MAX == UINT_MAX /* x32 */ 75 | GLIBC_2.12 linux.*gnu tilegx 76 | GLIBC_2.12 linux.*gnu tilepro 77 | GLIBC_2.4 linux.*gnu arm 78 | GLIBC_2.4 linux.*gnu m68k defined __mcoldfire__ 79 | GLIBC_2.3 linux.*gnu powerpc64 80 | GLIBC_2.2.5 linux.*gnu x86_64 defined __x86_64__ && ULONG_MAX != UINT_MAX /* 64 */ 81 | GLIBC_2.2 linux.*gnu s390x 82 | GLIBC_2.0 linux.*gnu alpha 83 | GLIBC_2.0 linux.*gnu e2k 84 | GLIBC_2.0 linux.*gnu hppa 85 | GLIBC_2.0 linux.*gnu i[3-9]86 86 | GLIBC_2.0 linux.*gnu ia64 87 | GLIBC_2.0 linux.*gnu m68k 88 | GLIBC_2.0 linux.*gnu mips 89 | GLIBC_2.0 linux.*gnu powerpc 90 | GLIBC_2.0 linux.*gnu s390 91 | GLIBC_2.0 linux.*gnu sh 92 | GLIBC_2.0 linux.*gnu sparc 93 | GLIBC_2.0 linux.*gnu x86_64 94 | ERROR linux.*gnu . 95 | 96 | # Other systems. 97 | XCRYPT_2.0 . . 98 | -------------------------------------------------------------------------------- /test/preferred-method.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 Björn Esser 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | #include 21 | 22 | #define PASSPHRASE "Ob-La-Di, Ob-La-Da" 23 | 24 | int 25 | main (void) 26 | { 27 | const char *pm = crypt_preferred_method(); 28 | int retval = 0; 29 | 30 | #if defined HASH_ALGORITHM_DEFAULT 31 | if (pm == NULL) 32 | { 33 | printf ("FAIL: crypt_preferred_method returned NULL.\n"); 34 | retval = 1; 35 | } 36 | else 37 | { 38 | printf ("PASS: crypt_preferred_method returned \"%s\".\n", pm); 39 | 40 | char gs[CRYPT_GENSALT_OUTPUT_SIZE]; 41 | struct crypt_data cd; 42 | 43 | crypt_gensalt_rn (NULL, 0, NULL, 0, gs, sizeof (gs)); 44 | 45 | if (strncmp (gs, pm, strlen (pm))) 46 | { 47 | printf ("FAIL: crypt_preferred_method: \"%s\" ", pm); 48 | printf ("differs from default prefix.\n"); 49 | printf ("crypt_gensalt returned: \"%s\".\n", gs); 50 | retval = 1; 51 | } 52 | else 53 | { 54 | printf ("PASS: crypt_preferred_method: \"%s\" ", pm); 55 | printf ("is the same as default prefix used by "); 56 | printf ("crypt_gensalt.\n"); 57 | } 58 | 59 | crypt_gensalt_rn (pm, 0, NULL, 0, gs, sizeof (gs)); 60 | 61 | if (gs[0] == '*') 62 | { 63 | printf ("FAIL: crypt_preferred_method: \"%s\" ", pm); 64 | printf ("is not a valid prefix for crypt_gensalt.\n"); 65 | printf ("crypt_gensalt returned: \"%s\".\n", gs); 66 | retval = 1; 67 | } 68 | else 69 | { 70 | printf ("PASS: crypt_preferred_method: \"%s\" ", pm); 71 | printf ("is a valid prefix for crypt_gensalt.\n"); 72 | } 73 | 74 | if (strncmp (gs, pm, strlen (pm))) 75 | { 76 | printf ("FAIL: crypt_preferred_method: \"%s\" ", pm); 77 | printf ("does not generate a setting for "); 78 | printf ("the intended method.\n"); 79 | printf ("crypt_gensalt returned: \"%s\".\n", gs); 80 | retval = 1; 81 | } 82 | else 83 | { 84 | printf ("PASS: crypt_preferred_method: \"%s\" ", pm); 85 | printf ("does generate a setting for "); 86 | printf ("the intended method.\n"); 87 | } 88 | 89 | crypt_r (PASSPHRASE, gs, &cd); 90 | 91 | if (cd.output[0] == '*') 92 | { 93 | printf ("FAIL: crypt_preferred_method: \"%s\" ", pm); 94 | printf ("is not a valid prefix for crypt.\n"); 95 | printf ("crypt returned: \"%s\".\n", gs); 96 | retval = 1; 97 | } 98 | else 99 | { 100 | printf ("PASS: crypt_preferred_method: \"%s\" ", pm); 101 | printf ("is a valid prefix for crypt.\n"); 102 | } 103 | 104 | if (strncmp (cd.output, pm, strlen (pm))) 105 | { 106 | printf ("FAIL: crypt_preferred_method: \"%s\" ", pm); 107 | printf ("does not generate a hash with "); 108 | printf ("the intended method.\n"); 109 | printf ("crypt returned: \"%s\".\n", gs); 110 | retval = 1; 111 | } 112 | else 113 | { 114 | printf ("PASS: crypt_preferred_method: \"%s\" ", pm); 115 | printf ("does generate a hash with "); 116 | printf ("the intended method.\n"); 117 | } 118 | } 119 | #else 120 | if (pm != NULL) 121 | { 122 | printf ("FAIL: crypt_preferred_method returned: \"%s\" ", pm); 123 | printf ("instead of NULL.\n"); 124 | retval = 1; 125 | } 126 | else 127 | { 128 | printf ("PASS: crypt_preferred_method returned NULL."); 129 | } 130 | #endif 131 | 132 | return retval; 133 | } 134 | -------------------------------------------------------------------------------- /test/crypt-sm3-yescrypt.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * Copyright (C) 2018, 2024 Björn Esser besser82@fedoraproject.org 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 8 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 11 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 14 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 16 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 17 | * SUCH DAMAGE. 18 | */ 19 | 20 | #include "crypt-port.h" 21 | 22 | #if INCLUDE_sm3_yescrypt 23 | 24 | #include "alg-sm3-hmac.h" 25 | 26 | #include 27 | 28 | /* redefine outer hmac to this function to test entropy bypass */ 29 | static void 30 | test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 31 | uint8_t *out, sm3_hmac_ctx_t *sm3buf); 32 | #define outer_sm3_hmac test_outer_hmac 33 | #include "../lib/crypt-sm3-yescrypt.c" 34 | 35 | static int test_mode = 0; 36 | 37 | static void 38 | test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 39 | uint8_t *out, sm3_hmac_ctx_t *sm3buf) 40 | { 41 | const uint8_t zero[32] = {0}; 42 | 43 | /* Zero one of arguments to outer hmac. */ 44 | if (test_mode & 1) 45 | { 46 | k = zero; 47 | n = sizeof (zero); 48 | } 49 | if (test_mode & 2) 50 | { 51 | t = zero; 52 | len = sizeof (zero); 53 | } 54 | sm3_hmac (k, n, t, len, out, sm3buf); 55 | } 56 | 57 | static int 58 | test_crypt_raw (int m, int p, int s, char **a, size_t *a_size) 59 | { 60 | char output[CRYPT_OUTPUT_SIZE]; 61 | char pass[CRYPT_MAX_PASSPHRASE_SIZE]; 62 | char pref[CRYPT_GENSALT_OUTPUT_SIZE]; 63 | char scratch[ALG_SPECIFIC_SIZE]; 64 | char *salt; 65 | 66 | test_mode = m; 67 | fprintf (stderr, "."); 68 | snprintf (pass, sizeof (pass), "%d", p); 69 | snprintf (pref, sizeof (pref), "%15d", s); 70 | salt = crypt_gensalt ("$sm3y$", 0, pref, (int) strlen(pref) + 1); 71 | if (!salt || salt[0] == '*') 72 | { 73 | fprintf(stderr, "ERROR: entropy test (gensalt) [%s]\n", pref); 74 | return 1; 75 | } 76 | crypt_sm3_yescrypt_rn (pass, strlen (pass), salt, strlen (salt), 77 | (uint8_t *) output, sizeof (output), 78 | scratch, sizeof (scratch)); 79 | if (output[0] == '*') 80 | { 81 | fprintf(stderr, "ERROR: entropy test (crypt)\n"); 82 | return 1; 83 | } 84 | char *h = strrchr (output, '$') + 1; 85 | if (*a && strstr (*a, h)) 86 | { 87 | fprintf (stderr, "ERROR: duplicated hash %s\n", output); 88 | return 1; 89 | } 90 | size_t len = strlen(h); 91 | *a = realloc (*a, *a_size + len + 1); 92 | strcpy (*a + *a_size, h); 93 | *a_size += len; 94 | (*a)[*a_size] = '\0'; 95 | 96 | return 0; 97 | } 98 | 99 | int 100 | main (void) 101 | { 102 | int result = 0; 103 | 104 | /* Entropy tests 105 | * Replace left then right argument of outer hmac() with constant 106 | * and do hashing, verifying that output hashes are still different 107 | * when password or salt are changing. 108 | * Thus, we prove that entropy is still passing to the output not 109 | * depending on yescrypt. */ 110 | 111 | int m, pp, ss; 112 | int etest = 0; 113 | char **a = malloc (sizeof (char*)); 114 | size_t *a_size = malloc (sizeof (size_t)); 115 | 116 | *a = malloc (sizeof (char)); 117 | (*a)[0] = '\0'; 118 | *a_size = 0; 119 | 120 | for (m = 1; m < 3; m++) 121 | { 122 | for (pp = 0; pp < 22; pp++) 123 | etest |= test_crypt_raw (m, pp, 0, a, a_size); 124 | for (ss = 0; ss < 22; ss++) 125 | etest |= test_crypt_raw (m, pp, ss, a, a_size); 126 | } 127 | fprintf (stderr, "\n"); 128 | if (etest) 129 | fprintf (stderr, "ERROR: entropy test failed.\n"); 130 | else 131 | fprintf (stderr, " ok: entropy test\n"); 132 | result |= etest; 133 | 134 | free (*a); 135 | free (a); 136 | free (a_size); 137 | 138 | return result; 139 | } 140 | 141 | #else 142 | 143 | int 144 | main (void) 145 | { 146 | return 77; /* UNSUPPORTED */ 147 | } 148 | 149 | #endif /* INCLUDE_sm3_yescrypt */ 150 | -------------------------------------------------------------------------------- /lib/alg-sha256.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2005-2016 Colin Percival 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _SHA256_H_ 28 | #define _SHA256_H_ 29 | 30 | #include "crypt-port.h" 31 | 32 | #include 33 | #include 34 | 35 | /* 36 | * Use #defines in order to avoid namespace collisions with anyone else's 37 | * SHA256 code (e.g., the code in OpenSSL). 38 | */ 39 | #define SHA256_Init libcperciva_SHA256_Init 40 | #define SHA256_Update libcperciva_SHA256_Update 41 | #define SHA256_Final libcperciva_SHA256_Final 42 | #define SHA256_Buf libcperciva_SHA256_Buf 43 | #define SHA256_CTX libcperciva_SHA256_CTX 44 | #define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init 45 | #define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update 46 | #define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final 47 | #define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf 48 | #define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX 49 | 50 | /* Context structure for SHA256 operations. */ 51 | typedef struct { 52 | uint32_t state[8]; 53 | uint64_t count; 54 | uint8_t buf[64]; 55 | } SHA256_CTX; 56 | 57 | /** 58 | * SHA256_Init(ctx): 59 | * Initialize the SHA256 context ${ctx}. 60 | */ 61 | extern void SHA256_Init(SHA256_CTX *); 62 | 63 | /** 64 | * SHA256_Update(ctx, in, len): 65 | * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. 66 | */ 67 | extern void SHA256_Update(SHA256_CTX *, const void *, size_t); 68 | 69 | /** 70 | * SHA256_Final(digest, ctx): 71 | * Output the SHA256 hash of the data input to the context ${ctx} into the 72 | * buffer ${digest}. 73 | */ 74 | extern void SHA256_Final(uint8_t[32], SHA256_CTX *); 75 | 76 | /** 77 | * SHA256_Buf(in, len, digest): 78 | * Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}. 79 | */ 80 | extern void SHA256_Buf(const void *, size_t, uint8_t[32]); 81 | 82 | /* Context structure for HMAC-SHA256 operations. */ 83 | typedef struct { 84 | SHA256_CTX ictx; 85 | SHA256_CTX octx; 86 | } HMAC_SHA256_CTX; 87 | 88 | /** 89 | * HMAC_SHA256_Init(ctx, K, Klen): 90 | * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from 91 | * ${K}. 92 | */ 93 | extern void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); 94 | 95 | /** 96 | * HMAC_SHA256_Update(ctx, in, len): 97 | * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. 98 | */ 99 | extern void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); 100 | 101 | /** 102 | * HMAC_SHA256_Final(digest, ctx): 103 | * Output the HMAC-SHA256 of the data input to the context ${ctx} into the 104 | * buffer ${digest}. 105 | */ 106 | extern void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); 107 | 108 | /** 109 | * HMAC_SHA256_Buf(K, Klen, in, len, digest): 110 | * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of 111 | * length ${Klen}, and write the result to ${digest}. 112 | */ 113 | extern void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); 114 | 115 | /** 116 | * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): 117 | * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and 118 | * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). 119 | */ 120 | extern void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, 121 | uint64_t, uint8_t *, size_t); 122 | 123 | #endif /* !_SHA256_H_ */ 124 | -------------------------------------------------------------------------------- /test/crypt-gost-yescrypt.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * Copyright (C) 2018 Björn Esser besser82@fedoraproject.org 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted. 6 | * 7 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 8 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 11 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 14 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 15 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 16 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 17 | * SUCH DAMAGE. 18 | */ 19 | 20 | #include "crypt-port.h" 21 | 22 | #if INCLUDE_gost_yescrypt 23 | 24 | #include "alg-gost3411-2012-hmac.h" 25 | 26 | #include 27 | 28 | /* redefine outer hmac to this function to test entropy bypass */ 29 | static void 30 | test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 31 | uint8_t *out32, gost_hmac_256_t *gostbuf); 32 | #define outer_gost_hmac256 test_outer_hmac 33 | #include "../lib/crypt-gost-yescrypt.c" 34 | 35 | static int test_mode = 0; 36 | 37 | static void 38 | test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, 39 | uint8_t *out32, gost_hmac_256_t *gostbuf) 40 | { 41 | const uint8_t zero[32] = {0}; 42 | 43 | /* Zero one of arguments to outer hmac. */ 44 | if (test_mode & 1) 45 | { 46 | k = zero; 47 | n = sizeof (zero); 48 | } 49 | if (test_mode & 2) 50 | { 51 | t = zero; 52 | len = sizeof (zero); 53 | } 54 | gost_hmac256 (k, n, t, len, out32, gostbuf); 55 | } 56 | 57 | static int 58 | test_crypt_raw (int m, int p, int s, char **a, size_t *a_size) 59 | { 60 | char output[CRYPT_OUTPUT_SIZE]; 61 | char pass[CRYPT_MAX_PASSPHRASE_SIZE]; 62 | char pref[CRYPT_GENSALT_OUTPUT_SIZE]; 63 | char scratch[ALG_SPECIFIC_SIZE]; 64 | char *salt; 65 | 66 | test_mode = m; 67 | fprintf (stderr, "."); 68 | snprintf (pass, sizeof (pass), "%d", p); 69 | snprintf (pref, sizeof (pref), "%15d", s); 70 | salt = crypt_gensalt ("$gy$", 0, pref, (int) strlen(pref) + 1); 71 | if (!salt || salt[0] == '*') 72 | { 73 | fprintf(stderr, "ERROR: entropy test (gensalt) [%s]\n", pref); 74 | return 1; 75 | } 76 | crypt_gost_yescrypt_rn (pass, strlen (pass), salt, strlen (salt), 77 | (uint8_t *) output, sizeof (output), 78 | scratch, sizeof (scratch)); 79 | if (output[0] == '*') 80 | { 81 | fprintf(stderr, "ERROR: entropy test (crypt)\n"); 82 | return 1; 83 | } 84 | char *h = strrchr (output, '$') + 1; 85 | if (*a && strstr (*a, h)) 86 | { 87 | fprintf (stderr, "ERROR: duplicated hash %s\n", output); 88 | return 1; 89 | } 90 | size_t len = strlen(h); 91 | *a = realloc (*a, *a_size + len + 1); 92 | strcpy (*a + *a_size, h); 93 | *a_size += len; 94 | (*a)[*a_size] = '\0'; 95 | 96 | return 0; 97 | } 98 | 99 | int 100 | main (void) 101 | { 102 | int result = 0; 103 | 104 | /* Entropy tests 105 | * Replace left then right argument of outer hmac() with constant 106 | * and do hashing, verifying that output hashes are still different 107 | * when password or salt are changing. 108 | * Thus, we prove that entropy is still passing to the output not 109 | * depending on yescrypt. */ 110 | 111 | int m, pp, ss; 112 | int etest = 0; 113 | char **a = malloc (sizeof (char*)); 114 | size_t *a_size = malloc (sizeof (size_t)); 115 | 116 | *a = malloc (sizeof (char)); 117 | (*a)[0] = '\0'; 118 | *a_size = 0; 119 | 120 | for (m = 1; m < 3; m++) 121 | { 122 | for (pp = 0; pp < 22; pp++) 123 | etest |= test_crypt_raw (m, pp, 0, a, a_size); 124 | for (ss = 0; ss < 22; ss++) 125 | etest |= test_crypt_raw (m, pp, ss, a, a_size); 126 | } 127 | fprintf (stderr, "\n"); 128 | if (etest) 129 | fprintf (stderr, "ERROR: entropy test failed.\n"); 130 | else 131 | fprintf (stderr, " ok: entropy test\n"); 132 | result |= etest; 133 | 134 | free (*a); 135 | free (a); 136 | free (a_size); 137 | 138 | return result; 139 | } 140 | 141 | #else 142 | 143 | int 144 | main (void) 145 | { 146 | return 77; /* UNSUPPORTED */ 147 | } 148 | 149 | #endif /* INCLUDE_gost_yescrypt */ 150 | -------------------------------------------------------------------------------- /lib/crypt-nthash.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1998-1999 Whistle Communications, Inc. 3 | * Copyright (c) 1998-1999 Archie Cobbs 4 | * Copyright (c) 2003 Michael Bretterklieber 5 | * Copyright (c) 2017-2019 Björn Esser 6 | * Copyright (c) 2017-2019 Zack Weinberg 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #include "crypt-port.h" 32 | 33 | #if INCLUDE_nt 34 | 35 | #include "alg-md4.h" 36 | 37 | #include 38 | #include 39 | 40 | #define MD4_HASHLEN 16 41 | 42 | typedef struct 43 | { 44 | MD4_CTX ctx; 45 | uint8_t unipw[CRYPT_MAX_PASSPHRASE_SIZE * 2]; 46 | unsigned char hash[MD4_HASHLEN]; 47 | } crypt_nt_internal_t; 48 | 49 | static_assert (sizeof (crypt_nt_internal_t) <= ALG_SPECIFIC_SIZE, 50 | "ALG_SPECIFIC_SIZE is too small for NTHASH."); 51 | 52 | /* 53 | * NT HASH = md4(str2unicode(phrase)) 54 | */ 55 | 56 | void 57 | crypt_nt_rn (const char *phrase, size_t phr_size, 58 | const char *setting, size_t ARG_UNUSED (set_size), 59 | uint8_t *output, size_t out_size, 60 | void *scratch, size_t scr_size) 61 | { 62 | static const char *magic = "$3$"; 63 | static const uint8_t *hexconvtab = (const uint8_t*) "0123456789abcdef"; 64 | 65 | if ((out_size < strlen (magic) + MD4_HASHLEN * 2 + 1) || 66 | (scr_size < sizeof (crypt_nt_internal_t))) 67 | { 68 | errno = ERANGE; 69 | return; 70 | } 71 | 72 | if (strncmp (setting, magic, strlen (magic))) 73 | { 74 | errno = EINVAL; 75 | return; 76 | } 77 | 78 | crypt_nt_internal_t *intbuf = scratch; 79 | 80 | /* Convert the input to UCS-2LE, blindly assuming that it was 81 | IANA ISO_8859-1:1987 to begin with (i.e. 0x00 .. 0xFF 82 | encode U+0000 .. U+FFFF; technically this is a superset 83 | of the original ISO 8859.1). Note that this does not 84 | U+0000-terminate intbuf->unipw. */ 85 | for (size_t i = 0; i < phr_size; i++) 86 | { 87 | intbuf->unipw[2*i ] = (uint8_t)phrase[i]; 88 | intbuf->unipw[2*i + 1] = 0x00; 89 | } 90 | 91 | /* Compute MD4 of Unicode password. */ 92 | MD4_Init (&intbuf->ctx); 93 | MD4_Update (&intbuf->ctx, intbuf->unipw, phr_size * 2); 94 | MD4_Final (intbuf->hash, &intbuf->ctx); 95 | 96 | /* Write the computed hash to the output buffer. */ 97 | output += strcpy_or_abort (output, out_size, magic); 98 | *output++ = '$'; 99 | for (size_t i = 0; i < MD4_HASHLEN; i++) 100 | { 101 | *output++ = hexconvtab[intbuf->hash[i] >> 4]; 102 | *output++ = hexconvtab[intbuf->hash[i] & 0xf]; 103 | } 104 | *output = '\0'; 105 | } 106 | 107 | /* This function simply returns the magic string '$3$', 108 | so it can be used as SETTING for the crypt function. */ 109 | void 110 | gensalt_nt_rn (unsigned long count, 111 | ARG_UNUSED(const uint8_t *rbytes), 112 | ARG_UNUSED(size_t nrbytes), 113 | uint8_t *output, 114 | size_t o_size) 115 | { 116 | const char *prefix = "$3$"; 117 | 118 | /* Minimal O_SIZE to store the prefix. */ 119 | if (o_size < strlen (prefix) + 1) 120 | { 121 | errno = ERANGE; 122 | return; 123 | } 124 | 125 | if (count != 0) 126 | { 127 | errno = EINVAL; 128 | return; 129 | } 130 | 131 | strcpy_or_abort (output, o_size, prefix); 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /test/symbols-compat.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # Written by Zack Weinberg in 2017 and 2020. 3 | # To the extent possible under law, Zack Weinberg has waived all 4 | # copyright and related or neighboring rights to this work. 5 | # 6 | # See https://creativecommons.org/publicdomain/zero/1.0/ for further 7 | # details. 8 | 9 | # This test is only run if we are building a shared library intended 10 | # to be binary backward compatible with GNU libc (libcrypt.so.1). 11 | # It locates any installed version of libcrypt.so.1, and verifies that 12 | # each public symbol exposed by that library is also exposed by our 13 | # libcrypt.so.1 with a matching symbol version. 14 | # 15 | # Due to limitations in Automake, this program takes parameters from 16 | # the environment: 17 | # $lib_la - full pathname of libcrypt.la 18 | # $SYMBOL_PREFIX - prefix, if any, added to global symbols defined from C 19 | # $CC, $NM - names of tools to run (defaults to 'cc' and 'nm' respectively) 20 | # $CFLAGS, $LDFLAGS - options to pass to $CC when linking (default: empty) 21 | 22 | use v5.14; # implicit use strict, use feature ':5.14' 23 | use warnings FATAL => 'all'; 24 | use utf8; 25 | use open qw(:std :utf8); 26 | no if $] >= 5.022, warnings => 'experimental::re_strict'; 27 | use if $] >= 5.022, re => 'strict'; 28 | 29 | use FindBin (); 30 | use lib $FindBin::Bin; 31 | use TestCommon qw( 32 | compare_symbol_lists 33 | ensure_C_locale 34 | find_real_library 35 | get_symbols 36 | popen 37 | sh_split 38 | skip 39 | subprocess_error 40 | which 41 | ); 42 | 43 | # Some differences between the symbols exported by heritage libcrypt.so.1 44 | # and our libcrypt.so.1 are expected: 45 | # 46 | # * All of the symbols we define with GLIBC_2.xx version tags are 47 | # compatibility symbols (nm prints only one @); naturally, 48 | # glibc-provided libcrypt.so.1 defines some of those symbols as 49 | # linkable symbols (two @). 50 | # 51 | # * Older versions of libcrypt defined five symbols as linkable, 52 | # with the XCRYPT_2.0 version tag, which are now compatibility-only: 53 | # crypt_gensalt_r, xcrypt, xcrypt_gensalt, xcrypt_gensalt_r, and 54 | # xcrypt_r. 55 | # 56 | # This sub is applied to the symbol listing from the system-provided 57 | # libcrypt.so.1; it edits that listing so that the comparison below 58 | # succeeds despite any expected differences. 59 | sub filter_expected_differences { 60 | my $symbols = shift; 61 | my %filtered; 62 | my $formerly_linkable = qr{ 63 | ^ (?: crypt_gensalt_r 64 | | xcrypt(?: _r)? 65 | | xcrypt_gensalt(?: _r)? 66 | ) @@ 67 | }x; 68 | for my $s (keys %{$symbols}) { 69 | $s =~ s/\b@@(?=GLIBC_)/@/; 70 | $s =~ s/\b@@(?=XCRYPT_2\.0)/@/ if $s =~ $formerly_linkable; 71 | $filtered{$s} = 1; 72 | } 73 | return \%filtered; 74 | } 75 | 76 | sub find_system_libcrypt { 77 | # Ask the compiler whether a libcrypt.so.1 exists in its search 78 | # path. The compiler option -print-file-name should be supported 79 | # on all operating systems where there's an older libcrypt that we 80 | # can be backward compatible with. 81 | state @CC; 82 | if (!@CC) { 83 | @CC = which($ENV{CC} || 'cc'); 84 | skip('C compiler not available') unless @CC; 85 | } 86 | 87 | state @CFLAGS; 88 | if (!@CFLAGS) { 89 | @CFLAGS = sh_split($ENV{CFLAGS} || q{}); 90 | } 91 | state @LDFLAGS; 92 | if (!@LDFLAGS) { 93 | @LDFLAGS = sh_split($ENV{LDFLAGS} || q{}); 94 | } 95 | 96 | my $fh = 97 | popen('-|', @CC, @CFLAGS, @LDFLAGS, '-print-file-name=libcrypt.so.1'); 98 | my $path; 99 | { 100 | local $/ = undef; # slurp 101 | $path = <$fh>; 102 | } 103 | close $fh or subprocess_error($CC[0]); 104 | 105 | chomp $path; 106 | # If we get back either the empty string or the same string we put 107 | # in, it means there is no libcrypt.so.1 on this system. 108 | if ($path eq q{} || $path eq 'libcrypt.so.1') { 109 | skip('no system-provided libcrypt.so.1'); 110 | } 111 | return $path; 112 | } 113 | 114 | sub get_our_symbols { 115 | return get_symbols(find_real_library(shift, 'shared')); 116 | } 117 | 118 | sub get_their_symbols { 119 | return filter_expected_differences(get_symbols(find_system_libcrypt())); 120 | } 121 | 122 | # 123 | # Main 124 | # 125 | my $lib_la = $ENV{lib_la} || '/nonexistent'; 126 | if (!-f $lib_la) { 127 | print {*STDERR} "usage: lib_la=/path/to/library.la $0"; 128 | exit 1; 129 | } 130 | 131 | ensure_C_locale(); 132 | exit compare_symbol_lists( 133 | get_our_symbols($lib_la), 134 | get_their_symbols(), 135 | 'symbol versions', 136 | 1, # extra symbols are allowed 137 | ); 138 | -------------------------------------------------------------------------------- /test/crypt-too-long-phrase.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Björn Esser 3 | * All rights reserved. 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted. 7 | * 8 | * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "crypt-port.h" 18 | #include 19 | #include 20 | #include 21 | 22 | static const char *settings[] = 23 | { 24 | #if INCLUDE_descrypt 25 | "Mp", 26 | #endif 27 | #if INCLUDE_bigcrypt 28 | "Mp............", 29 | #endif 30 | #if INCLUDE_bsdicrypt 31 | "_J9..MJHn", 32 | #endif 33 | #if INCLUDE_md5crypt 34 | "$1$MJHnaAke", 35 | #endif 36 | #if INCLUDE_nt 37 | "$3$", 38 | #endif 39 | #if INCLUDE_sunmd5 40 | "$md5$BPm.fm03$", 41 | #endif 42 | #if INCLUDE_sm3crypt 43 | "$sm3$MJHnaAkegEVYHsFK", 44 | #endif 45 | #if INCLUDE_sha1crypt 46 | "$sha1$248488$ggu.H673kaZ5$", 47 | #endif 48 | #if INCLUDE_sha256crypt 49 | "$5$MJHnaAkegEVYHsFK", 50 | #endif 51 | #if INCLUDE_sha512crypt 52 | "$6$MJHnaAkegEVYHsFK", 53 | #endif 54 | #if INCLUDE_bcrypt_a 55 | "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO", 56 | #endif 57 | #if INCLUDE_bcrypt 58 | "$2b$05$UBVLHeMpJ/QQCv3XqJx8zO", 59 | #endif 60 | #if INCLUDE_bcrypt_y 61 | "$2y$05$UBVLHeMpJ/QQCv3XqJx8zO", 62 | #endif 63 | #if INCLUDE_bcrypt_x 64 | "$2x$05$UBVLHeMpJ/QQCv3XqJx8zO", 65 | #endif 66 | #if INCLUDE_yescrypt 67 | "$y$j9T$MJHnaAkegEVYHsFKkmfzJ1", 68 | #endif 69 | #if INCLUDE_scrypt 70 | "$7$CU..../....MJHnaAkegEVYHsFKkmfzJ1", 71 | #endif 72 | #if INCLUDE_gost_yescrypt 73 | "$gy$j9T$MJHnaAkegEVYHsFKkmfzJ1", 74 | #endif 75 | #if INCLUDE_sm3_yescrypt 76 | "$sm3y$j9T$MJHnaAkegEVYHsFKkmfzJ1", 77 | #endif 78 | }; 79 | 80 | int 81 | main (void) 82 | { 83 | char *retval = NULL; 84 | char phrase[CRYPT_MAX_PASSPHRASE_SIZE * 2]; 85 | int status = 0; 86 | struct crypt_data crypt_ctx; 87 | 88 | memset (phrase, 'a', sizeof phrase); 89 | phrase[sizeof phrase - 1] = '\0'; 90 | 91 | for (size_t i = 0; i < ARRAY_SIZE (settings); i++) 92 | { 93 | struct crypt_data *cd = &crypt_ctx; 94 | void **data = (void **) &cd; 95 | int size = sizeof crypt_ctx; 96 | 97 | memset (cd, 0, sizeof crypt_ctx); 98 | errno = 0; 99 | retval = crypt (phrase, settings[i]); 100 | 101 | if ((retval && retval[0] != '*') || errno != ERANGE) 102 | { 103 | printf ("crypt(3) returned unexpectedly.\n" 104 | "setting: %s\ngot: %s\nERRNO: %d, %s\n", 105 | settings[i], retval, errno, strerror (errno)); 106 | status = 1; 107 | } 108 | 109 | errno = 0; 110 | retval = crypt_r (phrase, settings[i], cd); 111 | 112 | if ((retval && retval[0] != '*') || errno != ERANGE) 113 | { 114 | printf ("crypt_r(3) returned unexpectedly.\n" 115 | "setting: %s\ngot: %s\nERRNO: %d, %s\n", 116 | settings[i], retval, errno, strerror (errno)); 117 | status = 1; 118 | } 119 | 120 | errno = 0; 121 | retval = crypt_rn (phrase, settings[i], cd, size); 122 | 123 | if (retval || errno != ERANGE) 124 | { 125 | printf ("crypt_rn(3) returned unexpectedly.\n" 126 | "setting: %s\ngot: %s\nERRNO: %d, %s\n", 127 | settings[i], retval, errno, strerror (errno)); 128 | status = 1; 129 | } 130 | 131 | errno = 0; 132 | retval = crypt_ra (phrase, settings[i], data, &size); 133 | 134 | if (retval || errno != ERANGE) 135 | { 136 | printf ("crypt_ra(3) (pre-alloc) returned unexpectedly.\n" 137 | "setting: %s\ngot: %s\nERRNO: %d, %s\n", 138 | settings[i], retval, errno, strerror (errno)); 139 | status = 1; 140 | } 141 | 142 | *data = NULL; 143 | size = 0; 144 | errno = 0; 145 | retval = crypt_ra (phrase, settings[i], data, &size); 146 | 147 | if (retval || errno != ERANGE) 148 | { 149 | printf ("crypt_ra(3) (new alloc) returned unexpectedly.\n" 150 | "setting: %s\ngot: %s\nERRNO: %d, %s\n", 151 | settings[i], retval, errno, strerror (errno)); 152 | status = 1; 153 | } 154 | free (*data); 155 | } 156 | return status; 157 | } 158 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | to-do list for libxcrypt 2 | ------------------------ 3 | 4 | This list is categorized but not in any kind of priority order. 5 | It was last updated 20 October 2018. 6 | 7 | * Code cleanliness 8 | * Find and remove any code that still does dodgy things with type punning 9 | * Factor out all of the repetitive base64 code 10 | * Factor out the multiple implementations of HMAC and PBKDF 11 | 12 | * Testsuite improvements 13 | * Investigate branch coverage 14 | * Do some API fuzz testing and add missing cases to the testsuite 15 | * Many of the `test-crypt-*.c` files repeat more or less the same 16 | code with different data, consider merging them 17 | 18 | * Portability 19 | * Make sure the symbol versioning macros work with all of the 20 | compilers that anyone needs (they use GCC extensions that clang 21 | also supports). 22 | 23 | * Hardening 24 | * bcrypt-like selftest/memory scribble for all hashing methods 25 | * how do we know the memory scribble is doing its job? 26 | * build out of the box with compiler hardening features turned on 27 | * something bespoke for not having to write serialization and 28 | deserialization logic for hash strings by hand, as this is 29 | probably the most error-prone part of writing a hashing method 30 | 31 | * the most sensitive piece of data handled by this library is a 32 | cleartext passphrase. OS may have trusted-path facilities for 33 | prompting the user for a passphrase and feeding it to a KDF 34 | without its ever being accessible in normal memory. investigate 35 | whether we can use these. 36 | 37 | * Additional hashing methods 38 | * Argon2 39 | * ...? 40 | 41 | * Runtime configurability (in progress on the [crypt.conf branch][]) 42 | * allow installations to enable or disable specific hash methods 43 | without rebuilding the library 44 | * make the default cost parameter used by `crypt_gensalt_*` for new 45 | hashes configurable 46 | * update the compiled-in defaults used by `crypt_gensalt_*` (not the 47 | defaults used when no explicit cost parameter is present in a 48 | hash; those can’t be changed without breaking existing stored hashes) 49 | * relevant benchmarking at 50 | 51 | * offer a way to tune cost parameters for a specific installation 52 | * N.B. Solaris 11 has all of these features but our implementation will 53 | probably not match them (they have a `crypt.conf` but it’s not the 54 | same, and their `crypt_gensalt` is API-incompatible anyway). 55 | 56 | [crypt.conf branch]: https://github.com/besser82/libxcrypt/tree/zack/crypt.conf 57 | 58 | * Potential API enhancements: 59 | 60 | * Support for "pepper" (an additional piece of information, _not_ 61 | stored in the password file, that you need to check a password) 62 | 63 | * Reading passphrases from the terminal is finicky and there are 64 | several competing, poorly portable, questionably sound library 65 | functions to do it (`getpass`, `readpassphrase`, etc) -- should we 66 | incorporate one? 67 | * If we do, should it know how to trigger the trusted-path 68 | password prompt in modern GUI environments? (probably) 69 | 70 | * Make the crypt and crypt_gensalt static state thread-specific? 71 | * Solaris 11 may have done this (its `crypt(3)` manpage describes 72 | it as MT-Safe and I don’t see any other way they could have 73 | accomplished that). 74 | * if allocated on first use, this would also shave 32kB of 75 | data segment off the shared library 76 | * alternatively, add a global lock and *crash the program* if we 77 | detect concurrent calls 78 | 79 | * Allow access to more of yescrypt’s tunable parameters and ROM 80 | feature, in a way that’s generic enough that we could also use it 81 | for e.g. Argon2’s tunable parameters 82 | 83 | * Other yescrypt-inspired features relevant to using this library to 84 | back a “dedicated authentication service,” e.g. preallocation of 85 | large blocks of scratch memory 86 | * the main obstacles here are that `struct crypt_data` has a fixed 87 | size which is either too big or too small depending how you look 88 | at it, and no destructor function 89 | 90 | * Permissive relicensing, to encourage use beyond the GNU ecosystem? 91 | * Replace crypt-md5.c with original md5crypt from FreeBSD? 92 | * Other files subject to the (L)GPL are crypt.c, crypt-static.c, 93 | crypt-gensalt-static.c, crypt-obsolete.h, crypt-port.h, 94 | test-badsalt.c. It is not clear to me how much material originally 95 | assigned to the FSF remains in these files. 96 | Several of them are API definitions and trivial wrappers that 97 | could not be meaningfully changed without breaking them (so are 98 | arguably uncopyrightable). 99 | * Most of the test suite lacks any license or even authorship 100 | information. We would have to track down the original authors. 101 | -------------------------------------------------------------------------------- /lib/util-get-random-bytes.c: -------------------------------------------------------------------------------- 1 | /* Retrieval of cryptographically random bytes from the operating system. 2 | * 3 | * Written by Zack Weinberg in 2017. 4 | * 5 | * No copyright is claimed, and the software is hereby placed in the public 6 | * domain. In case this attempt to disclaim copyright and place the software 7 | * in the public domain is deemed null and void, then the software is 8 | * Copyright (c) 2017 Zack Weinberg and it is hereby released to the 9 | * general public under the following terms: 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted. 13 | * 14 | * There's ABSOLUTELY NO WARRANTY, express or implied. 15 | */ 16 | 17 | #include "crypt-port.h" 18 | 19 | #include 20 | #include 21 | 22 | #ifdef HAVE_FCNTL_H 23 | #include 24 | #endif 25 | #ifdef HAVE_SYS_RANDOM_H 26 | #include 27 | #endif 28 | #ifdef HAVE_SYS_SYSCALL_H 29 | #include 30 | #endif 31 | #ifdef HAVE_SYS_STAT_H 32 | #include 33 | #endif 34 | 35 | /* If we have O_CLOEXEC, we use it, but if we don't, we don't worry 36 | about it. */ 37 | #ifndef O_CLOEXEC 38 | #define O_CLOEXEC 0 39 | #endif 40 | 41 | /* There is no universally portable way to access a system CSPRNG. 42 | If the C library provides any of the following functions, we try them, 43 | in order of preference: arc4random_buf, getentropy, getrandom. 44 | If none of those are available or they don't work, we attempt to 45 | make direct system calls for getentropy and getrandom. If *that* 46 | doesn't work, we try opening and reading /dev/urandom. 47 | 48 | This function returns true if the exact number of requested bytes 49 | was successfully read, false otherwise; if it returns false, errno 50 | has been set. It may block. It cannot be used to read more than 51 | 256 bytes at a time (this is a limitation inherited from 52 | getentropy() and enforced regardless of the actual back-end in use). 53 | 54 | If we fall all the way back to /dev/urandom, we open and close it on 55 | each call. */ 56 | 57 | bool 58 | get_random_bytes(void *buf, size_t buflen) 59 | { 60 | if (buflen == 0) 61 | return true; 62 | 63 | /* Some, but not all, of the primitives below are limited to 64 | producing no more than 256 bytes of random data. Impose this 65 | constraint on our callers regardless of which primitive is 66 | actually used. */ 67 | if (buflen > 256) 68 | { 69 | errno = EIO; 70 | return false; 71 | } 72 | 73 | /* To eliminate the possibility of one of the primitives below failing 74 | with EFAULT, force a crash now if the buffer is unwritable. */ 75 | explicit_bzero (buf, buflen); 76 | 77 | #ifdef HAVE_ARC4RANDOM_BUF 78 | /* arc4random_buf, if it exists, can never fail. */ 79 | arc4random_buf (buf, buflen); 80 | return true; 81 | 82 | #else /* no arc4random_buf */ 83 | 84 | #ifdef HAVE_GETENTROPY 85 | /* getentropy may exist but lack kernel support. */ 86 | static bool getentropy_doesnt_work; 87 | if (!getentropy_doesnt_work) 88 | { 89 | if (!getentropy (buf, buflen)) 90 | return true; 91 | getentropy_doesnt_work = true; 92 | } 93 | #endif 94 | 95 | #ifdef HAVE_GETRANDOM 96 | /* Likewise getrandom. */ 97 | static bool getrandom_doesnt_work; 98 | if (!getrandom_doesnt_work) 99 | { 100 | if ((size_t)getrandom (buf, buflen, 0) == buflen) 101 | return true; 102 | getrandom_doesnt_work = true; 103 | } 104 | #endif 105 | 106 | /* If we can make arbitrary syscalls, try getentropy and getrandom 107 | again that way. */ 108 | #ifdef HAVE_SYSCALL 109 | #ifdef SYS_getentropy 110 | static bool sys_getentropy_doesnt_work; 111 | if (!sys_getentropy_doesnt_work) 112 | { 113 | if (!syscall (SYS_getentropy, buf, buflen)) 114 | return true; 115 | sys_getentropy_doesnt_work = true; 116 | } 117 | #endif 118 | 119 | #ifdef SYS_getrandom 120 | static bool sys_getrandom_doesnt_work; 121 | if (!sys_getrandom_doesnt_work) 122 | { 123 | if ((size_t)syscall (SYS_getrandom, buf, buflen, 0) == buflen) 124 | return true; 125 | sys_getrandom_doesnt_work = true; 126 | } 127 | #endif 128 | #endif 129 | 130 | #if defined HAVE_SYS_STAT_H && defined HAVE_FCNTL_H && defined HAVE_UNISTD_H 131 | /* Try reading from /dev/urandom. */ 132 | static bool dev_urandom_doesnt_work; 133 | if (!dev_urandom_doesnt_work) 134 | { 135 | int fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC); 136 | if (fd == -1) 137 | dev_urandom_doesnt_work = true; 138 | else 139 | { 140 | ssize_t nread = read (fd, buf, buflen); 141 | if (nread < 0 || (size_t)nread < buflen) 142 | dev_urandom_doesnt_work = true; 143 | 144 | close(fd); 145 | return !dev_urandom_doesnt_work; 146 | } 147 | } 148 | #endif 149 | 150 | /* if we get here, we're just completely hosed */ 151 | errno = ENOSYS; 152 | return false; 153 | #endif /* no arc4random_buf */ 154 | } 155 | -------------------------------------------------------------------------------- /.github/workflows/memcheck.yml: -------------------------------------------------------------------------------- 1 | name: Memory access checking 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | skip_duplicates: 9 | continue-on-error: true 10 | runs-on: ubuntu-24.04 11 | outputs: 12 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 13 | steps: 14 | - id: skip_check 15 | uses: fkirc/skip-duplicate-actions@v5 16 | with: 17 | concurrent_skipping: 'same_content_newer' 18 | skip_after_successful_duplicate: 'true' 19 | paths_ignore: '["doc/**", "**/*.md", ".gitignore", "libxcrypt.spec.rpkg", ".packit.yaml", "rpkg.macros", "AUTHORS", "ChangeLog", "COPYING.LIB", "LICENSING", "NEWS", "README", "THANKS", "TODO"]' 20 | do_not_skip: '["workflow_dispatch", "schedule"]' 21 | 22 | Valgrind: 23 | needs: skip_duplicates 24 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 25 | 26 | runs-on: ubuntu-24.04 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | compiler: [gcc, clang] 32 | 33 | env: 34 | ac_cv_func_arc4random_buf: "no" 35 | CC: ${{ matrix.compiler }} 36 | LDFLAGS: "-Wl,--no-undefined-version" 37 | VERBOSE: 1 38 | 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v4 42 | 43 | - name: Install packages 44 | run: sudo apt-get install clang libltdl-dev valgrind 45 | 46 | - name: Versions of build tools 47 | id: build-tools 48 | run: ./build-aux/ci/ci-log-dependency-versions 49 | 50 | - name: Get nprocs 51 | run: echo "NPROCS=$((`nproc --all 2>/dev/null || sysctl -n hw.ncpu` * 2))" | tee $GITHUB_ENV 52 | 53 | - name: Cache bootstrap 54 | id: cache 55 | uses: actions/cache@v4 56 | with: 57 | path: | 58 | INSTALL 59 | Makefile.in 60 | aclocal.m4 61 | config.h.in 62 | configure 63 | autom4te.cache/** 64 | build-aux/m4/libtool.m4 65 | build-aux/m4/ltoptions.m4 66 | build-aux/m4/ltsugar.m4 67 | build-aux/m4/ltversion.m4 68 | build-aux/m4/lt~obsolete.m4 69 | build-aux/m4-autogen/** 70 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 71 | 72 | - name: Bootstrap 73 | if: steps.cache.outputs.cache-hit != 'true' 74 | run: ./autogen.sh 75 | 76 | - name: Configure 77 | run: ./build-aux/ci/configure-wrapper --enable-obsolete-api --enable-hashes=all --enable-valgrind-memcheck 78 | 79 | - name: Build 80 | run: | 81 | make -j${{ env.NPROCS }} all 82 | make -j${{ env.NPROCS }} test-programs 83 | 84 | - name: Test 85 | run: make -j${{ env.NPROCS }} check-valgrind-memcheck 86 | 87 | - name: Detailed error logs 88 | if: failure() 89 | run: ./build-aux/ci/ci-log-logfiles 90 | 91 | ASan-UBSan: 92 | needs: skip_duplicates 93 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 94 | 95 | runs-on: ubuntu-24.04 96 | 97 | strategy: 98 | fail-fast: false 99 | matrix: 100 | compiler: [gcc, clang] 101 | 102 | env: 103 | ac_cv_func_arc4random_buf: "no" 104 | CC: ${{ matrix.compiler }} 105 | DEB_BUILD_MAINT_OPTIONS: hardening=+all sanitize=+address,+leak,+undefined 106 | LDFLAGS: "-Wl,--no-undefined-version" 107 | VERBOSE: 1 108 | 109 | steps: 110 | - name: Checkout 111 | uses: actions/checkout@v4 112 | 113 | - name: Install packages 114 | run: | 115 | packages="libltdl-dev" 116 | if [ "$CC" = clang ]; then 117 | packages="$packages clang" 118 | fi 119 | sudo apt-get install $packages 120 | 121 | - name: Versions of build tools 122 | id: build-tools 123 | run: ./build-aux/ci/ci-log-dependency-versions 124 | 125 | - name: Cache bootstrap 126 | id: cache 127 | uses: actions/cache@v4 128 | with: 129 | path: | 130 | INSTALL 131 | Makefile.in 132 | aclocal.m4 133 | config.h.in 134 | configure 135 | autom4te.cache/** 136 | build-aux/m4/libtool.m4 137 | build-aux/m4/ltoptions.m4 138 | build-aux/m4/ltsugar.m4 139 | build-aux/m4/ltversion.m4 140 | build-aux/m4/lt~obsolete.m4 141 | build-aux/m4-autogen/** 142 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 143 | 144 | - name: Bootstrap 145 | if: steps.cache.outputs.cache-hit != 'true' 146 | run: ./autogen.sh 147 | 148 | - name: Configure 149 | run: ./build-aux/ci/configure-wrapper --enable-obsolete-api --enable-hashes=all 150 | 151 | - name: Build 152 | run: | 153 | make -j${{ env.NPROCS }} all UNDEF_FLAG= 154 | make -j${{ env.NPROCS }} test-programs UNDEF_FLAG= 155 | 156 | - name: Test 157 | run: make -j${{ env.NPROCS }} check 158 | 159 | - name: Detailed error logs 160 | if: failure() 161 | run: ./build-aux/ci/ci-log-logfiles 162 | -------------------------------------------------------------------------------- /test/crypt-nested-call.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Björn Esser 3 | * All rights reserved. 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted. 7 | * 8 | * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "crypt-port.h" 18 | #include 19 | #include 20 | 21 | #define PASSW "alexander" 22 | 23 | static const char *settings[] = 24 | { 25 | #if INCLUDE_descrypt 26 | "Mp", 27 | #endif 28 | #if INCLUDE_bigcrypt 29 | "Mp............", 30 | #endif 31 | #if INCLUDE_bsdicrypt 32 | "_J9..MJHn", 33 | #endif 34 | #if INCLUDE_md5crypt 35 | "$1$MJHnaAke", 36 | #endif 37 | #if INCLUDE_nt 38 | "$3$", 39 | #endif 40 | #if INCLUDE_sunmd5 41 | "$md5$BPm.fm03$", 42 | #endif 43 | #if INCLUDE_sm3crypt 44 | "$sm3$MJHnaAkegEVYHsFK", 45 | #endif 46 | #if INCLUDE_sha1crypt 47 | "$sha1$248488$ggu.H673kaZ5$", 48 | #endif 49 | #if INCLUDE_sha256crypt 50 | "$5$MJHnaAkegEVYHsFK", 51 | #endif 52 | #if INCLUDE_sha512crypt 53 | "$6$MJHnaAkegEVYHsFK", 54 | #endif 55 | #if INCLUDE_bcrypt_a 56 | "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO", 57 | #endif 58 | #if INCLUDE_bcrypt 59 | "$2b$05$UBVLHeMpJ/QQCv3XqJx8zO", 60 | #endif 61 | #if INCLUDE_bcrypt_y 62 | "$2y$05$UBVLHeMpJ/QQCv3XqJx8zO", 63 | #endif 64 | #if INCLUDE_bcrypt_x 65 | "$2x$05$UBVLHeMpJ/QQCv3XqJx8zO", 66 | #endif 67 | #if INCLUDE_yescrypt 68 | "$y$j9T$MJHnaAkegEVYHsFKkmfzJ1", 69 | #endif 70 | #if INCLUDE_scrypt 71 | "$7$CU..../....MJHnaAkegEVYHsFKkmfzJ1", 72 | #endif 73 | #if INCLUDE_gost_yescrypt 74 | "$gy$j9T$MJHnaAkegEVYHsFKkmfzJ1", 75 | #endif 76 | #if INCLUDE_sm3_yescrypt 77 | "$sm3y$j9T$MJHnaAkegEVYHsFKkmfzJ1", 78 | #endif 79 | }; 80 | 81 | int 82 | main (void) 83 | { 84 | char *retval = NULL; 85 | int status = 0; 86 | struct crypt_data cd; 87 | struct crypt_data *p = &cd; 88 | int cd_size = (int) sizeof (cd); 89 | 90 | for (size_t i = 0; i < ARRAY_SIZE (settings); i++) 91 | { 92 | retval = crypt (PASSW, settings[i]); 93 | retval = crypt (PASSW, retval); 94 | 95 | if (!retval || *retval == '*') 96 | { 97 | printf ("Subsequent call to crypt(3) with output as setting " 98 | "failed for prefix \"%s\".\n", 99 | settings[i]); 100 | status = 1; 101 | } 102 | 103 | // coverity[var_deref_model] 104 | retval = crypt (retval, settings[i]); 105 | 106 | if (!retval || *retval == '*') 107 | { 108 | printf ("Subsequent call to crypt(3) with output as key " 109 | "failed for prefix \"%s\".\n", 110 | settings[i]); 111 | status = 1; 112 | } 113 | 114 | retval = crypt_r (PASSW, settings[i], p); 115 | retval = crypt_r (PASSW, retval, p); 116 | 117 | if (!retval || *retval == '*') 118 | { 119 | printf ("Subsequent call to crypt_r(3) with output as setting " 120 | "failed for prefix \"%s\".\n", 121 | settings[i]); 122 | status = 1; 123 | } 124 | 125 | retval = crypt_r (retval, settings[i], p); 126 | 127 | if (!retval || *retval == '*') 128 | { 129 | printf ("Subsequent call to crypt_r(3) with output as key " 130 | "failed for prefix \"%s\".\n", 131 | settings[i]); 132 | status = 1; 133 | } 134 | 135 | retval = crypt_rn (PASSW, settings[i], p, cd_size); 136 | retval = crypt_rn (PASSW, retval, p, cd_size); 137 | 138 | if (!retval || *retval == '*') 139 | { 140 | printf ("Subsequent call to crypt_rn(3) with output as setting " 141 | "failed for prefix \"%s\".\n", 142 | settings[i]); 143 | status = 1; 144 | } 145 | 146 | retval = crypt_rn (retval, settings[i], p, cd_size); 147 | 148 | if (!retval || *retval == '*') 149 | { 150 | printf ("Subsequent call to crypt_rn(3) with output as key " 151 | "failed for prefix \"%s\".\n", 152 | settings[i]); 153 | status = 1; 154 | } 155 | 156 | retval = crypt_ra (PASSW, settings[i], (void **) &p, &cd_size); 157 | retval = crypt_ra (PASSW, retval, (void **) &p, &cd_size); 158 | 159 | if (!retval || *retval == '*') 160 | { 161 | printf ("Subsequent call to crypt_ra(3) with output as setting " 162 | "failed for prefix \"%s\".\n", 163 | settings[i]); 164 | status = 1; 165 | } 166 | 167 | retval = crypt_ra (retval, settings[i], (void **) &p, &cd_size); 168 | 169 | if (!retval || *retval == '*') 170 | { 171 | printf ("Subsequent call to crypt_ra(3) with output as key " 172 | "failed for prefix \"%s\".\n", 173 | settings[i]); 174 | status = 1; 175 | } 176 | } 177 | 178 | explicit_bzero (&cd, sizeof cd); 179 | return status; 180 | } 181 | -------------------------------------------------------------------------------- /test/des-obsolete.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This crypt(3) validation program shipped with UFC-crypt 4 | * is derived from one distributed with Phil Karns PD DES package. 5 | * 6 | * @(#)cert.c 1.8 11 Aug 1996 7 | */ 8 | 9 | #include "crypt-port.h" 10 | #include "crypt-obsolete.h" 11 | #include "des-cases.h" 12 | 13 | #include 14 | 15 | #if ENABLE_OBSOLETE_API_ENOSYS 16 | #include 17 | #endif 18 | 19 | #if HAVE_SYMVER 20 | symver_ref("encrypt", encrypt, SYMVER_FLOOR); 21 | symver_ref("setkey", setkey, SYMVER_FLOOR); 22 | #endif 23 | 24 | static void 25 | expand (unsigned char ex[64], const unsigned char pk[8]) 26 | { 27 | int i, j; 28 | unsigned int t; 29 | 30 | for (i = 0; i < 8; i++) 31 | { 32 | t = pk[i]; 33 | for (j = 0; j < 8; j++) 34 | ex[i*8 + j] = (unsigned char)((t & (0x01u << (7 - j))) != 0); 35 | } 36 | } 37 | 38 | #if !ENABLE_OBSOLETE_API_ENOSYS 39 | 40 | static void 41 | ex_print (const unsigned char ex[64]) 42 | { 43 | int i, j; 44 | unsigned int t; 45 | 46 | for (i = 0; i < 8; i++) 47 | { 48 | t = 0; 49 | for (j = 0; j < 8; j++) 50 | t = (t << 1) | ex[i*8 + j]; 51 | printf ("%02x", t); 52 | } 53 | } 54 | 55 | static void 56 | pk_print (const unsigned char pk[8]) 57 | { 58 | for (int i = 0; i < 8; i++) 59 | printf ("%02x", (unsigned int)pk[i]); 60 | } 61 | 62 | static void 63 | report_failure (size_t n, bool decrypt, 64 | const struct des_testcase *tc, const unsigned char got[64]) 65 | { 66 | printf ("FAIL: %zu/%s: k=", n, decrypt ? "de" : "en"); 67 | pk_print (tc->key); 68 | fputs (" exp ", stdout); 69 | if (decrypt) 70 | pk_print (tc->plain); 71 | else 72 | pk_print (tc->answer); 73 | fputs (" got ", stdout); 74 | ex_print (got); 75 | putchar ('\n'); 76 | } 77 | 78 | int 79 | main (void) 80 | { 81 | unsigned char key[64], plain[64], cipher[64], answer[64]; 82 | const struct des_testcase *tc; 83 | size_t t; 84 | int status = 0; 85 | 86 | for (t = 0; t < N_DES_TESTCASES; t++) 87 | { 88 | tc = &des_testcases[t]; 89 | expand (key, tc->key); 90 | expand (plain, tc->plain); 91 | expand (answer, tc->answer); 92 | 93 | setkey ((char *)key); 94 | memcpy (cipher, plain, 64); 95 | encrypt ((char *)cipher, 0); 96 | 97 | if (memcmp (cipher, answer, 64) != 0) 98 | { 99 | status = 1; 100 | // coverity[sensitive_data_leak] 101 | report_failure (t, false, tc, cipher); 102 | } 103 | 104 | memcpy (cipher, answer, 64); 105 | encrypt ((char *)cipher, 1); 106 | if (memcmp (cipher, plain, 64) != 0) 107 | { 108 | status = 1; 109 | report_failure (t, true, tc, cipher); 110 | } 111 | } 112 | 113 | return status; 114 | } 115 | 116 | #else 117 | 118 | int 119 | main (void) 120 | { 121 | unsigned char key[64], plain[64], cipher[64], answer[64]; 122 | const struct des_testcase *tc; 123 | size_t t; 124 | int status = 0; 125 | 126 | for (t = 0; t < N_DES_TESTCASES; t++) 127 | { 128 | tc = &des_testcases[t]; 129 | expand (key, tc->key); 130 | expand (plain, tc->plain); 131 | expand (answer, tc->answer); 132 | 133 | /* Explicitly reset errno as required by POSIX. */ 134 | errno = 0; 135 | 136 | setkey ((char *)key); 137 | 138 | if (errno != ENOSYS) 139 | { 140 | status = 1; 141 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 142 | "expected: %d, %s, got: %d, %s\n", "setkey", 143 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 144 | } 145 | 146 | memcpy (cipher, plain, 64); 147 | 148 | /* Explicitly reset errno as required by POSIX. */ 149 | errno = 0; 150 | 151 | encrypt ((char *)cipher, 0); 152 | 153 | if (memcmp (cipher, answer, 64) == 0) 154 | { 155 | status = 1; 156 | printf ("FAIL: %s: still performs correct operation.\n", 157 | "encrypt"); 158 | } 159 | 160 | if (memcmp (cipher, plain, 64) == 0) 161 | { 162 | status = 1; 163 | printf ("FAIL: %s: data-block is has not changed.\n", 164 | "encrypt"); 165 | } 166 | 167 | if (errno != ENOSYS) 168 | { 169 | status = 1; 170 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 171 | "expected: %d, %s, got: %d, %s\n", "encrypt", 172 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 173 | } 174 | 175 | /* Explicitly reset errno as required by POSIX. */ 176 | errno = 0; 177 | 178 | encrypt ((char *)cipher, 1); 179 | 180 | if (memcmp (cipher, plain, 64) == 0) 181 | { 182 | status = 1; 183 | printf ("FAIL: %s: still performs correct operation.\n", 184 | "encrypt (decrypt)"); 185 | } 186 | 187 | if (memcmp (cipher, answer, 64) == 0) 188 | { 189 | status = 1; 190 | printf ("FAIL: %s: data-block is unchanged.\n", 191 | "encrypt (decrypt)"); 192 | } 193 | 194 | if (errno != ENOSYS) 195 | { 196 | status = 1; 197 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 198 | "expected: %d, %s, got: %d, %s\n", "encrypt (decrypt)", 199 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 200 | } 201 | } 202 | 203 | return status; 204 | } 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /test/des-obsolete_r.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This crypt(3) validation program shipped with UFC-crypt 4 | * is derived from one distributed with Phil Karns PD DES package. 5 | * 6 | * @(#)cert.c 1.8 11 Aug 1996 7 | */ 8 | 9 | #include "crypt-port.h" 10 | #include "crypt-obsolete.h" 11 | #include "des-cases.h" 12 | 13 | #include 14 | 15 | #if ENABLE_OBSOLETE_API_ENOSYS 16 | #include 17 | #endif 18 | 19 | #if HAVE_SYMVER 20 | symver_ref("encrypt_r", encrypt_r, SYMVER_FLOOR); 21 | symver_ref("setkey_r", setkey_r, SYMVER_FLOOR); 22 | #endif 23 | 24 | static void 25 | expand (unsigned char ex[64], const unsigned char pk[8]) 26 | { 27 | int i, j; 28 | unsigned int t; 29 | 30 | for (i = 0; i < 8; i++) 31 | { 32 | t = pk[i]; 33 | for (j = 0; j < 8; j++) 34 | ex[i*8 + j] = (unsigned char)((t & (0x01u << (7 - j))) != 0); 35 | } 36 | } 37 | 38 | #if !ENABLE_OBSOLETE_API_ENOSYS 39 | 40 | static void 41 | ex_print (const unsigned char ex[64]) 42 | { 43 | int i, j; 44 | unsigned int t; 45 | 46 | for (i = 0; i < 8; i++) 47 | { 48 | t = 0; 49 | for (j = 0; j < 8; j++) 50 | t = (t << 1) | ex[i*8 + j]; 51 | printf ("%02x", t); 52 | } 53 | } 54 | 55 | static void 56 | pk_print (const unsigned char pk[8]) 57 | { 58 | for (int i = 0; i < 8; i++) 59 | printf ("%02x", (unsigned int)pk[i]); 60 | } 61 | 62 | static void 63 | report_failure (size_t n, bool decrypt, 64 | const struct des_testcase *tc, const unsigned char got[64]) 65 | { 66 | printf ("FAIL: %zu/%s: k=", n, decrypt ? "de" : "en"); 67 | pk_print (tc->key); 68 | fputs (" exp ", stdout); 69 | if (decrypt) 70 | pk_print (tc->plain); 71 | else 72 | pk_print (tc->answer); 73 | fputs (" got ", stdout); 74 | ex_print (got); 75 | putchar ('\n'); 76 | } 77 | 78 | int 79 | main (void) 80 | { 81 | unsigned char key[64], plain[64], cipher[64], answer[64]; 82 | const struct des_testcase *tc; 83 | size_t t; 84 | int status = 0; 85 | struct crypt_data data; 86 | 87 | for (t = 0; t < N_DES_TESTCASES; t++) 88 | { 89 | tc = &des_testcases[t]; 90 | expand (key, tc->key); 91 | expand (plain, tc->plain); 92 | expand (answer, tc->answer); 93 | 94 | setkey_r ((char *)key, &data); 95 | memcpy (cipher, plain, 64); 96 | encrypt_r ((char *)cipher, 0, &data); 97 | 98 | if (memcmp (cipher, answer, 64) != 0) 99 | { 100 | status = 1; 101 | report_failure (t, false, tc, cipher); 102 | } 103 | 104 | memcpy (cipher, answer, 64); 105 | encrypt_r ((char *)cipher, 1, &data); 106 | if (memcmp (cipher, plain, 64) != 0) 107 | { 108 | status = 1; 109 | report_failure (t, true, tc, cipher); 110 | } 111 | } 112 | 113 | return status; 114 | } 115 | 116 | #else 117 | 118 | int 119 | main (void) 120 | { 121 | unsigned char key[64], plain[64], cipher[64], answer[64]; 122 | const struct des_testcase *tc; 123 | size_t t; 124 | int status = 0; 125 | struct crypt_data data; 126 | 127 | for (t = 0; t < N_DES_TESTCASES; t++) 128 | { 129 | tc = &des_testcases[t]; 130 | expand (key, tc->key); 131 | expand (plain, tc->plain); 132 | expand (answer, tc->answer); 133 | 134 | /* Explicitly reset errno as required by POSIX. */ 135 | errno = 0; 136 | 137 | setkey_r ((char *)key, &data); 138 | 139 | if (errno != ENOSYS) 140 | { 141 | status = 1; 142 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 143 | "expected: %d, %s, got: %d, %s\n", "setkey_r", 144 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 145 | } 146 | 147 | memcpy (cipher, plain, 64); 148 | 149 | /* Explicitly reset errno as required by POSIX. */ 150 | errno = 0; 151 | 152 | encrypt_r ((char *)cipher, 0, &data); 153 | 154 | if (memcmp (cipher, answer, 64) == 0) 155 | { 156 | status = 1; 157 | printf ("FAIL: %s: still performs correct operation.\n", 158 | "encrypt_r"); 159 | } 160 | 161 | if (memcmp (cipher, plain, 64) == 0) 162 | { 163 | status = 1; 164 | printf ("FAIL: %s: data-block is has not changed.\n", 165 | "encrypt_r"); 166 | } 167 | 168 | if (errno != ENOSYS) 169 | { 170 | status = 1; 171 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 172 | "expected: %d, %s, got: %d, %s\n", "encrypt_r", 173 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 174 | } 175 | 176 | /* Explicitly reset errno as required by POSIX. */ 177 | errno = 0; 178 | 179 | encrypt_r ((char *)cipher, 1, &data); 180 | 181 | if (memcmp (cipher, plain, 64) == 0) 182 | { 183 | status = 1; 184 | printf ("FAIL: %s: still performs correct operation.\n", 185 | "encrypt_r (decrypt)"); 186 | } 187 | 188 | if (memcmp (cipher, answer, 64) == 0) 189 | { 190 | status = 1; 191 | printf ("FAIL: %s: data-block is unchanged.\n", 192 | "encrypt_r (decrypt)"); 193 | } 194 | 195 | if (errno != ENOSYS) 196 | { 197 | status = 1; 198 | printf ("FAIL: %s: errno does NOT equal ENOSYS.\n" 199 | "expected: %d, %s, got: %d, %s\n", "encrypt_r (decrypt)", 200 | ENOSYS, strerror (ENOSYS), errno, strerror (errno)); 201 | } 202 | } 203 | 204 | return status; 205 | } 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /.github/workflows/config-matrix.yml: -------------------------------------------------------------------------------- 1 | name: "Config Matrix" 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | skip_duplicates: 9 | continue-on-error: true 10 | runs-on: ubuntu-24.04 11 | outputs: 12 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 13 | steps: 14 | - id: skip_check 15 | uses: fkirc/skip-duplicate-actions@v5 16 | with: 17 | concurrent_skipping: 'same_content_newer' 18 | skip_after_successful_duplicate: 'true' 19 | paths_ignore: '["doc/**", "**/*.md", ".gitignore", "libxcrypt.spec.rpkg", ".packit.yaml", "rpkg.macros", "AUTHORS", "ChangeLog", "COPYING.LIB", "LICENSING", "NEWS", "README", "THANKS", "TODO"]' 20 | do_not_skip: '["workflow_dispatch", "schedule"]' 21 | 22 | build: 23 | needs: skip_duplicates 24 | if: ${{ needs.skip_duplicates.outputs.should_skip != 'true' }} 25 | 26 | runs-on: ubuntu-24.04 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | compiler: [gcc, clang] 32 | config_opts: 33 | # General-purpose configurations with the obsolete APIs present. 34 | - "--enable-obsolete-api --enable-hashes=all" 35 | - "--enable-obsolete-api --enable-hashes=all --enable-obsolete-api-enosys" 36 | - "--enable-obsolete-api --enable-hashes=all --disable-failure-tokens" 37 | - "--enable-obsolete-api --enable-hashes=all --enable-obsolete-api-enosys --disable-failure-tokens" 38 | - "--enable-obsolete-api --enable-hashes=all --disable-symvers" 39 | - "--enable-obsolete-api --enable-hashes=glibc" 40 | - "--enable-obsolete-api=glibc --enable-hashes=strong,glibc" 41 | 42 | # General-purpose configurations with the obsolete APIs absent. 43 | # Note that the obsolete APIs are always absent from the static library, 44 | # so --disable-shared implies --disable-obsolete-api. 45 | - "--disable-obsolete-api --enable-hashes=all" 46 | - "--disable-obsolete-api --enable-hashes=all --disable-shared" 47 | - "--disable-obsolete-api --enable-hashes=all --disable-static" 48 | - "--disable-obsolete-api --enable-hashes=all --disable-failure-tokens" 49 | - "--disable-obsolete-api --enable-hashes=all --disable-symvers" 50 | - "--disable-obsolete-api --enable-hashes=strong" 51 | 52 | # Configurations with only one hash enabled. These exist to 53 | # detect build failures due to incorrect ifdeffage. 54 | - "--disable-obsolete-api --enable-hashes=bcrypt" 55 | - "--disable-obsolete-api --enable-hashes=bcrypt_a" 56 | - "--disable-obsolete-api --enable-hashes=bcrypt_x" 57 | - "--disable-obsolete-api --enable-hashes=bcrypt_y" 58 | - "--disable-obsolete-api --enable-hashes=bigcrypt" 59 | - "--disable-obsolete-api --enable-hashes=bsdicrypt" 60 | - "--disable-obsolete-api --enable-hashes=descrypt" 61 | - "--disable-obsolete-api --enable-hashes=gost-yescrypt" 62 | - "--disable-obsolete-api --enable-hashes=md5crypt" 63 | - "--disable-obsolete-api --enable-hashes=nt" 64 | - "--disable-obsolete-api --enable-hashes=scrypt" 65 | - "--disable-obsolete-api --enable-hashes=sha1crypt" 66 | - "--disable-obsolete-api --enable-hashes=sha256crypt" 67 | - "--disable-obsolete-api --enable-hashes=sha512crypt" 68 | - "--disable-obsolete-api --enable-hashes=sm3crypt" 69 | - "--disable-obsolete-api --enable-hashes=sm3-yescrypt" 70 | - "--disable-obsolete-api --enable-hashes=sunmd5" 71 | - "--disable-obsolete-api --enable-hashes=yescrypt" 72 | 73 | env: 74 | ac_cv_func_arc4random_buf: "no" 75 | CC: ${{ matrix.compiler }} 76 | CONFIG_OPTS: ${{ matrix.config_opts }} 77 | LDFLAGS: "-Wl,--no-undefined-version" 78 | 79 | steps: 80 | - name: Checkout 81 | uses: actions/checkout@v4 82 | 83 | - name: Install packages 84 | run: | 85 | packages="libltdl-dev" 86 | if [ "$CC" = clang ]; then 87 | packages="$packages clang" 88 | fi 89 | sudo apt-get install $packages 90 | 91 | - name: Versions of build tools 92 | id: build-tools 93 | run: ./build-aux/ci/ci-log-dependency-versions 94 | 95 | - name: Get nprocs 96 | run: echo "NPROCS=$((`nproc --all 2>/dev/null || sysctl -n hw.ncpu` * 2))" | tee $GITHUB_ENV 97 | 98 | - name: Cache bootstrap 99 | id: cache 100 | uses: actions/cache@v4 101 | with: 102 | path: | 103 | INSTALL 104 | Makefile.in 105 | aclocal.m4 106 | config.h.in 107 | configure 108 | autom4te.cache/** 109 | build-aux/m4/libtool.m4 110 | build-aux/m4/ltoptions.m4 111 | build-aux/m4/ltsugar.m4 112 | build-aux/m4/ltversion.m4 113 | build-aux/m4/lt~obsolete.m4 114 | build-aux/m4-autogen/** 115 | key: autoreconf-${{ steps.build-tools.outputs.autotools-ver }}-${{ hashFiles('autogen.sh', 'configure.ac', 'Makefile.am', 'build-aux/m4/*.m4', 'build-aux/m4-autogen/**') }} 116 | 117 | - name: Bootstrap 118 | if: steps.cache.outputs.cache-hit != 'true' 119 | run: ./autogen.sh 120 | 121 | - name: Configure 122 | run: ./build-aux/ci/configure-wrapper $CONFIG_OPTS 123 | 124 | - name: Build 125 | run: | 126 | make -j${{ env.NPROCS }} all 127 | make -j${{ env.NPROCS }} test-programs 128 | 129 | - name: Test 130 | run: make -j${{ env.NPROCS }} check 131 | 132 | - name: Detailed error logs 133 | if: failure() 134 | run: ./build-aux/ci/ci-log-logfiles 135 | -------------------------------------------------------------------------------- /test/alg-sm3-hmac.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018, 2024, 2025 Björn Esser besser82@fedoraproject.org 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | 21 | #if INCLUDE_sm3_yescrypt 22 | 23 | #include "alg-sm3-hmac.h" 24 | 25 | #include 26 | 27 | struct testcase 28 | { 29 | const char *subject; 30 | const char *t; 31 | size_t tlen; 32 | const char *k; 33 | size_t ksize; 34 | const char *match; 35 | }; 36 | 37 | /* Test vectors as published in GM/T 0042-2015 Appendix D.3 */ 38 | static const struct testcase testcases[] = 39 | { 40 | { 41 | "First test vector for HMAC-SM3 from GM/T 0042-2015 Appendix D.3", 42 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 43 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 112, 44 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" 45 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20", 32, 46 | "\xca\x05\xe1\x44\xed\x05\xd1\x85\x78\x40\xd1\xf3\x18\xa4\xa8\x66" 47 | "\x9e\x55\x9f\xc8\x39\x1f\x41\x44\x85\xbf\xdf\x7b\xb4\x08\x96\x3a" 48 | }, 49 | { 50 | "Second test vector for HMAC-SM3 from GM/T 0042-2015 Appendix D.3", 51 | "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 52 | "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 53 | "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" 54 | "\xcd\xcd", 50, 55 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" 56 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" 57 | "\x21\x22\x23\x24\x25", 37, 58 | "\x22\x0b\xf5\x79\xde\xd5\x55\x39\x3f\x01\x59\xf6\x6c\x99\x87\x78" 59 | "\x22\xa3\xec\xf6\x10\xd1\x55\x21\x54\xb4\x1d\x44\xb9\x4d\xb3\xae" 60 | }, 61 | { 62 | "Third test vector for HMAC-SM3 from GM/T 0042-2015 Appendix D.3", 63 | "Hi There", 8, 64 | "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 65 | "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 32, 66 | "\xc0\xba\x18\xc6\x8b\x90\xc8\x8b\xc0\x7d\xe7\x94\xbf\xc7\xd2\xc8" 67 | "\xd1\x9e\xc3\x1e\xd8\x77\x3b\xc2\xb3\x90\xc9\x60\x4e\x0b\xe1\x1e" 68 | }, 69 | { 70 | "Fourth test vector for HMAC-SM3 from GM/T 0042-2015 Appendix D.3", 71 | "what do ya want for nothing?", 28, 72 | "Jefe", 4, 73 | "\x2e\x87\xf1\xd1\x68\x62\xe6\xd9\x64\xb5\x0a\x52\x00\xbf\x2b\x10" 74 | "\xb7\x64\xfa\xa9\x68\x0a\x29\x6a\x24\x05\xf2\x4b\xec\x39\xf8\x82" 75 | }, 76 | { 77 | "Custom test vector for HMAC-SM3 with key length > 64", 78 | "What is the purpose of this test???", 35, 79 | "\x49\x74\x27\x73\x20\x63\x6f\x6d\x70\x6c\x69\x63\x61\x74\x65\x64" 80 | "\x20\x74\x6f\x20\x65\x78\x70\x6c\x61\x69\x6e\x2c\x20\x62\x75\x74" 81 | "\x20\x77\x65\x20\x6e\x65\x65\x64\x20\x73\x6f\x6d\x65\x20\x74\x65" 82 | "\x78\x74\x20\x74\x68\x61\x74\x20\x63\x6c\x65\x61\x72\x6c\x79\x20" 83 | "\x65\x78\x63\x65\x65\x64\x73\x20\x73\x69\x78\x74\x79\x66\x6f\x75" 84 | "\x72\x20\x62\x79\x74\x65\x73\x20\x6f\x66\x20\x64\x61\x74\x61\x20" 85 | "\x66\x6f\x72\x20\x74\x68\x65\x20\x6b\x65\x79\x20\x74\x6f\x20\x74" 86 | "\x65\x73\x74\x20\x63\x6f\x76\x65\x72\x61\x67\x65\x2e\x2e\x2e\x2e", 128, 87 | "\xd3\xde\xc8\x63\xe3\x16\x59\x62\x38\x09\x0e\xac\xe6\x61\xe6\xd3" 88 | "\xc4\xcb\xae\x43\xdc\xf0\x06\x0c\x71\xf0\xe4\xe5\xdc\x5f\xf7\xd3" 89 | }, 90 | }; 91 | 92 | 93 | static void 94 | dumphex(const void *ptr, size_t size) 95 | { 96 | size_t i; 97 | 98 | for (i = 0; i < size; i++) 99 | printf("\\x%02x", ((const unsigned char *)ptr)[i]); 100 | printf("\n"); 101 | } 102 | 103 | static int 104 | test_sm3_hmac(const struct testcase *tc) 105 | { 106 | uint8_t digest[32]; 107 | 108 | sm3_hmac_buf((const uint8_t *)tc->t, tc->tlen, 109 | (const uint8_t *)tc->k, tc->ksize, digest); 110 | 111 | if (memcmp(digest, tc->match, 32)) 112 | { 113 | fprintf(stderr, "ERROR: %s\n", tc->subject); 114 | printf(" key: "); 115 | dumphex(tc->k, tc->ksize); 116 | printf(" t: "); 117 | dumphex(tc->t, tc->tlen); 118 | printf(" hmac="); 119 | dumphex(digest, 32); 120 | printf(" expect="); 121 | dumphex(tc->match, 32); 122 | return 1; 123 | } 124 | else 125 | fprintf(stderr, " ok: %s\n", tc->subject); 126 | 127 | return 0; 128 | } 129 | 130 | int 131 | main (void) 132 | { 133 | int result = 0; 134 | 135 | for (size_t i = 0; i < ARRAY_SIZE (testcases); i++) 136 | result |= test_sm3_hmac(&testcases[i]); 137 | 138 | return result; 139 | } 140 | 141 | #else 142 | 143 | int 144 | main (void) 145 | { 146 | return 77; /* UNSUPPORTED */ 147 | } 148 | 149 | #endif /* INCLUDE_sm3_yescrypt */ 150 | -------------------------------------------------------------------------------- /test/alg-sm3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 Tianjia Zhang 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the author nor the names of other contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | #include "crypt-port.h" 31 | #include "alg-sm3.h" 32 | 33 | #include 34 | 35 | #if INCLUDE_sm3crypt 36 | 37 | static const struct 38 | { 39 | const char *input; 40 | const char result[33]; 41 | } tests[] = 42 | { 43 | /* Test vectors from OSCCA GM/T 0004-2012: appendix A. */ 44 | { 45 | "abc", 46 | "\x66\xc7\xf0\xf4\x62\xee\xed\xd9\xd1\xf2\xd4\x6b\xdc\x10\xe4\xe2" 47 | "\x41\x67\xc4\x87\x5c\xf2\xf7\xa2\x29\x7d\xa0\x2b\x8f\x4b\xa8\xe0" 48 | }, 49 | { 50 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 51 | "\x63\x9b\x6c\xc5\xe6\x4d\x9e\x37\xa3\x90\xb1\x92\xdf\x4f\xa1\xea" 52 | "\x07\x20\xab\x74\x7f\xf6\x92\xb9\xf3\x8c\x4e\x66\xad\x7b\x8c\x05" 53 | }, 54 | { 55 | "", 56 | "\x1a\xb2\x1d\x83\x55\xcf\xa1\x7f\x8E\x61\x19\x48\x31\xe8\x1a\x8f" 57 | "\x22\xbe\xc8\xc7\x28\xfe\xfb\x74\x7e\xd0\x35\xeb\x50\x82\xaa\x2b" 58 | }, 59 | { 60 | "a", 61 | "\x62\x34\x76\xac\x18\xf6\x5a\x29\x09\xe4\x3c\x7f\xec\x61\xb4\x9c" 62 | "\x7e\x76\x4a\x91\xa1\x8c\xcb\x82\xf1\x91\x7a\x29\xc8\x6c\x5e\x88" 63 | }, 64 | { 65 | "message digest", 66 | "\xc5\x22\xa9\x42\xe8\x9b\xd8\x0d\x97\xdd\x66\x6e\x7a\x55\x31\xb3" 67 | "\x61\x88\xc9\x81\x71\x49\xe9\xb2\x58\xdf\xe5\x1e\xce\x98\xed\x77" 68 | }, 69 | { 70 | "abcdefghijklmnopqrstuvwxyz", 71 | "\xb8\x0f\xe9\x7a\x4d\xa2\x4a\xfc\x27\x75\x64\xf6\x6a\x35\x9e\xf4" 72 | "\x40\x46\x2a\xd2\x8d\xcc\x6d\x63\xad\xb2\x4d\x5c\x20\xa6\x15\x95" 73 | }, 74 | { 75 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 76 | "\x29\x71\xd1\x0c\x88\x42\xb7\x0c\x97\x9e\x55\x06\x34\x80\xc5\x0b" 77 | "\xac\xff\xd9\x0e\x98\xe2\xe6\x0d\x25\x12\xab\x8a\xbf\xdf\xce\xc5" 78 | }, 79 | { 80 | "123456789012345678901234567890123456789012345678901234567890" 81 | "12345678901234567890", 82 | "\xad\x81\x80\x53\x21\xf3\xe6\x9d\x25\x12\x35\xbf\x88\x6a\x56\x48" 83 | "\x44\x87\x3b\x56\xdd\x7d\xde\x40\x0f\x05\x5b\x7d\xde\x39\x30\x7a" 84 | } 85 | }; 86 | 87 | 88 | static void 89 | report_failure(int n, const char *tag, 90 | const char expected[32], uint8_t actual[32]) 91 | { 92 | int i; 93 | printf ("FAIL: test %d (%s):\n exp:", n, tag); 94 | for (i = 0; i < 32; i++) 95 | { 96 | if (i % 4 == 0) 97 | putchar (' '); 98 | printf ("%02x", (unsigned int)(unsigned char)expected[i]); 99 | } 100 | printf ("\n got:"); 101 | for (i = 0; i < 32; i++) 102 | { 103 | if (i % 4 == 0) 104 | putchar (' '); 105 | printf ("%02x", (unsigned int)(unsigned char)actual[i]); 106 | } 107 | putchar ('\n'); 108 | putchar ('\n'); 109 | } 110 | 111 | int 112 | main (void) 113 | { 114 | sm3_ctx ctx; 115 | uint8_t sum[32]; 116 | int result = 0; 117 | int cnt; 118 | int i; 119 | 120 | for (cnt = 0; cnt < (int) ARRAY_SIZE (tests); ++cnt) 121 | { 122 | sm3_buf (tests[cnt].input, strlen (tests[cnt].input), sum); 123 | if (memcmp (tests[cnt].result, sum, 32) != 0) 124 | { 125 | report_failure (cnt, "all at once", tests[cnt].result, sum); 126 | result = 1; 127 | } 128 | 129 | sm3_init (&ctx); 130 | for (i = 0; tests[cnt].input[i] != '\0'; ++i) 131 | sm3_update (&ctx, &tests[cnt].input[i], 1); 132 | sm3_final (sum, &ctx); 133 | if (memcmp (tests[cnt].result, sum, 32) != 0) 134 | { 135 | report_failure (cnt, "byte by byte", tests[cnt].result, sum); 136 | result = 1; 137 | } 138 | } 139 | 140 | /* Test vector from FIPS 180-2: appendix B.3. */ 141 | char buf[1000]; 142 | memset (buf, 'a', sizeof (buf)); 143 | sm3_init (&ctx); 144 | for (i = 0; i < 1000; ++i) 145 | sm3_update (&ctx, buf, sizeof (buf)); 146 | sm3_final (sum, &ctx); 147 | static const char expected[33] = 148 | "\xc8\xaa\xf8\x94\x29\x55\x40\x29\xe2\x31\x94\x1a\x2a\xcc\x0a\xd6" 149 | "\x1f\xf2\xa5\xac\xd8\xfa\xdd\x25\x84\x7a\x3a\x73\x2b\x3b\x02\xc3"; 150 | 151 | if (memcmp (expected, sum, 32) != 0) 152 | { 153 | report_failure (cnt, "block by block", expected, sum); 154 | result = 1; 155 | } 156 | 157 | return result; 158 | } 159 | 160 | #else 161 | 162 | int 163 | main (void) 164 | { 165 | return 77; /* UNSUPPORTED */ 166 | } 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /lib/crypt-yescrypt.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2018 vt@altlinux.org 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted. 5 | * 6 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 7 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 10 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 11 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 14 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 15 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 16 | * SUCH DAMAGE. 17 | */ 18 | 19 | #include "crypt-port.h" 20 | #include "alg-yescrypt.h" 21 | 22 | #include 23 | 24 | #if INCLUDE_yescrypt || INCLUDE_scrypt 25 | 26 | /* For use in scratch space by crypt_yescrypt_rn(). */ 27 | typedef struct 28 | { 29 | yescrypt_local_t local; 30 | uint8_t outbuf[CRYPT_OUTPUT_SIZE]; 31 | uint8_t *retval; 32 | } crypt_yescrypt_internal_t; 33 | 34 | static_assert (sizeof (crypt_yescrypt_internal_t) <= ALG_SPECIFIC_SIZE, 35 | "ALG_SPECIFIC_SIZE is too small for YESCRYPT."); 36 | 37 | void 38 | crypt_yescrypt_rn (const char *phrase, size_t phr_size, 39 | const char *setting, size_t set_size, 40 | uint8_t *output, size_t o_size, 41 | void *scratch, size_t s_size) 42 | { 43 | #if !INCLUDE_scrypt 44 | 45 | /* If scrypt is disabled fail when called with its prefix. */ 46 | if (!strncmp (setting, "$7$", 3)) 47 | { 48 | errno = EINVAL; 49 | return; 50 | } 51 | 52 | #endif /* !INCLUDE_scrypt */ 53 | 54 | #if !INCLUDE_yescrypt 55 | 56 | /* If yescrypt is disabled fail when called with its prefix. */ 57 | if (!strncmp (setting, "$y$", 3)) 58 | { 59 | errno = EINVAL; 60 | return; 61 | } 62 | 63 | #endif /* !INCLUDE_yescrypt */ 64 | 65 | if (o_size < set_size + 1 + 43 + 1 || 66 | CRYPT_OUTPUT_SIZE < set_size + 1 + 43 + 1 || 67 | s_size < sizeof (crypt_yescrypt_internal_t)) 68 | { 69 | errno = ERANGE; 70 | return; 71 | } 72 | 73 | crypt_yescrypt_internal_t *intbuf = scratch; 74 | 75 | if (yescrypt_init_local (&intbuf->local)) 76 | return; 77 | 78 | intbuf->retval = yescrypt_r (NULL, &intbuf->local, 79 | (const uint8_t *)phrase, phr_size, 80 | (const uint8_t *)setting, NULL, 81 | intbuf->outbuf, o_size); 82 | 83 | if (!intbuf->retval) 84 | errno = EINVAL; 85 | 86 | if (yescrypt_free_local (&intbuf->local) || !intbuf->retval) 87 | return; 88 | 89 | strcpy_or_abort (output, o_size, intbuf->outbuf); 90 | return; 91 | } 92 | 93 | #endif /* INCLUDE_yescrypt || INCLUDE_scrypt */ 94 | 95 | #if INCLUDE_gost_yescrypt || INCLUDE_yescrypt || INCLUDE_sm3_yescrypt 96 | 97 | /* 98 | * As OUTPUT is initialized with a failure token before gensalt_yescrypt_rn 99 | * is called, in case of an error we could just set an appropriate errno 100 | * and return. 101 | * Since O_SIZE is guaranteed to be greater than 2, we may fill OUTPUT 102 | * with a short failure token when need. 103 | */ 104 | void 105 | gensalt_yescrypt_rn (unsigned long count, 106 | const uint8_t *rbytes, size_t nrbytes, 107 | uint8_t *output, size_t o_size) 108 | { 109 | /* Up to 512 bits (64 bytes) of entropy for computing the salt portion 110 | of the MCF-setting are supported. */ 111 | nrbytes = (nrbytes > 64 ? 64 : nrbytes); 112 | 113 | if (o_size < 3 + 8 * 6 + 1 + BASE64_LEN (nrbytes) + 1 || 114 | CRYPT_GENSALT_OUTPUT_SIZE < 3 + 8 * 6 + 1 + BASE64_LEN (nrbytes) + 1) 115 | { 116 | errno = ERANGE; 117 | return; 118 | } 119 | 120 | if (count > 11 || nrbytes < 16) 121 | { 122 | errno = EINVAL; 123 | return; 124 | } 125 | 126 | /* Temporary buffer for operation. The buffer is guaranteed to be 127 | large enough to hold the maximum size of the generated salt. */ 128 | uint8_t outbuf[CRYPT_GENSALT_OUTPUT_SIZE]; 129 | 130 | yescrypt_params_t params = 131 | { 132 | .flags = YESCRYPT_DEFAULTS, 133 | .p = 1, 134 | }; 135 | 136 | /* Valid cost parameters are from 1 to 11. The default is 5. 137 | These are used to set yescrypt's 'N' and 'r' parameters as 138 | follows: 139 | N (block count) is specified in units of r (block size, 140 | adjustable in steps of 128 bytes). 141 | 142 | 128 bytes * r = size of each memory block 143 | 144 | 128 bytes * r * N = total amount of memory used for hashing 145 | in N blocks of r * 128 bytes. 146 | 147 | The author of yescrypt recommends in the documentation to use 148 | r=8 (a block size of 1 KiB) for total sizes of 2 MiB and less, 149 | and r=32 (a block size of 4KiB) above that. 150 | This has to do with the typical per-core last-level cache sizes 151 | of current CPUs. */ 152 | 153 | if (count == 0) 154 | count = 5; 155 | 156 | if (count < 3) 157 | { 158 | params.r = 8; // N in 1KiB 159 | params.N = 1ULL << (count + 9); // 1 -> 1024, 2 -> 2048 160 | } 161 | else 162 | { 163 | params.r = 32; // N in 4KiB 164 | params.N = 1ULL << (count + 7); // 3 -> 1024, 4 -> 2048, ... 11 -> 262144 165 | } 166 | 167 | if (!yescrypt_encode_params_r (¶ms, rbytes, nrbytes, outbuf, o_size)) 168 | { 169 | errno = ERANGE; 170 | return; 171 | } 172 | 173 | strcpy_or_abort (output, o_size, outbuf); 174 | return; 175 | } 176 | 177 | #endif /* INCLUDE_gost_yescrypt || INCLUDE_yescrypt || INCLUDE_sm3_yescrypt */ 178 | --------------------------------------------------------------------------------