Add password hashing
This commit is contained in:
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2002.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 2000-2002 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gnu-crypt.h>
|
|
||||||
|
|
||||||
#if defined(_OW_SOURCE) || defined(__USE_OW)
|
|
||||||
#define __SKIP_GNU
|
|
||||||
#undef __SKIP_OW
|
|
||||||
#include <ow-crypt.h>
|
|
||||||
#undef __SKIP_GNU
|
|
||||||
#endif
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*
|
|
||||||
* This file contains salt generation functions for the traditional and
|
|
||||||
* other common crypt(3) algorithms, except for bcrypt which is defined
|
|
||||||
* entirely in crypt_blowfish.c.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#ifndef __set_errno
|
|
||||||
#define __set_errno(val) errno = (val)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Just to make sure the prototypes match the actual definitions */
|
|
||||||
#include "crypt_gensalt.h"
|
|
||||||
|
|
||||||
unsigned char _crypt_itoa64[64 + 1] =
|
|
||||||
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
||||||
|
|
||||||
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size)
|
|
||||||
{
|
|
||||||
(void) prefix;
|
|
||||||
|
|
||||||
if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
|
|
||||||
if (output_size > 0) output[0] = '\0';
|
|
||||||
__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
|
|
||||||
output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
|
|
||||||
output[2] = '\0';
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size)
|
|
||||||
{
|
|
||||||
unsigned long value;
|
|
||||||
|
|
||||||
(void) prefix;
|
|
||||||
|
|
||||||
/* Even iteration counts make it easier to detect weak DES keys from a look
|
|
||||||
* at the hash, so they should be avoided */
|
|
||||||
if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
|
|
||||||
(count && (count > 0xffffff || !(count & 1)))) {
|
|
||||||
if (output_size > 0) output[0] = '\0';
|
|
||||||
__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!count) count = 725;
|
|
||||||
|
|
||||||
output[0] = '_';
|
|
||||||
output[1] = _crypt_itoa64[count & 0x3f];
|
|
||||||
output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
|
|
||||||
output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
|
|
||||||
output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
|
|
||||||
value = (unsigned long)(unsigned char)input[0] |
|
|
||||||
((unsigned long)(unsigned char)input[1] << 8) |
|
|
||||||
((unsigned long)(unsigned char)input[2] << 16);
|
|
||||||
output[5] = _crypt_itoa64[value & 0x3f];
|
|
||||||
output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
|
|
||||||
output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
|
|
||||||
output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
|
|
||||||
output[9] = '\0';
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size)
|
|
||||||
{
|
|
||||||
unsigned long value;
|
|
||||||
|
|
||||||
(void) prefix;
|
|
||||||
|
|
||||||
if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
|
|
||||||
if (output_size > 0) output[0] = '\0';
|
|
||||||
__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
output[0] = '$';
|
|
||||||
output[1] = '1';
|
|
||||||
output[2] = '$';
|
|
||||||
value = (unsigned long)(unsigned char)input[0] |
|
|
||||||
((unsigned long)(unsigned char)input[1] << 8) |
|
|
||||||
((unsigned long)(unsigned char)input[2] << 16);
|
|
||||||
output[3] = _crypt_itoa64[value & 0x3f];
|
|
||||||
output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
|
|
||||||
output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
|
|
||||||
output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
|
|
||||||
output[7] = '\0';
|
|
||||||
|
|
||||||
if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
|
|
||||||
value = (unsigned long)(unsigned char)input[3] |
|
|
||||||
((unsigned long)(unsigned char)input[4] << 8) |
|
|
||||||
((unsigned long)(unsigned char)input[5] << 16);
|
|
||||||
output[7] = _crypt_itoa64[value & 0x3f];
|
|
||||||
output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
|
|
||||||
output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
|
|
||||||
output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
|
|
||||||
output[11] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CRYPT_GENSALT_H
|
|
||||||
#define _CRYPT_GENSALT_H
|
|
||||||
|
|
||||||
extern unsigned char _crypt_itoa64[];
|
|
||||||
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
|
|
||||||
unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size);
|
|
||||||
extern char *_crypt_gensalt_extended_rn(const char *prefix,
|
|
||||||
unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size);
|
|
||||||
extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _OW_CRYPT_H
|
|
||||||
#define _OW_CRYPT_H
|
|
||||||
|
|
||||||
#ifndef __GNUC__
|
|
||||||
#undef __const
|
|
||||||
#define __const const
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __SKIP_GNU
|
|
||||||
extern char *crypt(__const char *key, __const char *setting);
|
|
||||||
extern char *crypt_r(__const char *key, __const char *setting, void *data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __SKIP_OW
|
|
||||||
extern char *crypt_rn(__const char *key, __const char *setting,
|
|
||||||
void *data, int size);
|
|
||||||
extern char *crypt_ra(__const char *key, __const char *setting,
|
|
||||||
void **data, int *size);
|
|
||||||
extern char *crypt_gensalt(__const char *prefix, unsigned long count,
|
|
||||||
__const char *input, int size);
|
|
||||||
extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
|
|
||||||
__const char *input, int size, char *output, int output_size);
|
|
||||||
extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
|
|
||||||
__const char *input, int size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,551 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 2000-2014.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#ifndef __set_errno
|
|
||||||
#define __set_errno(val) errno = (val)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TEST
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/times.h>
|
|
||||||
#ifdef TEST_THREADS
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CRYPT_OUTPUT_SIZE (7 + 22 + 31 + 1)
|
|
||||||
#define CRYPT_GENSALT_OUTPUT_SIZE (7 + 22 + 1)
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && defined(_LIBC)
|
|
||||||
#define __SKIP_GNU
|
|
||||||
#endif
|
|
||||||
#include "ow-crypt.h"
|
|
||||||
|
|
||||||
#include "crypt_blowfish.h"
|
|
||||||
#include "crypt_gensalt.h"
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && defined(_LIBC)
|
|
||||||
/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
|
|
||||||
#include "crypt.h"
|
|
||||||
extern char *__md5_crypt_r(const char *key, const char *salt,
|
|
||||||
char *buffer, int buflen);
|
|
||||||
/* crypt-entry.c needs to be patched to define __des_crypt_r rather than
|
|
||||||
* __crypt_r, and not define crypt_r and crypt at all */
|
|
||||||
extern char *__des_crypt_r(const char *key, const char *salt,
|
|
||||||
struct crypt_data *data);
|
|
||||||
extern struct crypt_data _ufc_foobar;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int _crypt_data_alloc(void **data, int *size, int need)
|
|
||||||
{
|
|
||||||
void *updated;
|
|
||||||
|
|
||||||
if (*data && *size >= need) return 0;
|
|
||||||
|
|
||||||
updated = realloc(*data, need);
|
|
||||||
|
|
||||||
if (!updated) {
|
|
||||||
#ifndef __GLIBC__
|
|
||||||
/* realloc(3) on glibc sets errno, so we don't need to bother */
|
|
||||||
__set_errno(ENOMEM);
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && defined(_LIBC)
|
|
||||||
if (need >= sizeof(struct crypt_data))
|
|
||||||
((struct crypt_data *)updated)->initialized = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*data = updated;
|
|
||||||
*size = need;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *_crypt_retval_magic(char *retval, const char *setting,
|
|
||||||
char *output, int size)
|
|
||||||
{
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (_crypt_output_magic(setting, output, size))
|
|
||||||
return NULL; /* shouldn't happen */
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && defined(_LIBC)
|
|
||||||
/*
|
|
||||||
* Applications may re-use the same instance of struct crypt_data without
|
|
||||||
* resetting the initialized field in order to let crypt_r() skip some of
|
|
||||||
* its initialization code. Thus, it is important that our multiple hashing
|
|
||||||
* algorithms either don't conflict with each other in their use of the
|
|
||||||
* data area or reset the initialized field themselves whenever required.
|
|
||||||
* Currently, the hashing algorithms simply have no conflicts: the first
|
|
||||||
* field of struct crypt_data is the 128-byte large DES key schedule which
|
|
||||||
* __des_crypt_r() calculates each time it is called while the two other
|
|
||||||
* hashing algorithms use less than 128 bytes of the data area.
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *__crypt_rn(__const char *key, __const char *setting,
|
|
||||||
void *data, int size)
|
|
||||||
{
|
|
||||||
if (setting[0] == '$' && setting[1] == '2')
|
|
||||||
return _crypt_blowfish_rn(key, setting, (char *)data, size);
|
|
||||||
if (setting[0] == '$' && setting[1] == '1')
|
|
||||||
return __md5_crypt_r(key, setting, (char *)data, size);
|
|
||||||
if (setting[0] == '$' || setting[0] == '_') {
|
|
||||||
__set_errno(EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (size >= sizeof(struct crypt_data))
|
|
||||||
return __des_crypt_r(key, setting, (struct crypt_data *)data);
|
|
||||||
__set_errno(ERANGE);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *__crypt_ra(__const char *key, __const char *setting,
|
|
||||||
void **data, int *size)
|
|
||||||
{
|
|
||||||
if (setting[0] == '$' && setting[1] == '2') {
|
|
||||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
|
||||||
return NULL;
|
|
||||||
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
|
||||||
}
|
|
||||||
if (setting[0] == '$' && setting[1] == '1') {
|
|
||||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
|
||||||
return NULL;
|
|
||||||
return __md5_crypt_r(key, setting, (char *)*data, *size);
|
|
||||||
}
|
|
||||||
if (setting[0] == '$' || setting[0] == '_') {
|
|
||||||
__set_errno(EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
|
|
||||||
return NULL;
|
|
||||||
return __des_crypt_r(key, setting, (struct crypt_data *)*data);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *__crypt_r(__const char *key, __const char *setting,
|
|
||||||
struct crypt_data *data)
|
|
||||||
{
|
|
||||||
return _crypt_retval_magic(
|
|
||||||
__crypt_rn(key, setting, data, sizeof(*data)),
|
|
||||||
setting, (char *)data, sizeof(*data));
|
|
||||||
}
|
|
||||||
|
|
||||||
char *__crypt(__const char *key, __const char *setting)
|
|
||||||
{
|
|
||||||
return _crypt_retval_magic(
|
|
||||||
__crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
|
|
||||||
setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
char *crypt_rn(const char *key, const char *setting, void *data, int size)
|
|
||||||
{
|
|
||||||
return _crypt_blowfish_rn(key, setting, (char *)data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *crypt_ra(const char *key, const char *setting,
|
|
||||||
void **data, int *size)
|
|
||||||
{
|
|
||||||
if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
|
|
||||||
return NULL;
|
|
||||||
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *crypt_r(const char *key, const char *setting, void *data)
|
|
||||||
{
|
|
||||||
return _crypt_retval_magic(
|
|
||||||
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
|
|
||||||
setting, (char *)data, CRYPT_OUTPUT_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *crypt(const char *key, const char *setting)
|
|
||||||
{
|
|
||||||
static char output[CRYPT_OUTPUT_SIZE];
|
|
||||||
|
|
||||||
return _crypt_retval_magic(
|
|
||||||
crypt_rn(key, setting, output, sizeof(output)),
|
|
||||||
setting, output, sizeof(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define __crypt_gensalt_rn crypt_gensalt_rn
|
|
||||||
#define __crypt_gensalt_ra crypt_gensalt_ra
|
|
||||||
#define __crypt_gensalt crypt_gensalt
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size, char *output, int output_size)
|
|
||||||
{
|
|
||||||
char *(*use)(const char *_prefix, unsigned long _count,
|
|
||||||
const char *_input, int _size,
|
|
||||||
char *_output, int _output_size);
|
|
||||||
|
|
||||||
/* This may be supported on some platforms in the future */
|
|
||||||
if (!input) {
|
|
||||||
__set_errno(EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
|
|
||||||
!strncmp(prefix, "$2y$", 4))
|
|
||||||
use = _crypt_gensalt_blowfish_rn;
|
|
||||||
else
|
|
||||||
if (!strncmp(prefix, "$1$", 3))
|
|
||||||
use = _crypt_gensalt_md5_rn;
|
|
||||||
else
|
|
||||||
if (prefix[0] == '_')
|
|
||||||
use = _crypt_gensalt_extended_rn;
|
|
||||||
else
|
|
||||||
if (!prefix[0] ||
|
|
||||||
(prefix[0] && prefix[1] &&
|
|
||||||
memchr(_crypt_itoa64, prefix[0], 64) &&
|
|
||||||
memchr(_crypt_itoa64, prefix[1], 64)))
|
|
||||||
use = _crypt_gensalt_traditional_rn;
|
|
||||||
else {
|
|
||||||
__set_errno(EINVAL);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return use(prefix, count, input, size, output, output_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size)
|
|
||||||
{
|
|
||||||
char output[CRYPT_GENSALT_OUTPUT_SIZE];
|
|
||||||
char *retval;
|
|
||||||
|
|
||||||
retval = __crypt_gensalt_rn(prefix, count,
|
|
||||||
input, size, output, sizeof(output));
|
|
||||||
|
|
||||||
if (retval) {
|
|
||||||
retval = strdup(retval);
|
|
||||||
#ifndef __GLIBC__
|
|
||||||
/* strdup(3) on glibc sets errno, so we don't need to bother */
|
|
||||||
if (!retval)
|
|
||||||
__set_errno(ENOMEM);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *__crypt_gensalt(const char *prefix, unsigned long count,
|
|
||||||
const char *input, int size)
|
|
||||||
{
|
|
||||||
static char output[CRYPT_GENSALT_OUTPUT_SIZE];
|
|
||||||
|
|
||||||
return __crypt_gensalt_rn(prefix, count,
|
|
||||||
input, size, output, sizeof(output));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__GLIBC__) && defined(_LIBC)
|
|
||||||
weak_alias(__crypt_rn, crypt_rn)
|
|
||||||
weak_alias(__crypt_ra, crypt_ra)
|
|
||||||
weak_alias(__crypt_r, crypt_r)
|
|
||||||
weak_alias(__crypt, crypt)
|
|
||||||
weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn)
|
|
||||||
weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra)
|
|
||||||
weak_alias(__crypt_gensalt, crypt_gensalt)
|
|
||||||
weak_alias(crypt, fcrypt)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TEST
|
|
||||||
static const char *tests[][3] = {
|
|
||||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
|
|
||||||
"U*U"},
|
|
||||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
|
|
||||||
"U*U*"},
|
|
||||||
{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
|
|
||||||
"U*U*U"},
|
|
||||||
{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
|
|
||||||
"0123456789abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
|
||||||
"chars after 72 are ignored"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
|
||||||
"\xa3"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
|
||||||
"\xff\xff\xa3"},
|
|
||||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
|
||||||
"\xff\xff\xa3"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
|
|
||||||
"\xff\xff\xa3"},
|
|
||||||
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
|
|
||||||
"\xff\xff\xa3"},
|
|
||||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
|
||||||
"\xa3"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
|
||||||
"\xa3"},
|
|
||||||
{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
|
|
||||||
"\xa3"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
|
||||||
"1\xa3" "345"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
|
||||||
"\xff\xa3" "345"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
|
||||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
|
||||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
|
|
||||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
|
|
||||||
"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
|
|
||||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
|
|
||||||
"\xff\xa3" "345"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
|
|
||||||
"\xff\xa3" "345"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
|
||||||
"\xa3" "ab"},
|
|
||||||
{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
|
||||||
"\xa3" "ab"},
|
|
||||||
{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
|
|
||||||
"\xa3" "ab"},
|
|
||||||
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
|
|
||||||
"\xd1\x91"},
|
|
||||||
{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
|
|
||||||
"\xd0\xc1\xd2\xcf\xcc\xd8"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
|
|
||||||
"chars after 72 are ignored as usual"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
|
|
||||||
"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
|
|
||||||
{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
|
|
||||||
"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
|
|
||||||
{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
|
|
||||||
""},
|
|
||||||
{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
|
|
||||||
{"*1", "", "*0"},
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
#define which tests[0]
|
|
||||||
|
|
||||||
static volatile sig_atomic_t running;
|
|
||||||
|
|
||||||
static void handle_timer(int signum)
|
|
||||||
{
|
|
||||||
(void) signum;
|
|
||||||
running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *run(void *arg)
|
|
||||||
{
|
|
||||||
unsigned long count = 0;
|
|
||||||
int i = 0;
|
|
||||||
void *data = NULL;
|
|
||||||
int size = 0x12345678;
|
|
||||||
|
|
||||||
do {
|
|
||||||
const char *hash = tests[i][0];
|
|
||||||
const char *key = tests[i][1];
|
|
||||||
const char *setting = tests[i][2];
|
|
||||||
|
|
||||||
if (!tests[++i][0])
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if (setting && strlen(hash) < 30) /* not for benchmark */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
|
|
||||||
printf("%d: FAILED (crypt_ra/%d/%lu)\n",
|
|
||||||
(int)((char *)arg - (char *)0), i, count);
|
|
||||||
free(data);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
} while (running);
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
return count + (char *)0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
struct itimerval it;
|
|
||||||
struct tms buf;
|
|
||||||
clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
|
|
||||||
unsigned long count;
|
|
||||||
void *data;
|
|
||||||
int size;
|
|
||||||
char *setting1, *setting2;
|
|
||||||
int i;
|
|
||||||
#ifdef TEST_THREADS
|
|
||||||
pthread_t t[TEST_THREADS];
|
|
||||||
void *t_retval;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
data = NULL;
|
|
||||||
size = 0x12345678;
|
|
||||||
|
|
||||||
for (i = 0; tests[i][0]; i++) {
|
|
||||||
const char *hash = tests[i][0];
|
|
||||||
const char *key = tests[i][1];
|
|
||||||
const char *setting = tests[i][2];
|
|
||||||
const char *p;
|
|
||||||
int ok = !setting || strlen(hash) >= 30;
|
|
||||||
int o_size;
|
|
||||||
char s_buf[30], o_buf[61];
|
|
||||||
if (!setting) {
|
|
||||||
memcpy(s_buf, hash, sizeof(s_buf) - 1);
|
|
||||||
s_buf[sizeof(s_buf) - 1] = 0;
|
|
||||||
setting = s_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
__set_errno(0);
|
|
||||||
p = crypt(key, setting);
|
|
||||||
if ((!ok && !errno) || strcmp(p, hash)) {
|
|
||||||
printf("FAILED (crypt/%d)\n", i);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ok && strcmp(crypt(key, hash), hash)) {
|
|
||||||
printf("FAILED (crypt/%d)\n", i);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
|
|
||||||
int ok_n = ok && o_size == (int)sizeof(o_buf);
|
|
||||||
const char *x = "abc";
|
|
||||||
strcpy(o_buf, x);
|
|
||||||
if (o_size >= 3) {
|
|
||||||
x = "*0";
|
|
||||||
if (setting[0] == '*' && setting[1] == '0')
|
|
||||||
x = "*1";
|
|
||||||
}
|
|
||||||
__set_errno(0);
|
|
||||||
p = crypt_rn(key, setting, o_buf, o_size);
|
|
||||||
if ((ok_n && (!p || strcmp(p, hash))) ||
|
|
||||||
(!ok_n && (!errno || p || strcmp(o_buf, x)))) {
|
|
||||||
printf("FAILED (crypt_rn/%d)\n", i);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__set_errno(0);
|
|
||||||
p = crypt_ra(key, setting, &data, &size);
|
|
||||||
if ((ok && (!p || strcmp(p, hash))) ||
|
|
||||||
(!ok && (!errno || p || strcmp((char *)data, hash)))) {
|
|
||||||
printf("FAILED (crypt_ra/%d)\n", i);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setting1 = crypt_gensalt(which[0], 12, data, size);
|
|
||||||
if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
|
|
||||||
puts("FAILED (crypt_gensalt)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setting2 = crypt_gensalt_ra(setting1, 12, data, size);
|
|
||||||
if (strcmp(setting1, setting2)) {
|
|
||||||
puts("FAILED (crypt_gensalt_ra/1)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*(char *)data)++;
|
|
||||||
setting1 = crypt_gensalt_ra(setting2, 12, data, size);
|
|
||||||
if (!strcmp(setting1, setting2)) {
|
|
||||||
puts("FAILED (crypt_gensalt_ra/2)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(setting1);
|
|
||||||
free(setting2);
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
|
|
||||||
clk_tck = sysconf(_SC_CLK_TCK);
|
|
||||||
#else
|
|
||||||
clk_tck = CLK_TCK;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
running = 1;
|
|
||||||
signal(SIGALRM, handle_timer);
|
|
||||||
|
|
||||||
memset(&it, 0, sizeof(it));
|
|
||||||
it.it_value.tv_sec = 5;
|
|
||||||
setitimer(ITIMER_REAL, &it, NULL);
|
|
||||||
|
|
||||||
start_real = times(&buf);
|
|
||||||
start_virtual = buf.tms_utime + buf.tms_stime;
|
|
||||||
|
|
||||||
count = (char *)run((char *)0) - (char *)0;
|
|
||||||
|
|
||||||
end_real = times(&buf);
|
|
||||||
end_virtual = buf.tms_utime + buf.tms_stime;
|
|
||||||
if (end_virtual == start_virtual) end_virtual++;
|
|
||||||
|
|
||||||
printf("%.1f c/s real, %.1f c/s virtual\n",
|
|
||||||
(float)count * clk_tck / (end_real - start_real),
|
|
||||||
(float)count * clk_tck / (end_virtual - start_virtual));
|
|
||||||
|
|
||||||
#ifdef TEST_THREADS
|
|
||||||
running = 1;
|
|
||||||
it.it_value.tv_sec = 60;
|
|
||||||
setitimer(ITIMER_REAL, &it, NULL);
|
|
||||||
start_real = times(&buf);
|
|
||||||
|
|
||||||
for (i = 0; i < TEST_THREADS; i++)
|
|
||||||
if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
|
|
||||||
perror("pthread_create");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < TEST_THREADS; i++) {
|
|
||||||
if (pthread_join(t[i], &t_retval)) {
|
|
||||||
perror("pthread_join");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!t_retval) continue;
|
|
||||||
count = (char *)t_retval - (char *)0;
|
|
||||||
end_real = times(&buf);
|
|
||||||
printf("%d: %.1f c/s real\n", i,
|
|
||||||
(float)count * clk_tck / (end_real - start_real));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
* Written by Solar Designer <solar at openwall.com> in 1998-2010.
|
|
||||||
* No copyright is claimed, and the software is hereby placed in the public
|
|
||||||
* domain. In case this attempt to disclaim copyright and place the software
|
|
||||||
* in the public domain is deemed null and void, then the software is
|
|
||||||
* Copyright (c) 1998-2010 Solar Designer and it is hereby released to the
|
|
||||||
* general public under the following terms:
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted.
|
|
||||||
*
|
|
||||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
|
||||||
*
|
|
||||||
* See crypt_blowfish.c for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __i386__
|
|
||||||
|
|
||||||
#if defined(__OpenBSD__) && !defined(__ELF__)
|
|
||||||
#define UNDERSCORES
|
|
||||||
#define ALIGN_LOG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__CYGWIN32__) || defined(__MINGW32__)
|
|
||||||
#define UNDERSCORES
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __DJGPP__
|
|
||||||
#define UNDERSCORES
|
|
||||||
#define ALIGN_LOG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UNDERSCORES
|
|
||||||
#define _BF_body_r __BF_body_r
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ALIGN_LOG
|
|
||||||
#define DO_ALIGN(log) .align (log)
|
|
||||||
#elif defined(DUMBAS)
|
|
||||||
#define DO_ALIGN(log) .align 1 << log
|
|
||||||
#else
|
|
||||||
#define DO_ALIGN(log) .align (1 << (log))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BF_FRAME 0x200
|
|
||||||
#define ctx %esp
|
|
||||||
|
|
||||||
#define BF_ptr (ctx)
|
|
||||||
|
|
||||||
#define S(N, r) N+BF_FRAME(ctx,r,4)
|
|
||||||
#ifdef DUMBAS
|
|
||||||
#define P(N) 0x1000+N+N+N+N+BF_FRAME(ctx)
|
|
||||||
#else
|
|
||||||
#define P(N) 0x1000+4*N+BF_FRAME(ctx)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This version of the assembly code is optimized primarily for the original
|
|
||||||
* Intel Pentium but is also careful to avoid partial register stalls on the
|
|
||||||
* Pentium Pro family of processors (tested up to Pentium III Coppermine).
|
|
||||||
*
|
|
||||||
* It is possible to do 15% faster on the Pentium Pro family and probably on
|
|
||||||
* many non-Intel x86 processors, but, unfortunately, that would make things
|
|
||||||
* twice slower for the original Pentium.
|
|
||||||
*
|
|
||||||
* An additional 2% speedup may be achieved with non-reentrant code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define L %esi
|
|
||||||
#define R %edi
|
|
||||||
#define tmp1 %eax
|
|
||||||
#define tmp1_lo %al
|
|
||||||
#define tmp2 %ecx
|
|
||||||
#define tmp2_hi %ch
|
|
||||||
#define tmp3 %edx
|
|
||||||
#define tmp3_lo %dl
|
|
||||||
#define tmp4 %ebx
|
|
||||||
#define tmp4_hi %bh
|
|
||||||
#define tmp5 %ebp
|
|
||||||
|
|
||||||
.text
|
|
||||||
|
|
||||||
#define BF_ROUND(L, R, N) \
|
|
||||||
xorl L,tmp2; \
|
|
||||||
xorl tmp1,tmp1; \
|
|
||||||
movl tmp2,L; \
|
|
||||||
shrl $16,tmp2; \
|
|
||||||
movl L,tmp4; \
|
|
||||||
movb tmp2_hi,tmp1_lo; \
|
|
||||||
andl $0xFF,tmp2; \
|
|
||||||
movb tmp4_hi,tmp3_lo; \
|
|
||||||
andl $0xFF,tmp4; \
|
|
||||||
movl S(0,tmp1),tmp1; \
|
|
||||||
movl S(0x400,tmp2),tmp5; \
|
|
||||||
addl tmp5,tmp1; \
|
|
||||||
movl S(0x800,tmp3),tmp5; \
|
|
||||||
xorl tmp5,tmp1; \
|
|
||||||
movl S(0xC00,tmp4),tmp5; \
|
|
||||||
addl tmp1,tmp5; \
|
|
||||||
movl 4+P(N),tmp2; \
|
|
||||||
xorl tmp5,R
|
|
||||||
|
|
||||||
#define BF_ENCRYPT_START \
|
|
||||||
BF_ROUND(L, R, 0); \
|
|
||||||
BF_ROUND(R, L, 1); \
|
|
||||||
BF_ROUND(L, R, 2); \
|
|
||||||
BF_ROUND(R, L, 3); \
|
|
||||||
BF_ROUND(L, R, 4); \
|
|
||||||
BF_ROUND(R, L, 5); \
|
|
||||||
BF_ROUND(L, R, 6); \
|
|
||||||
BF_ROUND(R, L, 7); \
|
|
||||||
BF_ROUND(L, R, 8); \
|
|
||||||
BF_ROUND(R, L, 9); \
|
|
||||||
BF_ROUND(L, R, 10); \
|
|
||||||
BF_ROUND(R, L, 11); \
|
|
||||||
BF_ROUND(L, R, 12); \
|
|
||||||
BF_ROUND(R, L, 13); \
|
|
||||||
BF_ROUND(L, R, 14); \
|
|
||||||
BF_ROUND(R, L, 15); \
|
|
||||||
movl BF_ptr,tmp5; \
|
|
||||||
xorl L,tmp2; \
|
|
||||||
movl P(17),L
|
|
||||||
|
|
||||||
#define BF_ENCRYPT_END \
|
|
||||||
xorl R,L; \
|
|
||||||
movl tmp2,R
|
|
||||||
|
|
||||||
DO_ALIGN(5)
|
|
||||||
.globl _BF_body_r
|
|
||||||
_BF_body_r:
|
|
||||||
movl 4(%esp),%eax
|
|
||||||
pushl %ebp
|
|
||||||
pushl %ebx
|
|
||||||
pushl %esi
|
|
||||||
pushl %edi
|
|
||||||
subl $BF_FRAME-8,%eax
|
|
||||||
xorl L,L
|
|
||||||
cmpl %esp,%eax
|
|
||||||
ja BF_die
|
|
||||||
xchgl %eax,%esp
|
|
||||||
xorl R,R
|
|
||||||
pushl %eax
|
|
||||||
leal 0x1000+BF_FRAME-4(ctx),%eax
|
|
||||||
movl 0x1000+BF_FRAME-4(ctx),tmp2
|
|
||||||
pushl %eax
|
|
||||||
xorl tmp3,tmp3
|
|
||||||
BF_loop_P:
|
|
||||||
BF_ENCRYPT_START
|
|
||||||
addl $8,tmp5
|
|
||||||
BF_ENCRYPT_END
|
|
||||||
leal 0x1000+18*4+BF_FRAME(ctx),tmp1
|
|
||||||
movl tmp5,BF_ptr
|
|
||||||
cmpl tmp5,tmp1
|
|
||||||
movl L,-8(tmp5)
|
|
||||||
movl R,-4(tmp5)
|
|
||||||
movl P(0),tmp2
|
|
||||||
ja BF_loop_P
|
|
||||||
leal BF_FRAME(ctx),tmp5
|
|
||||||
xorl tmp3,tmp3
|
|
||||||
movl tmp5,BF_ptr
|
|
||||||
BF_loop_S:
|
|
||||||
BF_ENCRYPT_START
|
|
||||||
BF_ENCRYPT_END
|
|
||||||
movl P(0),tmp2
|
|
||||||
movl L,(tmp5)
|
|
||||||
movl R,4(tmp5)
|
|
||||||
BF_ENCRYPT_START
|
|
||||||
BF_ENCRYPT_END
|
|
||||||
movl P(0),tmp2
|
|
||||||
movl L,8(tmp5)
|
|
||||||
movl R,12(tmp5)
|
|
||||||
BF_ENCRYPT_START
|
|
||||||
BF_ENCRYPT_END
|
|
||||||
movl P(0),tmp2
|
|
||||||
movl L,16(tmp5)
|
|
||||||
movl R,20(tmp5)
|
|
||||||
BF_ENCRYPT_START
|
|
||||||
addl $32,tmp5
|
|
||||||
BF_ENCRYPT_END
|
|
||||||
leal 0x1000+BF_FRAME(ctx),tmp1
|
|
||||||
movl tmp5,BF_ptr
|
|
||||||
cmpl tmp5,tmp1
|
|
||||||
movl P(0),tmp2
|
|
||||||
movl L,-8(tmp5)
|
|
||||||
movl R,-4(tmp5)
|
|
||||||
ja BF_loop_S
|
|
||||||
movl 4(%esp),%esp
|
|
||||||
popl %edi
|
|
||||||
popl %esi
|
|
||||||
popl %ebx
|
|
||||||
popl %ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
BF_die:
|
|
||||||
/* Oops, need to re-compile with a larger BF_FRAME. */
|
|
||||||
hlt
|
|
||||||
jmp BF_die
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__ELF__) && defined(__linux__)
|
|
||||||
.section .note.GNU-stack,"",@progbits
|
|
||||||
#endif
|
|
||||||
@@ -2,3 +2,4 @@ bcrypt passwords
|
|||||||
session management using proper random tokens
|
session management using proper random tokens
|
||||||
CSRF protection
|
CSRF protection
|
||||||
input validation to avoid XSS and injection
|
input validation to avoid XSS and injection
|
||||||
|
only allow signup, login ecc over HTTPS
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE IF NOT EXISTS Users (
|
CREATE TABLE IF NOT EXISTS Users (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username TEXT NOT NULL UNIQUE,
|
||||||
password TEXT NOT NULL,
|
hash TEXT NOT NULL,
|
||||||
email TEXT NOT NULL UNIQUE,
|
email TEXT NOT NULL UNIQUE,
|
||||||
signup_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
signup_time DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <crypt_blowfish.h>
|
||||||
|
#include "bcrypt.h"
|
||||||
|
|
||||||
|
int hash_password(char *pass, int passlen, int cost, PasswordHash *hash)
|
||||||
|
{
|
||||||
|
char passzt[128];
|
||||||
|
if (passlen >= (int) sizeof(passzt))
|
||||||
|
return -1;
|
||||||
|
memcpy(passzt, pass, passlen);
|
||||||
|
passzt[passlen] = '\0';
|
||||||
|
|
||||||
|
unsigned char random[16] = {
|
||||||
|
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, // TODO
|
||||||
|
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||||
|
};
|
||||||
|
|
||||||
|
char salt[30];
|
||||||
|
if (_crypt_gensalt_blowfish_rn("$2b$", cost, (char*) random, sizeof(random), salt, sizeof(salt)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (_crypt_blowfish_rn(passzt, salt, hash->data, (int) sizeof(hash->data)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_password(char *pass, int passlen, PasswordHash hash)
|
||||||
|
{
|
||||||
|
char passzt[128];
|
||||||
|
if (passlen >= (int) sizeof(passzt))
|
||||||
|
return -1;
|
||||||
|
memcpy(passzt, pass, passlen);
|
||||||
|
passzt[passlen] = '\0';
|
||||||
|
|
||||||
|
PasswordHash new_hash;
|
||||||
|
if (_crypt_blowfish_rn(passzt, hash.data, new_hash.data, sizeof(new_hash.data)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(hash.data, new_hash.data)) // TODO: should be constant-time
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef BCRYPT_INCLUDED
|
||||||
|
#define BCRYPT_INCLUDED
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char data[61];
|
||||||
|
} PasswordHash;
|
||||||
|
|
||||||
|
int hash_password(char *pass, int passlen, int cost, PasswordHash *hash);
|
||||||
|
int check_password(char *pass, int passlen, PasswordHash hash);
|
||||||
|
|
||||||
|
#endif // BCRYPT_INCLUDED
|
||||||
+33
-4
@@ -4,8 +4,9 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "sqlite3.h"
|
|
||||||
#include "chttp.h"
|
#include "chttp.h"
|
||||||
|
#include "bcrypt.h"
|
||||||
|
#include "sqlite3.h"
|
||||||
#include "sqlite3utils.h"
|
#include "sqlite3utils.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
@@ -45,9 +46,13 @@ int load_file(char *file, char **data, long *size)
|
|||||||
|
|
||||||
int create_user(SQLiteCache *dbcache, HTTP_String name, HTTP_String email, HTTP_String pass)
|
int create_user(SQLiteCache *dbcache, HTTP_String name, HTTP_String email, HTTP_String pass)
|
||||||
{
|
{
|
||||||
|
PasswordHash hash;
|
||||||
|
int ret = hash_password(pass.ptr, pass.len, 12, &hash);
|
||||||
|
if (ret) return -500;
|
||||||
|
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int ret = sqlite3utils_prepare_and_bind(dbcache, &stmt,
|
ret = sqlite3utils_prepare_and_bind(dbcache, &stmt,
|
||||||
"INSERT INTO Users(username, email, password) VALUES (?, ?, ?)", name, email, pass);
|
"INSERT INTO Users(username, email, hash) VALUES (?, ?, ?)", name, email, ((HTTP_String) { hash.data, strlen(hash.data) }));
|
||||||
if (ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
return -500;
|
return -500;
|
||||||
|
|
||||||
@@ -80,7 +85,7 @@ int user_exists(SQLiteCache *dbcache, HTTP_String name, HTTP_String pass)
|
|||||||
{
|
{
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int ret = sqlite3utils_prepare_and_bind(dbcache, &stmt,
|
int ret = sqlite3utils_prepare_and_bind(dbcache, &stmt,
|
||||||
"SELECT id FROM Users WHERE username=? AND password=?", name, pass);
|
"SELECT id, hash FROM Users WHERE username=?", name);
|
||||||
if (ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
return -500;
|
return -500;
|
||||||
|
|
||||||
@@ -100,6 +105,30 @@ int user_exists(SQLiteCache *dbcache, HTTP_String name, HTTP_String pass)
|
|||||||
return -500;
|
return -500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *rawhash = (const char*) sqlite3_column_text(stmt, 1);
|
||||||
|
if (rawhash == NULL) {
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
return -500;
|
||||||
|
}
|
||||||
|
int rawhashlen = sqlite3_column_bytes(stmt, 1);
|
||||||
|
|
||||||
|
PasswordHash hash;
|
||||||
|
if (rawhashlen >= sizeof(hash.data)) {
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
return -500;
|
||||||
|
}
|
||||||
|
strcpy(hash.data, rawhash);
|
||||||
|
|
||||||
|
ret = check_password(pass.ptr, pass.len, hash);
|
||||||
|
if (ret < 0) {
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
return -500;
|
||||||
|
}
|
||||||
|
if (ret > 0) {
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
return -400;
|
||||||
|
}
|
||||||
|
|
||||||
ret = sqlite3_reset(stmt);
|
ret = sqlite3_reset(stmt);
|
||||||
if (ret != SQLITE_OK)
|
if (ret != SQLITE_OK)
|
||||||
return -500;
|
return -500;
|
||||||
|
|||||||
+2
-2
@@ -83,7 +83,7 @@ static int lookup(SQLiteCache *cache, char *fmt, int fmtlen)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, const char *fmt, int fmtlen)
|
int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, char *fmt, int fmtlen)
|
||||||
{
|
{
|
||||||
if (fmtlen < 0)
|
if (fmtlen < 0)
|
||||||
fmtlen = strlen(fmt);
|
fmtlen = strlen(fmt);
|
||||||
@@ -118,7 +118,7 @@ int sqlite3utils_prepare(SQLiteCache *cache, sqlite3_stmt **pstmt, const char *f
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
||||||
sqlite3_stmt **pstmt, const char *fmt, VArgs args)
|
sqlite3_stmt **pstmt, char *fmt, VArgs args)
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int ret = sqlite3utils_prepare(cache, &stmt, fmt, strlen(fmt));
|
int ret = sqlite3utils_prepare(cache, &stmt, fmt, strlen(fmt));
|
||||||
|
|||||||
+2
-2
@@ -13,9 +13,9 @@ void sqlite_cache_free(SQLiteCache *cache);
|
|||||||
sqlite3* sqlite_cache_getdb(SQLiteCache *cache);
|
sqlite3* sqlite_cache_getdb(SQLiteCache *cache);
|
||||||
|
|
||||||
int sqlite3utils_prepare(SQLiteCache *cache,
|
int sqlite3utils_prepare(SQLiteCache *cache,
|
||||||
sqlite3_stmt **pstmt, const char *fmt, int fmtlen);
|
sqlite3_stmt **pstmt, char *fmt, int fmtlen);
|
||||||
|
|
||||||
int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
int sqlite3utils_prepare_and_bind_impl(SQLiteCache *cache,
|
||||||
sqlite3_stmt **pstmt, const char *fmt, VArgs args);
|
sqlite3_stmt **pstmt, char *fmt, VArgs args);
|
||||||
|
|
||||||
#endif // SQLITE3UTILS_INCLUDED
|
#endif // SQLITE3UTILS_INCLUDED
|
||||||
Reference in New Issue
Block a user