2016-01-12 23:52:30 +01:00
|
|
|
#include <platform.h>
|
|
|
|
#include "password.h"
|
|
|
|
|
2016-01-13 14:41:09 +01:00
|
|
|
#include <md5.h>
|
2016-01-14 16:50:42 +01:00
|
|
|
#include <mtrand.h>
|
2016-01-13 14:41:09 +01:00
|
|
|
|
2016-01-12 23:52:30 +01:00
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2016-01-13 14:41:09 +01:00
|
|
|
#define MAXSALTLEN 32 // maximum length in characters of any salt
|
2016-01-14 16:50:42 +01:00
|
|
|
#define SALTLEN 8 // length of salts we generate
|
|
|
|
|
|
|
|
/* Table with characters for base64 transformation. */
|
|
|
|
static const char b64t[65] =
|
|
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
|
|
#define b64_from_24bit(B2, B1, B0, N) \
|
|
|
|
do { \
|
|
|
|
unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
|
|
|
|
int n = (N); \
|
|
|
|
while (n-- > 0 && buflen > 0) \
|
|
|
|
{ \
|
|
|
|
*cp++ = b64t[w & 0x3f]; \
|
|
|
|
--buflen; \
|
|
|
|
w >>= 6; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
char *password_gensalt(void) {
|
|
|
|
static char salt[SALTLEN + 1];
|
|
|
|
char *cp = salt;
|
|
|
|
int buflen = SALTLEN;
|
|
|
|
while (buflen) {
|
|
|
|
unsigned long ul = genrand_int32();
|
2016-01-14 17:28:20 +01:00
|
|
|
b64_from_24bit((char)(ul & 0xFF), (char)((ul>>8)&0xff), (char)((ul>>16)&0xFF), 4);
|
2016-01-14 16:50:42 +01:00
|
|
|
}
|
|
|
|
salt[SALTLEN] = 0;
|
|
|
|
return salt;
|
|
|
|
}
|
2016-01-13 14:41:09 +01:00
|
|
|
|
2016-01-13 16:16:02 +01:00
|
|
|
static const char * password_hash_i(const char * passwd, const char *salt, int algo, char *result, size_t len) {
|
2016-01-12 23:52:30 +01:00
|
|
|
assert(passwd);
|
2016-01-14 16:50:42 +01:00
|
|
|
if (!salt) {
|
|
|
|
salt = password_gensalt();
|
|
|
|
}
|
2016-01-12 23:52:30 +01:00
|
|
|
if (algo==PASSWORD_PLAIN) {
|
2016-01-13 16:16:02 +01:00
|
|
|
_snprintf(result, len, "$0$%s$%s", salt, passwd);
|
2016-01-12 23:52:30 +01:00
|
|
|
}
|
2016-01-13 14:41:09 +01:00
|
|
|
else if (algo == PASSWORD_MD5) {
|
2016-01-14 15:49:09 +01:00
|
|
|
char * result = md5_crypt(passwd, salt);
|
|
|
|
return result;
|
2016-01-13 14:41:09 +01:00
|
|
|
}
|
2016-01-12 23:52:30 +01:00
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-01-14 15:49:09 +01:00
|
|
|
const char * password_hash(const char * passwd, const char * salt, int algo) {
|
2016-01-13 16:16:02 +01:00
|
|
|
static char result[64]; // TODO: static result buffers are bad mojo!
|
|
|
|
if (algo < 0) algo = PASSWORD_DEFAULT;
|
2016-01-14 15:49:09 +01:00
|
|
|
return password_hash_i(passwd, salt, algo, result, sizeof(result));
|
2016-01-12 23:52:30 +01:00
|
|
|
}
|
|
|
|
|
2016-01-13 14:41:09 +01:00
|
|
|
static bool password_is_implemented(int algo) {
|
2016-01-13 16:16:02 +01:00
|
|
|
return algo==PASSWORD_PLAIN || algo==PASSWORD_MD5;
|
2016-01-13 14:41:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int password_verify(const char * pwhash, const char * passwd) {
|
|
|
|
char salt[MAXSALTLEN+1];
|
2016-01-13 16:16:02 +01:00
|
|
|
char hash[64];
|
2016-01-13 14:41:09 +01:00
|
|
|
size_t len;
|
|
|
|
int algo;
|
|
|
|
char *pos;
|
2016-01-14 15:49:09 +01:00
|
|
|
const char *dol, *result;
|
2016-01-12 23:52:30 +01:00
|
|
|
assert(passwd);
|
2016-01-14 15:49:09 +01:00
|
|
|
assert(pwhash);
|
2016-01-13 14:41:09 +01:00
|
|
|
assert(pwhash[0] == '$');
|
2016-01-13 16:16:02 +01:00
|
|
|
algo = pwhash[1] - '0';
|
|
|
|
pos = strchr(pwhash+2, '$');
|
2016-01-13 14:41:09 +01:00
|
|
|
assert(pos[0] == '$');
|
|
|
|
++pos;
|
|
|
|
dol = strchr(pos, '$');
|
|
|
|
assert(dol>pos && dol[0] == '$');
|
|
|
|
len = dol - pos;
|
|
|
|
assert(len <= MAXSALTLEN);
|
|
|
|
strncpy(salt, pos, len);
|
|
|
|
salt[len] = 0;
|
2016-01-14 15:49:09 +01:00
|
|
|
result = password_hash_i(passwd, salt, algo, hash, sizeof(hash));
|
2016-01-13 14:41:09 +01:00
|
|
|
if (!password_is_implemented(algo)) {
|
|
|
|
return VERIFY_UNKNOWN;
|
|
|
|
}
|
2016-01-14 15:49:09 +01:00
|
|
|
if (strcmp(pwhash, result) == 0) {
|
2016-01-13 14:41:09 +01:00
|
|
|
return VERIFY_OK;
|
|
|
|
}
|
|
|
|
return VERIFY_FAIL;
|
2016-01-12 23:52:30 +01:00
|
|
|
}
|