💾 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

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

bcrypt

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