bcrypt.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * bcrypt wrapper library
  3. *
  4. * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
  5. *
  6. * To the extent possible under law, the author(s) have dedicated all copyright
  7. * and related and neighboring rights to this software to the public domain
  8. * worldwide. This software is distributed without any warranty.
  9. *
  10. * You should have received a copy of the CC0 Public Domain Dedication along
  11. * with this software. If not, see
  12. * <http://creativecommons.org/publicdomain/zero/1.0/>.
  13. */
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <errno.h>
  20. #include "bcrypt.h"
  21. #include "crypt_blowfish/ow-crypt.h"
  22. #define RANDBYTES (16)
  23. static int try_close(int fd)
  24. {
  25. int ret;
  26. for (;;) {
  27. errno = 0;
  28. ret = close(fd);
  29. if (ret == -1 && errno == EINTR)
  30. continue;
  31. break;
  32. }
  33. return ret;
  34. }
  35. static int try_read(int fd, char *out, size_t count)
  36. {
  37. size_t total;
  38. ssize_t partial;
  39. total = 0;
  40. while (total < count)
  41. {
  42. for (;;) {
  43. errno = 0;
  44. partial = read(fd, out + total, count - total);
  45. if (partial == -1 && errno == EINTR)
  46. continue;
  47. break;
  48. }
  49. if (partial < 1)
  50. return -1;
  51. total += partial;
  52. }
  53. return 0;
  54. }
  55. /*
  56. * This is a best effort implementation. Nothing prevents a compiler from
  57. * optimizing this function and making it vulnerable to timing attacks, but
  58. * this method is commonly used in crypto libraries like NaCl.
  59. *
  60. * Return value is zero if both strings are equal and nonzero otherwise.
  61. */
  62. static int timing_safe_strcmp(const char *str1, const char *str2)
  63. {
  64. const unsigned char *u1;
  65. const unsigned char *u2;
  66. int ret;
  67. int i;
  68. int len1 = strlen(str1);
  69. int len2 = strlen(str2);
  70. /* In our context both strings should always have the same length
  71. * because they will be hashed passwords. */
  72. if (len1 != len2)
  73. return 1;
  74. /* Force unsigned for bitwise operations. */
  75. u1 = (const unsigned char *)str1;
  76. u2 = (const unsigned char *)str2;
  77. ret = 0;
  78. for (i = 0; i < len1; ++i)
  79. ret |= (u1[i] ^ u2[i]);
  80. return ret;
  81. }
  82. int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
  83. {
  84. int fd;
  85. char input[RANDBYTES];
  86. int workf;
  87. char *aux;
  88. fd = open("/dev/urandom", O_RDONLY);
  89. if (fd == -1)
  90. return 1;
  91. if (try_read(fd, input, RANDBYTES) != 0) {
  92. if (try_close(fd) != 0)
  93. return 4;
  94. return 2;
  95. }
  96. if (try_close(fd) != 0)
  97. return 3;
  98. /* Generate salt. */
  99. workf = (factor < 4 || factor > 31)?12:factor;
  100. aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
  101. salt, BCRYPT_HASHSIZE);
  102. return (aux == NULL)?5:0;
  103. }
  104. int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE])
  105. {
  106. char *aux;
  107. aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE);
  108. return (aux == NULL)?1:0;
  109. }
  110. int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE])
  111. {
  112. int ret;
  113. char outhash[BCRYPT_HASHSIZE];
  114. ret = bcrypt_hashpw(passwd, hash, outhash);
  115. if (ret != 0)
  116. return -1;
  117. return timing_safe_strcmp(hash, outhash);
  118. }
  119. #ifdef TEST_BCRYPT
  120. #include <assert.h>
  121. #include <stdio.h>
  122. #include <string.h>
  123. #include <time.h>
  124. int main(void)
  125. {
  126. clock_t before;
  127. clock_t after;
  128. char salt[BCRYPT_HASHSIZE];
  129. char hash[BCRYPT_HASHSIZE];
  130. int ret;
  131. const char pass[] = "hi,mom";
  132. const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK";
  133. const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO";
  134. ret = bcrypt_gensalt(12, salt);
  135. assert(ret == 0);
  136. printf("Generated salt: %s\n", salt);
  137. before = clock();
  138. ret = bcrypt_hashpw("testtesttest", salt, hash);
  139. assert(ret == 0);
  140. after = clock();
  141. printf("Hashed password: %s\n", hash);
  142. printf("Time taken: %f seconds\n",
  143. (double)(after - before) / CLOCKS_PER_SEC);
  144. ret = bcrypt_hashpw(pass, hash1, hash);
  145. assert(ret == 0);
  146. printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL");
  147. ret = bcrypt_hashpw(pass, hash2, hash);
  148. assert(ret == 0);
  149. printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL");
  150. before = clock();
  151. ret = (bcrypt_checkpw(pass, hash1) == 0);
  152. after = clock();
  153. printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
  154. printf("Time taken: %f seconds\n",
  155. (double)(after - before) / CLOCKS_PER_SEC);
  156. before = clock();
  157. ret = (bcrypt_checkpw(pass, hash2) == 0);
  158. after = clock();
  159. printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
  160. printf("Time taken: %f seconds\n",
  161. (double)(after - before) / CLOCKS_PER_SEC);
  162. return 0;
  163. }
  164. #endif