/* Copyright (C) 2018 vt@altlinux.org * Copyright (C) 2018 Björn Esser besser82@fedoraproject.org * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "crypt-port.h" #if INCLUDE_gost_yescrypt #include "alg-gost3411-2012-hmac.h" #include /* redefine outer hmac to this function to test entropy bypass */ static void test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, uint8_t *out32, gost_hmac_256_t *gostbuf); #define outer_gost_hmac256 test_outer_hmac #include "../lib/crypt-gost-yescrypt.c" static int test_mode = 0; static void test_outer_hmac (const uint8_t *k, size_t n, const uint8_t *t, size_t len, uint8_t *out32, gost_hmac_256_t *gostbuf) { const uint8_t zero[32] = {0}; /* Zero one of arguments to outer hmac. */ if (test_mode & 1) { k = zero; n = sizeof (zero); } if (test_mode & 2) { t = zero; len = sizeof (zero); } gost_hmac256 (k, n, t, len, out32, gostbuf); } static int test_crypt_raw (int m, int p, int s, char **a, size_t *a_size) { char output[CRYPT_OUTPUT_SIZE]; char pass[CRYPT_MAX_PASSPHRASE_SIZE]; char pref[CRYPT_GENSALT_OUTPUT_SIZE]; char scratch[ALG_SPECIFIC_SIZE]; char *salt; test_mode = m; fprintf (stderr, "."); snprintf (pass, sizeof (pass), "%d", p); snprintf (pref, sizeof (pref), "%15d", s); salt = crypt_gensalt ("$gy$", 0, pref, (int) strlen(pref) + 1); if (!salt || salt[0] == '*') { fprintf(stderr, "ERROR: entropy test (gensalt) [%s]\n", pref); return 1; } crypt_gost_yescrypt_rn (pass, strlen (pass), salt, strlen (salt), (uint8_t *) output, sizeof (output), scratch, sizeof (scratch)); if (output[0] == '*') { fprintf(stderr, "ERROR: entropy test (crypt)\n"); return 1; } char *h = strrchr (output, '$') + 1; if (*a && strstr (*a, h)) { fprintf (stderr, "ERROR: duplicated hash %s\n", output); return 1; } size_t len = strlen(h); *a = realloc (*a, *a_size + len + 1); strcpy (*a + *a_size, h); *a_size += len; (*a)[*a_size] = '\0'; return 0; } int main (void) { int result = 0; /* Entropy tests * Replace left then right argument of outer hmac() with constant * and do hashing, verifying that output hashes are still different * when password or salt are changing. * Thus, we prove that entropy is still passing to the output not * depending on yescrypt. */ int m, pp, ss; int etest = 0; char **a = malloc (sizeof (char*)); size_t *a_size = malloc (sizeof (size_t)); *a = malloc (sizeof (char)); (*a)[0] = '\0'; *a_size = 0; for (m = 1; m < 3; m++) { for (pp = 0; pp < 22; pp++) etest |= test_crypt_raw (m, pp, 0, a, a_size); for (ss = 0; ss < 22; ss++) etest |= test_crypt_raw (m, pp, ss, a, a_size); } fprintf (stderr, "\n"); if (etest) fprintf (stderr, "ERROR: entropy test failed.\n"); else fprintf (stderr, " ok: entropy test\n"); result |= etest; free (*a); free (a); free (a_size); return result; } #else int main (void) { return 77; /* UNSUPPORTED */ } #endif /* INCLUDE_gost_yescrypt */