bcrypt

bcrypt with a threadpool
git clone https://noulin.net/git/bcrypt.git
Log | Files | Refs | README | LICENSE

bcrypt.c (4893B)


      1 /*
      2  * bcrypt wrapper library
      3  *
      4  * Written by Remy.
      5  * No copyright is claimed, and the software is hereby placed in the public
      6  * domain.  In case this attempt to disclaim copyright and place the software
      7  * in the public domain is deemed null and void, then the software is
      8  * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
      9  * general public under the following terms:
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted.
     13  *
     14  * There's ABSOLUTELY NO WARRANTY, express or implied.
     15  *
     16  * Original code: https://github.com/rg3/bcrypt
     17  */
     18 
     19 #include <string.h>
     20 #include <sys/types.h>
     21 #include <sys/stat.h>
     22 #include <fcntl.h>
     23 #include <unistd.h>
     24 #include <errno.h>
     25 
     26 #include "libsheepyObject.h"
     27 #include "bcrypt.h"
     28 #include "wrapper.h"
     29 
     30 
     31 #define RANDBYTES (16)
     32 
     33 internal int try_close(int fd)
     34 {
     35 	int r;
     36 	for (;;) {
     37 		errno = 0;
     38 		r = close(fd);
     39 		if (r == -1 && errno == EINTR)
     40 			continue;
     41 		break;
     42 	}
     43 	return r;
     44 }
     45 
     46 internal int try_read(int fd, char *out, size_t count)
     47 {
     48 	size_t total;
     49 	ssize_t partial;
     50 
     51 	total = 0;
     52 	while (total < count)
     53 	{
     54 		for (;;) {
     55 			errno = 0;
     56 			partial = read(fd, out + total, count - total);
     57 			if (partial == -1 && errno == EINTR)
     58 				continue;
     59 			break;
     60 		}
     61 
     62 		if (partial < 1)
     63 			return -1;
     64 
     65 		total += partial;
     66 	}
     67 
     68 	return 0;
     69 }
     70 
     71 /*
     72  * This is a best effort implementation. Nothing prevents a compiler from
     73  * optimizing this function and making it vulnerable to timing attacks, but
     74  * this method is commonly used in crypto libraries like NaCl.
     75  *
     76  * Return value is nonzero if both strings are equal and zero otherwise.
     77 */
     78 internal int timing_safe_strcmp(const char *str1, const char *str2)
     79 {
     80 	const unsigned char *u1;
     81 	const unsigned char *u2;
     82 	int r;
     83 	int i;
     84 
     85 	int len1 = strlen(str1);
     86 	int len2 = strlen(str2);
     87 
     88 	/* In our context both strings should always have the same length
     89 	 * because they will be hashed passwords. */
     90 	if (len1 != len2)
     91 		return 1;
     92 
     93 	/* Force unsigned for bitwise operations. */
     94 	u1 = (const unsigned char *)str1;
     95 	u2 = (const unsigned char *)str2;
     96 
     97 	r = 0;
     98 	for (i = 0; i < len1; ++i)
     99 		r |= (u1[i] ^ u2[i]);
    100 
    101 	return !r;
    102 }
    103 
    104 
    105 int bcryptGensaltSync(int workfactor, char salt[BCRYPT_HASHSIZE])
    106 {
    107 	int fd;
    108 	char input[RANDBYTES];
    109 	int workf;
    110 	char *aux;
    111 
    112 	fd = open("/dev/urandom", O_RDONLY);
    113 	if (fd == -1) {
    114 		u64 *in = (u64*) input;
    115 		*(in++) = randomWordFromHW();
    116 		*(in++) = randomWordFromHW();
    117 		goto gensalt;
    118 	}
    119 
    120 	if (try_read(fd, input, RANDBYTES) != 0) {
    121 		if (try_close(fd) != 0)
    122 			return 4;
    123 		return 2;
    124 	}
    125 
    126 	if (try_close(fd) != 0)
    127 		return 3;
    128 
    129 	/* Generate salt. */
    130 	gensalt:
    131 	workf = (workfactor < 4 || workfactor > 31)?12:workfactor;
    132 	aux = crypt_gensalt_rn("$2b$", workf, input, RANDBYTES,
    133 			       salt, BCRYPT_HASHSIZE);
    134 	return (aux == NULL)?0:1;
    135 }
    136 
    137 int bcryptHashSync(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE])
    138 {
    139 	char *aux;
    140 	aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
    141 	return (aux == NULL)?0:1;
    142 }
    143 
    144 int bcryptCheckSync(const char *passwd, const char hash[BCRYPT_HASHSIZE])
    145 {
    146 	int r;
    147 	char outhash[BCRYPT_HASHSIZE];
    148 
    149 	r = bcryptHashSync(passwd, hash, outhash);
    150 	if (!r)
    151 		return 0;
    152 
    153 	return timing_safe_strcmp(hash, outhash);
    154 }
    155 
    156 typedef struct {
    157 	const char *passwd;
    158 	u8 saltRounds;
    159 	bcryptHashCallbackt callback;
    160 	void *callbackEnv;
    161 } bcryptHashArgs;
    162 
    163 internal void hash(void *AG) {
    164 
    165 	cast(bcryptHashArgs *, args, AG);
    166 
    167 	char salt[BCRYPT_HASHSIZE];
    168 	char hash[BCRYPT_HASHSIZE];
    169 	int r;
    170 
    171 	r = bcryptGensaltSync(args->saltRounds, salt);
    172 	r = bcryptHashSync(args->passwd, salt, hash);
    173 
    174 	args->callback(r, hash, args->callbackEnv);
    175 	free(AG);
    176 }
    177 
    178 int bcryptHash(const char *passwd, u8 saltRounds, bcryptHashCallbackt callback, void *callbackEnv) {
    179 
    180 	int r = 0;
    181 	bcryptHashArgs *args;
    182 
    183 	if (!callback || !passwd) return 0;
    184 
    185 	args = malloc(sizeof(bcryptHashArgs));
    186 
    187 	args->passwd      = passwd;
    188 	args->saltRounds  = saltRounds;
    189 	args->callback    = callback;
    190 	args->callbackEnv = callbackEnv;
    191 
    192 	tpoolAdd(hash, args);
    193 
    194 	return r;
    195 }
    196 
    197 typedef struct {
    198 	const char *passwd;
    199 	char *hash;
    200 	bcryptCheckCallbackt callback;
    201 	void *callbackEnv;
    202 } bcryptCheckArgs;
    203 
    204 internal void check(void *AG) {
    205 
    206 	cast(bcryptCheckArgs *, args, AG);
    207 
    208 	int r;
    209 
    210 	r = bcryptCheckSync(args->passwd, args->hash);
    211 
    212 	args->callback(0, r, args->callbackEnv);
    213 	free(args->hash);
    214 	free(AG);
    215 }
    216 
    217 
    218 int bcryptCheck(const char *passwd, char hash[BCRYPT_HASHSIZE], bcryptCheckCallbackt callback, void *callbackEnv) {
    219 
    220 	int r = 0;
    221 	bcryptCheckArgs *args;
    222 
    223 	if (!callback || !passwd) return 0;
    224 
    225 	args = malloc(sizeof(bcryptCheckArgs));
    226 
    227 	args->passwd      = passwd;
    228 	args->hash        = strdup(hash);
    229 	args->callback    = callback;
    230 	args->callbackEnv = callbackEnv;
    231 
    232 	tpoolAdd(check, args);
    233 
    234 	return r;
    235 }
    236 
    237 bool checkLibsheepyVersionBcrypt(const char *currentLibsheepyVersion) {
    238   return eqG(currentLibsheepyVersion, LIBSHEEPY_VERSION);
    239 }
    240