用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
12 KiB

5 months ago
/* Copyright (c) 2011, 2019, 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, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
Without limiting anything contained in the foregoing, this file,
which is part of C Driver for MySQL (Connector/C), is also subject to the
Universal FOSS Exception, version 1.0, a copy of which can be found at
http://oss.oracle.com/licenses/universal-foss-exception.
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, version 2.0, 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 */
/**
@file mysys/crypt_genhash_impl.cc
*/
// First include (the generated) my_config.h, to get correct platform defines.
#include "my_config.h"
#include <sys/types.h>
#ifdef HAVE_OPENSSL
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt_genhash_impl.h"
#include "m_string.h"
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <errno.h>
#ifdef _WIN32
#include <malloc.h>
#endif
#define DIGEST_CTX EVP_MD_CTX
#define DIGEST_LEN SHA256_DIGEST_LENGTH
static void DIGESTCreate(DIGEST_CTX **ctx) {
if (ctx != nullptr) {
*ctx = EVP_MD_CTX_create();
}
}
static void DIGESTInit(DIGEST_CTX *ctx) {
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
}
static void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len) {
EVP_DigestUpdate(ctx, plaintext, len);
}
static void DIGESTFinal(void *txt, DIGEST_CTX *ctx) {
EVP_DigestFinal_ex(ctx, (unsigned char *)txt, NULL);
}
static void DIGESTDestroy(DIGEST_CTX **ctx) {
if (ctx != nullptr) {
EVP_MD_CTX_destroy(*ctx);
*ctx = NULL;
}
}
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
#ifndef HAVE_STRLCAT
/**
Size-bounded string copying and concatenation
This is a replacement for STRLCPY(3)
*/
static 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 */
}
#endif
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 [in,out] salt_begin As input, pointer to start of crypt passwd,
as output, pointer to first byte of the salt
@param [in,out] salt_end As input, pointer to the last byte in passwd,
as output, pointer to the byte immediatly following
the salt ($)
@return The size of the salt identified
*/
int extract_user_salt(const char **salt_begin, const char **salt_end) {
const 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;
}
/*
* Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) :
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> 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 <drepper@redhat.com>."
*/
/*
Due to a Solaris namespace bug DS is a reserved word. To work around this
DS is undefined.
*/
#undef DS
/* ARGSUSED4 */
char *my_crypt_genhash(char *ctbuffer, size_t ctbufflen, const char *plaintext,
size_t plaintext_len, const char *switchsalt,
const char **, unsigned int *num_rounds) /* = NULL */
{
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 = nullptr;
unsigned int rounds =
num_rounds && (*num_rounds <= ROUNDS_MAX && *num_rounds >= ROUNDS_MIN)
? *num_rounds
: ROUNDS_DEFAULT;
int srounds = 0;
bool custom_rounds = false;
char *p;
char *P, *Pp;
char *S, *Sp;
/* Create Digest context. */
DIGESTCreate(&ctxA);
DIGESTCreate(&ctxB);
DIGESTCreate(&ctxC);
DIGESTCreate(&ctxDP);
DIGESTCreate(&ctxDS);
if (num_rounds) *num_rounds = rounds;
/* Refine the salt */
salt = const_cast<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)snprintf(ctbuffer, ctbufflen, "%s$rounds=%zu$", crypt_alg_magic,
(size_t)rounds);
} else {
(void)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));
/* 23. Clearing the context */
DIGESTDestroy(&ctxA);
DIGESTDestroy(&ctxB);
DIGESTDestroy(&ctxC);
DIGESTDestroy(&ctxDP);
DIGESTDestroy(&ctxDS);
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.
*/
void generate_user_salt(char *buffer, int buffer_len) {
char *end = buffer + buffer_len - 1;
RAND_bytes((unsigned char *)buffer, buffer_len);
/* 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