💾 Archived View for gmi.noulin.net › gitRepositories › bcrypt › file › wrapper.c.gmi captured on 2023-07-10 at 18:01:01. 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

wrapper.c (11373B)

     1 /*
     2  * Written by Solar Designer <solar at openwall.com> in 2000-2014.
     3  * No copyright is claimed, and the software is hereby placed in the public
     4  * domain.  In case this attempt to disclaim copyright and place the software
     5  * in the public domain is deemed null and void, then the software is
     6  * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
     7  * general public under the following terms:
     8  *
     9  * Redistribution and use in source and binary forms, with or without
    10  * modification, are permitted.
    11  *
    12  * There's ABSOLUTELY NO WARRANTY, express or implied.
    13  *
    14  * See crypt_blowfish.c for more information.
    15  */
    16 
    17 #include <stdlib.h>
    18 #include <string.h>
    19 
    20 #include <errno.h>
    21 #ifndef __set_errno
    22 #define __set_errno(val) errno = (val)
    23 #endif
    24 
    25 #ifdef TEST
    26 #include <stdio.h>
    27 #include <unistd.h>
    28 #include <signal.h>
    29 #include <time.h>
    30 #include <sys/time.h>
    31 #include <sys/times.h>
    32 #ifdef TEST_THREADS
    33 #include <pthread.h>
    34 #endif
    35 #endif
    36 
    37 #define CRYPT_OUTPUT_SIZE                (7 + 22 + 31 + 1)
    38 #define CRYPT_GENSALT_OUTPUT_SIZE        (7 + 22 + 1)
    39 
    40 #include "crypt_blowfish.h"
    41 
    42 static int _crypt_data_alloc(void **data, int *size, int need)
    43 {
    44         void *updated;
    45 
    46         if (*data && *size >= need) return 0;
    47 
    48         updated = realloc(*data, need);
    49 
    50         if (!updated) {
    51                 return -1;
    52         }
    53 
    54         *data = updated;
    55         *size = need;
    56 
    57         return 0;
    58 }
    59 
    60 static char *_crypt_retval_magic(char *retval, const char *setting,
    61         char *output, int size)
    62 {
    63         if (retval)
    64                 return retval;
    65 
    66         if (_crypt_output_magic(setting, output, size))
    67                 return NULL; /* shouldn't happen */
    68 
    69         return output;
    70 }
    71 
    72 char *crypt_rn(const char *key, const char *setting, void *data, int size)
    73 {
    74         return _crypt_blowfish_rn(key, setting, (char *)data, size);
    75 }
    76 
    77 char *crypt_ra(const char *key, const char *setting,
    78         void **data, int *size)
    79 {
    80         if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
    81                 return NULL;
    82         return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
    83 }
    84 
    85 char *crypt_r(const char *key, const char *setting, void *data)
    86 {
    87         return _crypt_retval_magic(
    88                 crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
    89                 setting, (char *)data, CRYPT_OUTPUT_SIZE);
    90 }
    91 
    92 char *crypt(const char *key, const char *setting)
    93 {
    94         static char output[CRYPT_OUTPUT_SIZE];
    95 
    96         return _crypt_retval_magic(
    97                 crypt_rn(key, setting, output, sizeof(output)),
    98                 setting, output, sizeof(output));
    99 }
   100 
   101 char *crypt_gensalt_rn(const char *prefix, unsigned long count,
   102         const char *input, int size, char *output, int output_size)
   103 {
   104         char *(*use)(const char *_prefix, unsigned long _count,
   105                 const char *_input, int _size,
   106                 char *_output, int _output_size);
   107 
   108         /* This may be supported on some platforms in the future */
   109         if (!input) {
   110                 __set_errno(EINVAL);
   111                 return NULL;
   112         }
   113 
   114         if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
   115             !strncmp(prefix, "$2y$", 4))
   116                 use = _crypt_gensalt_blowfish_rn;
   117         else {
   118                 __set_errno(EINVAL);
   119                 return NULL;
   120         }
   121 
   122         return use(prefix, count, input, size, output, output_size);
   123 }
   124 
   125 char *crypt_gensalt_ra(const char *prefix, unsigned long count,
   126         const char *input, int size)
   127 {
   128         char output[CRYPT_GENSALT_OUTPUT_SIZE];
   129         char *retval;
   130 
   131         retval = crypt_gensalt_rn(prefix, count,
   132                 input, size, output, sizeof(output));
   133 
   134         if (retval) {
   135                 retval = strdup(retval);
   136         }
   137 
   138         return retval;
   139 }
   140 
   141 char *crypt_gensalt(const char *prefix, unsigned long count,
   142         const char *input, int size)
   143 {
   144         static char output[CRYPT_GENSALT_OUTPUT_SIZE];
   145 
   146         return crypt_gensalt_rn(prefix, count,
   147                 input, size, output, sizeof(output));
   148 }
   149 
   150 #ifdef TEST
   151 static const char *tests[][3] = {
   152         {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
   153                 "U*U"},
   154         {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
   155                 "U*U*"},
   156         {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
   157                 "U*U*U"},
   158         {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
   159                 "0123456789abcdefghijklmnopqrstuvwxyz"
   160                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
   161                 "chars after 72 are ignored"},
   162         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
   163                 "\xa3"},
   164         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
   165                 "\xff\xff\xa3"},
   166         {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
   167                 "\xff\xff\xa3"},
   168         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
   169                 "\xff\xff\xa3"},
   170         {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
   171                 "\xff\xff\xa3"},
   172         {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
   173                 "\xa3"},
   174         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
   175                 "\xa3"},
   176         {"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
   177                 "\xa3"},
   178         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
   179                 "1\xa3" "345"},
   180         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
   181                 "\xff\xa3" "345"},
   182         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
   183                 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
   184         {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
   185                 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
   186         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
   187                 "\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
   188         {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
   189                 "\xff\xa3" "345"},
   190         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
   191                 "\xff\xa3" "345"},
   192         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
   193                 "\xa3" "ab"},
   194         {"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
   195                 "\xa3" "ab"},
   196         {"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
   197                 "\xa3" "ab"},
   198         {"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
   199                 "\xd1\x91"},
   200         {"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
   201                 "\xd0\xc1\xd2\xcf\xcc\xd8"},
   202         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
   203                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   204                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   205                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   206                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   207                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   208                 "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
   209                 "chars after 72 are ignored as usual"},
   210         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
   211                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
   212                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
   213                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
   214                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
   215                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
   216                 "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
   217         {"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
   218                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
   219                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
   220                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
   221                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
   222                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
   223                 "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
   224         {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
   225                 ""},
   226         {"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
   227         {"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
   228         {"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
   229         {"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
   230         {"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
   231         {"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
   232         {"*1", "", "*0"},
   233         {NULL}
   234 };
   235 
   236 #define which                                tests[0]
   237 
   238 static volatile sig_atomic_t running;
   239 
   240 static void handle_timer(int signum)
   241 {
   242         (void) signum;
   243         running = 0;
   244 }
   245 
   246 static void *run(void *arg)
   247 {
   248         unsigned long count = 0;
   249         int i = 0;
   250         void *data = NULL;
   251         int size = 0x12345678;
   252 
   253         do {
   254                 const char *hash = tests[i][0];
   255                 const char *key = tests[i][1];
   256                 const char *setting = tests[i][2];
   257 
   258                 if (!tests[++i][0])
   259                         i = 0;
   260 
   261                 if (setting && strlen(hash) < 30) /* not for benchmark */
   262                         continue;
   263 
   264                 if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
   265                         printf("%d: FAILED (crypt_ra/%d/%lu)\n",
   266                                 (int)((char *)arg - (char *)0), i, count);
   267                         free(data);
   268                         return NULL;
   269                 }
   270                 count++;
   271         } while (running);
   272 
   273         free(data);
   274         return count + (char *)0;
   275 }
   276 
   277 int main(void)
   278 {
   279         struct itimerval it;
   280         struct tms buf;
   281         clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
   282         unsigned long count;
   283         void *data;
   284         int size;
   285         char *setting1, *setting2;
   286         int i;
   287 #ifdef TEST_THREADS
   288         pthread_t t[TEST_THREADS];
   289         void *t_retval;
   290 #endif
   291 
   292         data = NULL;
   293         size = 0x12345678;
   294 
   295         for (i = 0; tests[i][0]; i++) {
   296                 const char *hash = tests[i][0];
   297                 const char *key = tests[i][1];
   298                 const char *setting = tests[i][2];
   299                 const char *p;
   300                 int ok = !setting || strlen(hash) >= 30;
   301                 int o_size;
   302                 char s_buf[30], o_buf[61];
   303                 if (!setting) {
   304                         memcpy(s_buf, hash, sizeof(s_buf) - 1);
   305                         s_buf[sizeof(s_buf) - 1] = 0;
   306                         setting = s_buf;
   307                 }
   308 
   309                 __set_errno(0);
   310                 p = crypt(key, setting);
   311                 if ((!ok && !errno) || strcmp(p, hash)) {
   312                         printf("FAILED (crypt/%d)\n", i);
   313                         return 1;
   314                 }
   315 
   316                 if (ok && strcmp(crypt(key, hash), hash)) {
   317                         printf("FAILED (crypt/%d)\n", i);
   318                         return 1;
   319                 }
   320 
   321                 for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
   322                         int ok_n = ok && o_size == (int)sizeof(o_buf);
   323                         const char *x = "abc";
   324                         strcpy(o_buf, x);
   325                         if (o_size >= 3) {
   326                                 x = "*0";
   327                                 if (setting[0] == '*' && setting[1] == '0')
   328                                         x = "*1";
   329                         }
   330                         __set_errno(0);
   331                         p = crypt_rn(key, setting, o_buf, o_size);
   332                         if ((ok_n && (!p || strcmp(p, hash))) ||
   333                             (!ok_n && (!errno || p || strcmp(o_buf, x)))) {
   334                                 printf("FAILED (crypt_rn/%d)\n", i);
   335                                 return 1;
   336                         }
   337                 }
   338 
   339                 __set_errno(0);
   340                 p = crypt_ra(key, setting, &data, &size);
   341                 if ((ok && (!p || strcmp(p, hash))) ||
   342                     (!ok && (!errno || p || strcmp((char *)data, hash)))) {
   343                         printf("FAILED (crypt_ra/%d)\n", i);
   344                         return 1;
   345                 }
   346         }
   347 
   348         setting1 = crypt_gensalt(which[0], 12, data, size);
   349         if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
   350                 puts("FAILED (crypt_gensalt)\n");
   351                 return 1;
   352         }
   353 
   354         setting2 = crypt_gensalt_ra(setting1, 12, data, size);
   355         if (strcmp(setting1, setting2)) {
   356                 puts("FAILED (crypt_gensalt_ra/1)\n");
   357                 return 1;
   358         }
   359 
   360         (*(char *)data)++;
   361         setting1 = crypt_gensalt_ra(setting2, 12, data, size);
   362         if (!strcmp(setting1, setting2)) {
   363                 puts("FAILED (crypt_gensalt_ra/2)\n");
   364                 return 1;
   365         }
   366 
   367         free(setting1);
   368         free(setting2);
   369         free(data);
   370 
   371 #if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
   372         clk_tck = sysconf(_SC_CLK_TCK);
   373 #else
   374         clk_tck = CLK_TCK;
   375 #endif
   376 
   377         running = 1;
   378         signal(SIGALRM, handle_timer);
   379 
   380         memset(&it, 0, sizeof(it));
   381         it.it_value.tv_sec = 5;
   382         setitimer(ITIMER_REAL, &it, NULL);
   383 
   384         start_real = times(&buf);
   385         start_virtual = buf.tms_utime + buf.tms_stime;
   386 
   387         count = (char *)run((char *)0) - (char *)0;
   388 
   389         end_real = times(&buf);
   390         end_virtual = buf.tms_utime + buf.tms_stime;
   391         if (end_virtual == start_virtual) end_virtual++;
   392 
   393         printf("%.1f c/s real, %.1f c/s virtual\n",
   394                 (float)count * clk_tck / (end_real - start_real),
   395                 (float)count * clk_tck / (end_virtual - start_virtual));
   396 
   397 #ifdef TEST_THREADS
   398         running = 1;
   399         it.it_value.tv_sec = 60;
   400         setitimer(ITIMER_REAL, &it, NULL);
   401         start_real = times(&buf);
   402 
   403         for (i = 0; i < TEST_THREADS; i++)
   404         if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
   405                 perror("pthread_create");
   406                 return 1;
   407         }
   408 
   409         for (i = 0; i < TEST_THREADS; i++) {
   410                 if (pthread_join(t[i], &t_retval)) {
   411                         perror("pthread_join");
   412                         continue;
   413                 }
   414                 if (!t_retval) continue;
   415                 count = (char *)t_retval - (char *)0;
   416                 end_real = times(&buf);
   417                 printf("%d: %.1f c/s real\n", i,
   418                         (float)count * clk_tck / (end_real - start_real));
   419         }
   420 #endif
   421 
   422         return 0;
   423 }
   424 #endif