From 354bb40e75d94466e91fe6960523612c9d17ccfb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 2 Nov 2017 23:11:29 +0300 Subject: Add implementation --- mysql/mysys_ssl/crypt_genhash_impl.cpp | 465 +++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 mysql/mysys_ssl/crypt_genhash_impl.cpp (limited to 'mysql/mysys_ssl/crypt_genhash_impl.cpp') diff --git a/mysql/mysys_ssl/crypt_genhash_impl.cpp b/mysql/mysys_ssl/crypt_genhash_impl.cpp new file mode 100644 index 0000000..80b61dc --- /dev/null +++ b/mysql/mysys_ssl/crypt_genhash_impl.cpp @@ -0,0 +1,465 @@ +/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +// First include (the generated) my_config.h, to get correct platform defines. +#include "my_config.h" + +#ifdef HAVE_OPENSSL + +#ifdef HAVE_YASSL +#include +#include +#else +#include +#include +#endif + +#include "crypt_genhash_impl.h" + +#include "m_string.h" + +#include +#include +#include + +#ifdef HAVE_ALLOCA_H +#include +#endif + +#ifndef HAVE_YASSL +#define DIGEST_CTX SHA256_CTX +#define DIGESTInit SHA256_Init +#define DIGESTUpdate SHA256_Update +#define DIGESTFinal SHA256_Final +#define DIGEST_LEN SHA256_DIGEST_LENGTH +#else +#define DIGEST_CTX TaoCrypt::SHA256 +#define DIGEST_LEN 32 +void DIGESTInit(DIGEST_CTX *ctx) +{ + ctx->Init(); +} + +void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len) +{ + ctx->Update((const TaoCrypt::byte *)plaintext, len); +} + +void DIGESTFinal(void *txt, DIGEST_CTX *ctx) +{ + ctx->Final((TaoCrypt::byte *)txt); +} + +#endif // HAVE_YASSL + +static const char crypt_alg_magic[] = "$5"; + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + + +/** + Size-bounded string copying and concatenation + This is a replacement for STRLCPY(3) +*/ + +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d= dst; + const char *s= src; + size_t n= siz; + size_t dlen; + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen= d - dst; + n= siz - dlen; + if (n == 0) + return(dlen + siz); + while (*s != '\0') + { + if (n != 1) + { + *d++= *s; + n--; + } + s++; + } + *d= '\0'; + return(dlen + (s - src)); /* count does not include NUL */ +} + +static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1; + +static unsigned char b64t[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +#define b64_from_24bit(B2, B1, B0, N) \ +{ \ + uint32_t w = ((B2) << 16) | ((B1) << 8) | (B0); \ + int n = (N); \ + while (--n >= 0 && ctbufflen > 0) { \ + *p++ = b64t[w & 0x3f]; \ + w >>= 6; \ + ctbufflen--; \ +} \ +} + +#define ROUNDS "rounds=" +#define ROUNDSLEN (sizeof (ROUNDS) - 1) + +/** + Get the integer value after rounds= where ever it occurs in the string. + if the last char after the int is a , or $ that is fine anything else is an + error. +*/ +static uint getrounds(const char *s) +{ + const char *r; + const char *p; + char *e; + long val; + + if (s == NULL) + return (0); + + if ((r = strstr(s, ROUNDS)) == NULL) + { + return (0); + } + + if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) + { + return (0); + } + + p= r + ROUNDSLEN; + errno= 0; + val= strtol(p, &e, 10); + /* + An error occurred or there is non-numeric stuff at the end + which isn't one of the crypt(3c) special chars ',' or '$' + */ + if (errno != 0 || val < 0 || !(*e == '\0' || *e == ',' || *e == '$')) + { + return (0); + } + + return ((uint32_t) val); +} + +/** + Finds the interval which envelopes the user salt in a crypt password + The crypt format is assumed to be $a$bbbb$cccccc\0 and the salt is found + by counting the delimiters and marking begin and end. + + @param salt_being[in] Pointer to start of crypt passwd + @param salt_being[out] Pointer to first byte of the salt + @param salt_end[in] Pointer to the last byte in passwd + @param salt_end[out] Pointer to the byte immediatly following the salt ($) + + @return The size of the salt identified +*/ + +int extract_user_salt(char **salt_begin, + char **salt_end) +{ + char *it= *salt_begin; + int delimiter_count= 0; + while(it != *salt_end) + { + if (*it == '$') + { + ++delimiter_count; + if (delimiter_count == 2) + { + *salt_begin= it + 1; + } + if (delimiter_count == 3) + break; + } + ++it; + } + *salt_end= it; + return *salt_end - *salt_begin; +} + +const char *sha256_find_digest(char *pass) +{ + int sz= strlen(pass); + return pass + sz - SHA256_HASH_LENGTH; +} + +/* + * Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) : + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ + * + */ + +/* + * The below code implements the specification from: + * + * From http://people.redhat.com/drepper/SHA-crypt.txt + * + * Portions of the code taken from inspired by or verified against the + * source in the above document which is licensed as: + * + * "Released into the Public Domain by Ulrich Drepper ." + */ + +/* + Due to a Solaris namespace bug DS is a reserved word. To work around this + DS is undefined. +*/ +#undef DS + +/* ARGSUSED4 */ +extern "C" +char * +my_crypt_genhash(char *ctbuffer, + size_t ctbufflen, + const char *plaintext, + size_t plaintext_len, + const char *switchsalt, + const char **params) +{ + int salt_len; + size_t i; + char *salt; + unsigned char A[DIGEST_LEN]; + unsigned char B[DIGEST_LEN]; + unsigned char DP[DIGEST_LEN]; + unsigned char DS[DIGEST_LEN]; + DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS; + uint rounds = ROUNDS_DEFAULT; + int srounds = 0; + bool custom_rounds= false; + char *p; + char *P, *Pp; + char *S, *Sp; + + /* Refine the salt */ + salt = (char *)switchsalt; + + /* skip our magic string */ + if (strncmp(salt, crypt_alg_magic, crypt_alg_magic_len) == 0) + { + salt += crypt_alg_magic_len + 1; + } + + srounds = getrounds(salt); + if (srounds != 0) { + rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); + custom_rounds= true; + p = strchr(salt, '$'); + if (p != NULL) + salt = p + 1; + } + + salt_len = MIN(strcspn(salt, "$"), CRYPT_SALT_LENGTH); + //plaintext_len = strlen(plaintext); + + /* 1. */ + DIGESTInit(&ctxA); + + /* 2. The password first, since that is what is most unknown */ + DIGESTUpdate(&ctxA, plaintext, plaintext_len); + + /* 3. Then the raw salt */ + DIGESTUpdate(&ctxA, salt, salt_len); + + /* 4. - 8. */ + DIGESTInit(&ctxB); + DIGESTUpdate(&ctxB, plaintext, plaintext_len); + DIGESTUpdate(&ctxB, salt, salt_len); + DIGESTUpdate(&ctxB, plaintext, plaintext_len); + DIGESTFinal(B, &ctxB); + + /* 9. - 10. */ + for (i= plaintext_len; i > MIXCHARS; i -= MIXCHARS) + DIGESTUpdate(&ctxA, B, MIXCHARS); + DIGESTUpdate(&ctxA, B, i); + + /* 11. */ + for (i= plaintext_len; i > 0; i >>= 1) { + if ((i & 1) != 0) + { + DIGESTUpdate(&ctxA, B, MIXCHARS); + } + else + { + DIGESTUpdate(&ctxA, plaintext, plaintext_len); + } + } + + /* 12. */ + DIGESTFinal(A, &ctxA); + + /* 13. - 15. */ + DIGESTInit(&ctxDP); + for (i= 0; i < plaintext_len; i++) + DIGESTUpdate(&ctxDP, plaintext, plaintext_len); + DIGESTFinal(DP, &ctxDP); + + /* 16. */ + Pp= P= (char *)alloca(plaintext_len); + for (i= plaintext_len; i >= MIXCHARS; i -= MIXCHARS) + { + Pp= (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS; + } + (void) memcpy(Pp, DP, i); + + /* 17. - 19. */ + DIGESTInit(&ctxDS); + for (i= 0; i < 16U + (uint8_t)A[0]; i++) + DIGESTUpdate(&ctxDS, salt, salt_len); + DIGESTFinal(DS, &ctxDS); + + /* 20. */ + Sp= S= (char *)alloca(salt_len); + for (i= salt_len; i >= MIXCHARS; i -= MIXCHARS) + { + Sp= (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS; + } + (void) memcpy(Sp, DS, i); + + /* 21. */ + for (i= 0; i < rounds; i++) + { + DIGESTInit(&ctxC); + + if ((i & 1) != 0) + { + DIGESTUpdate(&ctxC, P, plaintext_len); + } + else + { + if (i == 0) + DIGESTUpdate(&ctxC, A, MIXCHARS); + else + DIGESTUpdate(&ctxC, DP, MIXCHARS); + } + + if (i % 3 != 0) { + DIGESTUpdate(&ctxC, S, salt_len); + } + + if (i % 7 != 0) { + DIGESTUpdate(&ctxC, P, plaintext_len); + } + + if ((i & 1) != 0) + { + if (i == 0) + DIGESTUpdate(&ctxC, A, MIXCHARS); + else + DIGESTUpdate(&ctxC, DP, MIXCHARS); + } + else + { + DIGESTUpdate(&ctxC, P, plaintext_len); + } + DIGESTFinal(DP, &ctxC); + } + + /* 22. Now make the output string */ + if (custom_rounds) + { + (void) my_snprintf(ctbuffer, ctbufflen, + "%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds); + } + else + { + (void) my_snprintf(ctbuffer, ctbufflen, + "%s$", crypt_alg_magic); + } + (void) strncat(ctbuffer, (const char *)salt, salt_len); + (void) strlcat(ctbuffer, "$", ctbufflen); + + p= ctbuffer + strlen(ctbuffer); + ctbufflen -= strlen(ctbuffer); + + b64_from_24bit(DP[ 0], DP[10], DP[20], 4); + b64_from_24bit(DP[21], DP[ 1], DP[11], 4); + b64_from_24bit(DP[12], DP[22], DP[ 2], 4); + b64_from_24bit(DP[ 3], DP[13], DP[23], 4); + b64_from_24bit(DP[24], DP[ 4], DP[14], 4); + b64_from_24bit(DP[15], DP[25], DP[ 5], 4); + b64_from_24bit(DP[ 6], DP[16], DP[26], 4); + b64_from_24bit(DP[27], DP[ 7], DP[17], 4); + b64_from_24bit(DP[18], DP[28], DP[ 8], 4); + b64_from_24bit(DP[ 9], DP[19], DP[29], 4); + b64_from_24bit(0, DP[31], DP[30], 3); + *p= '\0'; + + (void) memset(A, 0, sizeof (A)); + (void) memset(B, 0, sizeof (B)); + (void) memset(DP, 0, sizeof (DP)); + (void) memset(DS, 0, sizeof (DS)); + + return (ctbuffer); +} + + +/** + Generate a random string using ASCII characters but avoid seperator character. + Stdlib rand and srand are used to produce pseudo random numbers between + with about 7 bit worth of entropty between 1-127. +*/ +extern "C" +void generate_user_salt(char *buffer, int buffer_len) +{ + char *end= buffer + buffer_len - 1; +#ifdef HAVE_YASSL + yaSSL::RAND_bytes((unsigned char *) buffer, buffer_len); +#else + RAND_bytes((unsigned char *) buffer, buffer_len); +#endif + + /* Sequence must be a legal UTF8 string */ + for (; buffer < end; buffer++) + { + *buffer &= 0x7f; + if (*buffer == '\0' || *buffer == '$') + *buffer= *buffer + 1; + } + /* Make sure the buffer is terminated properly */ + *end= '\0'; +} + +void xor_string(char *to, int to_len, char *pattern, int pattern_len) +{ + int loop= 0; + while(loop <= to_len) + { + *(to + loop) ^= *(pattern + loop % pattern_len); + ++loop; + } +} + +#endif // HAVE_OPENSSL -- cgit v1.1