char * __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) { unsigned char alt_result[64] __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); unsigned char temp_result[64] __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); size_t salt_len; size_t key_len; size_t cnt; char *cp; char *copied_key = NULL; char *copied_salt = NULL; char *p_bytes; char *s_bytes; /* Default number of rounds. */ size_t rounds = ROUNDS_DEFAULT; bool rounds_custom = false; size_t alloca_used = 0; char *free_key = NULL; char *free_pbytes = NULL; /* Find beginning of salt string. The prefix should normally always be present. Just in case it is not. */ if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0) /* Skip salt prefix. */ salt += sizeof (sha512_salt_prefix) - 1; if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1) == 0) { const char *num = salt + sizeof (sha512_rounds_prefix) - 1; char *endp; unsigned long int srounds = strtoul (num, &endp, 10); if (*endp == '$') { salt = endp + 1; rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX)); rounds_custom = true; } } salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); key_len = strlen (key); if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { char *tmp; if (__libc_use_alloca (alloca_used + key_len + __alignof__ (uint64_t))) tmp = alloca_account (key_len + __alignof__ (uint64_t), alloca_used); else { free_key = tmp = (char *) malloc (key_len + __alignof__ (uint64_t)); if (tmp == NULL) return NULL; } key = copied_key = memcpy (tmp + __alignof__ (uint64_t) - (tmp - (char *) 0) % __alignof__ (uint64_t), key, key_len); assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0); } if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) { char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t)); salt = copied_salt = memcpy (tmp + __alignof__ (uint64_t) - (tmp - (char *) 0) % __alignof__ (uint64_t), salt, salt_len); assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0); } #ifdef USE_NSS /* Initialize libfreebl3. */ NSSLOWInitContext *nss_ictx = NSSLOW_Init (); if (nss_ictx == NULL) { free (free_key); return NULL; } NSSLOWHASHContext *nss_ctx = NULL; NSSLOWHASHContext *nss_alt_ctx = NULL; #else struct sha512_ctx ctx; struct sha512_ctx alt_ctx; #endif /* Prepare for the real work. */ sha512_init_ctx (&ctx, nss_ctx); /* Add the key string. */ sha512_process_bytes (key, key_len, &ctx, nss_ctx); /* The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character. */ sha512_process_bytes (salt, salt_len, &ctx, nss_ctx); /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The final result will be added to the first context. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* Add key. */ sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Add salt. */ sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx); /* Add key again. */ sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Now get result of this (64 bytes) and add it to the other context. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result); /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > 64; cnt -= 64) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); sha512_process_bytes (alt_result, cnt, &ctx, nss_ctx); /* Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0 the key. */ for (cnt = key_len; cnt > 0; cnt >>= 1) if ((cnt & 1) != 0) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); else sha512_process_bytes (key, key_len, &ctx, nss_ctx); /* Create intermediate result. */ sha512_finish_ctx (&ctx, nss_ctx, alt_result); /* Start computation of P byte sequence. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* For every character in the password add the entire password. */ for (cnt = 0; cnt < key_len; ++cnt) sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Finish the digest. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result); /* Create byte sequence P. */ if (__libc_use_alloca (alloca_used + key_len)) cp = p_bytes = (char *) alloca (key_len); else { free_pbytes = cp = p_bytes = (char *)malloc (key_len); if (free_pbytes == NULL) { free (free_key); return NULL; } } for (cnt = key_len; cnt >= 64; cnt -= 64) cp = mempcpy (cp, temp_result, 64); memcpy (cp, temp_result, cnt); /* Start computation of S byte sequence. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* For every character in the password add the entire password. */ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx); /* Finish the digest. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result); /* Create byte sequence S. */ cp = s_bytes = alloca (salt_len); for (cnt = salt_len; cnt >= 64; cnt -= 64) cp = mempcpy (cp, temp_result, 64); memcpy (cp, temp_result, cnt); /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */ for (cnt = 0; cnt < rounds; ++cnt) { /* New context. */ sha512_init_ctx (&ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); else sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) sha512_process_bytes (s_bytes, salt_len, &ctx, nss_ctx); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); else sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); /* Create intermediate result. */ sha512_finish_ctx (&ctx, nss_ctx, alt_result); } #ifdef USE_NSS /* Free libfreebl3 resources. */ NSSLOW_Shutdown (nss_ictx); #endif /* Now we can construct the result string. It consists of three parts. */ cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen)); buflen -= sizeof (sha512_salt_prefix) - 1; if (rounds_custom) { int n = snprintf (cp, MAX (0, buflen), "%s%zu$", sha512_rounds_prefix, rounds); cp += n; buflen -= n; } cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); buflen -= MIN ((size_t) MAX (0, buflen), salt_len); if (buflen > 0) { *cp++ = '$'; --buflen; } __b64_from_24bit (&cp, &buflen, alt_result[0], alt_result[21], alt_result[42], 4); __b64_from_24bit (&cp, &buflen, alt_result[22], alt_result[43], alt_result[1], 4); __b64_from_24bit (&cp, &buflen, alt_result[44], alt_result[2], alt_result[23], 4); __b64_from_24bit (&cp, &buflen, alt_result[3], alt_result[24], alt_result[45], 4); __b64_from_24bit (&cp, &buflen, alt_result[25], alt_result[46], alt_result[4], 4); __b64_from_24bit (&cp, &buflen, alt_result[47], alt_result[5], alt_result[26], 4); __b64_from_24bit (&cp, &buflen, alt_result[6], alt_result[27], alt_result[48], 4); __b64_from_24bit (&cp, &buflen, alt_result[28], alt_result[49], alt_result[7], 4); __b64_from_24bit (&cp, &buflen, alt_result[50], alt_result[8], alt_result[29], 4); __b64_from_24bit (&cp, &buflen, alt_result[9], alt_result[30], alt_result[51], 4); __b64_from_24bit (&cp, &buflen, alt_result[31], alt_result[52], alt_result[10], 4); __b64_from_24bit (&cp, &buflen, alt_result[53], alt_result[11], alt_result[32], 4); __b64_from_24bit (&cp, &buflen, alt_result[12], alt_result[33], alt_result[54], 4); __b64_from_24bit (&cp, &buflen, alt_result[34], alt_result[55], alt_result[13], 4); __b64_from_24bit (&cp, &buflen, alt_result[56], alt_result[14], alt_result[35], 4); __b64_from_24bit (&cp, &buflen, alt_result[15], alt_result[36], alt_result[57], 4); __b64_from_24bit (&cp, &buflen, alt_result[37], alt_result[58], alt_result[16], 4); __b64_from_24bit (&cp, &buflen, alt_result[59], alt_result[17], alt_result[38], 4); __b64_from_24bit (&cp, &buflen, alt_result[18], alt_result[39], alt_result[60], 4); __b64_from_24bit (&cp, &buflen, alt_result[40], alt_result[61], alt_result[19], 4); __b64_from_24bit (&cp, &buflen, alt_result[62], alt_result[20], alt_result[41], 4); __b64_from_24bit (&cp, &buflen, 0, 0, alt_result[63], 2); if (buflen <= 0) { __set_errno (ERANGE); buffer = NULL; } else *cp = '\0'; /* Terminate the string. */ /* Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps cannot get any information. We do it in this way to clear correct_words[] inside the SHA512 implementation as well. */ #ifndef USE_NSS __sha512_init_ctx (&ctx); __sha512_finish_ctx (&ctx, alt_result); memset (&ctx, '\0', sizeof (ctx)); memset (&alt_ctx, '\0', sizeof (alt_ctx)); #endif memset (temp_result, '\0', sizeof (temp_result)); memset (p_bytes, '\0', key_len); memset (s_bytes, '\0', salt_len); if (copied_key != NULL) memset (copied_key, '\0', key_len); if (copied_salt != NULL) memset (copied_salt, '\0', salt_len); free (free_key); free (free_pbytes); return buffer; }
int fnmatch (const char *pattern, const char *string, int flags) { # if HANDLE_MULTIBYTE if (__builtin_expect (MB_CUR_MAX, 1) != 1) { mbstate_t ps; size_t n; const char *p; wchar_t *wpattern_malloc = NULL; wchar_t *wpattern; wchar_t *wstring_malloc = NULL; wchar_t *wstring; size_t alloca_used = 0; /* Convert the strings into wide characters. */ memset (&ps, '\0', sizeof (ps)); p = pattern; #ifdef _LIBC n = __strnlen (pattern, 1024); #else n = strlen (pattern); #endif if (__glibc_likely (n < 1024)) { wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), alloca_used); n = mbsrtowcs (wpattern, &p, n + 1, &ps); if (__glibc_unlikely (n == (size_t) -1)) /* Something wrong. XXX Do we have to set `errno' to something which mbsrtows hasn't already done? */ return -1; if (p) { memset (&ps, '\0', sizeof (ps)); goto prepare_wpattern; } } else { prepare_wpattern: n = mbsrtowcs (NULL, &pattern, 0, &ps); if (__glibc_unlikely (n == (size_t) -1)) /* Something wrong. XXX Do we have to set `errno' to something which mbsrtows hasn't already done? */ return -1; if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) { __set_errno (ENOMEM); return -2; } wpattern_malloc = wpattern = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); assert (mbsinit (&ps)); if (wpattern == NULL) return -2; (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); } assert (mbsinit (&ps)); #ifdef _LIBC n = __strnlen (string, 1024); #else n = strlen (string); #endif p = string; if (__glibc_likely (n < 1024)) { wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), alloca_used); n = mbsrtowcs (wstring, &p, n + 1, &ps); if (__glibc_unlikely (n == (size_t) -1)) { /* Something wrong. XXX Do we have to set `errno' to something which mbsrtows hasn't already done? */ free_return: free (wpattern_malloc); return -1; } if (p) { memset (&ps, '\0', sizeof (ps)); goto prepare_wstring; } } else { prepare_wstring: n = mbsrtowcs (NULL, &string, 0, &ps); if (__glibc_unlikely (n == (size_t) -1)) /* Something wrong. XXX Do we have to set `errno' to something which mbsrtows hasn't already done? */ goto free_return; if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) { free (wpattern_malloc); __set_errno (ENOMEM); return -2; } wstring_malloc = wstring = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); if (wstring == NULL) { free (wpattern_malloc); return -2; } assert (mbsinit (&ps)); (void) mbsrtowcs (wstring, &string, n + 1, &ps); } int res = internal_fnwmatch (wpattern, wstring, wstring + n, flags & FNM_PERIOD, flags, NULL, alloca_used); free (wstring_malloc); free (wpattern_malloc); return res; } # endif /* mbstate_t and mbsrtowcs or _LIBC. */ return internal_fnmatch (pattern, string, string + strlen (string), flags & FNM_PERIOD, flags, NULL, 0); }