💾 Archived View for gmi.noulin.net › gitRepositories › bcrypt › file › bcrypt.c.gmi captured on 2024-09-29 at 00:24:12. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
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