PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/standard/crypt.c

http://github.com/infusion/PHP
C | 316 lines | 227 code | 43 blank | 46 comment | 58 complexity | 883483a97f99f6015d1af2788877bc54 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Stig Bakken <ssb@php.net> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Rasmus Lerdorf <rasmus@php.net> |
  18. | Pierre Joye <pierre@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. /* $Id: crypt.c 306939 2011-01-01 02:19:59Z felipe $ */
  22. #include <stdlib.h>
  23. #include "php.h"
  24. #if HAVE_CRYPT
  25. #if HAVE_UNISTD_H
  26. #include <unistd.h>
  27. #endif
  28. #if PHP_USE_PHP_CRYPT_R
  29. # include "php_crypt_r.h"
  30. # include "crypt_freesec.h"
  31. #else
  32. # if HAVE_CRYPT_H
  33. # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
  34. # define _GNU_SOURCE
  35. # endif
  36. # include <crypt.h>
  37. # endif
  38. #endif
  39. #if TM_IN_SYS_TIME
  40. #include <sys/time.h>
  41. #else
  42. #include <time.h>
  43. #endif
  44. #if HAVE_STRING_H
  45. #include <string.h>
  46. #else
  47. #include <strings.h>
  48. #endif
  49. #ifdef PHP_WIN32
  50. #include <process.h>
  51. #endif
  52. #include "php_lcg.h"
  53. #include "php_crypt.h"
  54. #include "php_rand.h"
  55. /* The capabilities of the crypt() function is determined by the test programs
  56. * run by configure from aclocal.m4. They will set PHP_STD_DES_CRYPT,
  57. * PHP_EXT_DES_CRYPT, PHP_MD5_CRYPT and PHP_BLOWFISH_CRYPT as appropriate
  58. * for the target platform. */
  59. #if PHP_STD_DES_CRYPT
  60. #define PHP_MAX_SALT_LEN 2
  61. #endif
  62. #if PHP_EXT_DES_CRYPT
  63. #undef PHP_MAX_SALT_LEN
  64. #define PHP_MAX_SALT_LEN 9
  65. #endif
  66. #if PHP_MD5_CRYPT
  67. #undef PHP_MAX_SALT_LEN
  68. #define PHP_MAX_SALT_LEN 12
  69. #endif
  70. #if PHP_BLOWFISH_CRYPT
  71. #undef PHP_MAX_SALT_LEN
  72. #define PHP_MAX_SALT_LEN 60
  73. #endif
  74. #if PHP_SHA512_CRYPT
  75. #undef PHP_MAX_SALT_LEN
  76. #define PHP_MAX_SALT_LEN 123
  77. #endif
  78. /* If the configure-time checks fail, we provide DES.
  79. * XXX: This is a hack. Fix the real problem! */
  80. #ifndef PHP_MAX_SALT_LEN
  81. #define PHP_MAX_SALT_LEN 2
  82. #undef PHP_STD_DES_CRYPT
  83. #define PHP_STD_DES_CRYPT 1
  84. #endif
  85. #define PHP_CRYPT_RAND php_rand(TSRMLS_C)
  86. PHP_MINIT_FUNCTION(crypt) /* {{{ */
  87. {
  88. REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT);
  89. REGISTER_LONG_CONSTANT("CRYPT_STD_DES", PHP_STD_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
  90. REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", PHP_EXT_DES_CRYPT, CONST_CS | CONST_PERSISTENT);
  91. REGISTER_LONG_CONSTANT("CRYPT_MD5", PHP_MD5_CRYPT, CONST_CS | CONST_PERSISTENT);
  92. REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", PHP_BLOWFISH_CRYPT, CONST_CS | CONST_PERSISTENT);
  93. #ifdef PHP_SHA256_CRYPT
  94. REGISTER_LONG_CONSTANT("CRYPT_SHA256", PHP_SHA256_CRYPT, CONST_CS | CONST_PERSISTENT);
  95. #endif
  96. #ifdef PHP_SHA512_CRYPT
  97. REGISTER_LONG_CONSTANT("CRYPT_SHA512", PHP_SHA512_CRYPT, CONST_CS | CONST_PERSISTENT);
  98. #endif
  99. #if PHP_USE_PHP_CRYPT_R
  100. php_init_crypt_r();
  101. #endif
  102. return SUCCESS;
  103. }
  104. /* }}} */
  105. PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
  106. {
  107. #if PHP_USE_PHP_CRYPT_R
  108. php_shutdown_crypt_r();
  109. #endif
  110. return SUCCESS;
  111. }
  112. /* }}} */
  113. static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  114. static void php_to64(char *s, long v, int n) /* {{{ */
  115. {
  116. while (--n >= 0) {
  117. *s++ = itoa64[v&0x3f];
  118. v >>= 6;
  119. }
  120. }
  121. /* }}} */
  122. /* {{{ proto string crypt(string str [, string salt])
  123. Hash a string */
  124. PHP_FUNCTION(crypt)
  125. {
  126. char salt[PHP_MAX_SALT_LEN + 1];
  127. char *str, *salt_in = NULL;
  128. int str_len, salt_in_len = 0;
  129. char *crypt_res;
  130. salt[0] = salt[PHP_MAX_SALT_LEN] = '\0';
  131. /* This will produce suitable results if people depend on DES-encryption
  132. * available (passing always 2-character salt). At least for glibc6.1 */
  133. memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
  134. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) {
  135. return;
  136. }
  137. if (salt_in) {
  138. memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
  139. }
  140. /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
  141. if (!*salt) {
  142. #if PHP_MD5_CRYPT
  143. strcpy(salt, "$1$");
  144. php_to64(&salt[3], PHP_CRYPT_RAND, 4);
  145. php_to64(&salt[7], PHP_CRYPT_RAND, 4);
  146. strcpy(&salt[11], "$");
  147. #elif PHP_STD_DES_CRYPT
  148. php_to64(&salt[0], PHP_CRYPT_RAND, 2);
  149. salt[2] = '\0';
  150. #endif
  151. salt_in_len = strlen(salt);
  152. }
  153. /* Windows (win32/crypt) has a stripped down version of libxcrypt and
  154. a CryptoApi md5_crypt implementation */
  155. #if PHP_USE_PHP_CRYPT_R
  156. {
  157. struct php_crypt_extended_data buffer;
  158. if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') {
  159. char output[MD5_HASH_MAX_LEN];
  160. RETURN_STRING(php_md5_crypt_r(str, salt, output), 1);
  161. } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') {
  162. const char sha512_salt_prefix[] = "$6$";
  163. const char sha512_rounds_prefix[] = "rounds=";
  164. char *output;
  165. int needed = (sizeof(sha512_salt_prefix) - 1
  166. + sizeof(sha512_rounds_prefix) + 9 + 1
  167. + strlen(salt) + 1 + 43 + 1);
  168. output = emalloc(needed * sizeof(char *));
  169. salt[salt_in_len] = '\0';
  170. crypt_res = php_sha512_crypt_r(str, salt, output, needed);
  171. if (!crypt_res) {
  172. if (salt[0]=='*' && salt[1]=='0') {
  173. RETVAL_STRING("*1", 1);
  174. } else {
  175. RETVAL_STRING("*0", 1);
  176. }
  177. } else {
  178. RETVAL_STRING(output, 1);
  179. }
  180. memset(output, 0, PHP_MAX_SALT_LEN + 1);
  181. efree(output);
  182. } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') {
  183. const char sha256_salt_prefix[] = "$5$";
  184. const char sha256_rounds_prefix[] = "rounds=";
  185. char *output;
  186. int needed = (sizeof(sha256_salt_prefix) - 1
  187. + sizeof(sha256_rounds_prefix) + 9 + 1
  188. + strlen(salt) + 1 + 43 + 1);
  189. output = emalloc(needed * sizeof(char *));
  190. salt[salt_in_len] = '\0';
  191. crypt_res = php_sha256_crypt_r(str, salt, output, needed);
  192. if (!crypt_res) {
  193. if (salt[0]=='*' && salt[1]=='0') {
  194. RETVAL_STRING("*1", 1);
  195. } else {
  196. RETVAL_STRING("*0", 1);
  197. }
  198. } else {
  199. RETVAL_STRING(output, 1);
  200. }
  201. memset(output, 0, PHP_MAX_SALT_LEN + 1);
  202. efree(output);
  203. } else if (
  204. salt[0] == '$' &&
  205. salt[1] == '2' &&
  206. salt[2] == 'a' &&
  207. salt[3] == '$' &&
  208. salt[4] >= '0' && salt[4] <= '3' &&
  209. salt[5] >= '0' && salt[5] <= '9' &&
  210. salt[6] == '$') {
  211. char output[PHP_MAX_SALT_LEN + 1];
  212. memset(output, 0, PHP_MAX_SALT_LEN + 1);
  213. crypt_res = php_crypt_blowfish_rn(str, salt, output, sizeof(output));
  214. if (!crypt_res) {
  215. if (salt[0]=='*' && salt[1]=='0') {
  216. RETVAL_STRING("*1", 1);
  217. } else {
  218. RETVAL_STRING("*0", 1);
  219. }
  220. } else {
  221. RETVAL_STRING(output, 1);
  222. }
  223. memset(output, 0, PHP_MAX_SALT_LEN + 1);
  224. } else {
  225. memset(&buffer, 0, sizeof(buffer));
  226. _crypt_extended_init_r();
  227. crypt_res = _crypt_extended_r(str, salt, &buffer);
  228. if (!crypt_res) {
  229. if (salt[0]=='*' && salt[1]=='0') {
  230. RETURN_STRING("*1", 1);
  231. } else {
  232. RETURN_STRING("*0", 1);
  233. }
  234. } else {
  235. RETURN_STRING(crypt_res, 1);
  236. }
  237. }
  238. }
  239. #else
  240. # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
  241. {
  242. # if defined(CRYPT_R_STRUCT_CRYPT_DATA)
  243. struct crypt_data buffer;
  244. memset(&buffer, 0, sizeof(buffer));
  245. # elif defined(CRYPT_R_CRYPTD)
  246. CRYPTD buffer;
  247. # else
  248. # error Data struct used by crypt_r() is unknown. Please report.
  249. # endif
  250. crypt_res = crypt_r(str, salt, &buffer);
  251. if (!crypt_res) {
  252. if (salt[0]=='*' && salt[1]=='0') {
  253. RETURN_STRING("*1", 1);
  254. } else {
  255. RETURN_STRING("*0", 1);
  256. }
  257. } else {
  258. RETURN_STRING(crypt_res, 1);
  259. }
  260. }
  261. # endif
  262. #endif
  263. }
  264. /* }}} */
  265. #endif
  266. /*
  267. * Local variables:
  268. * tab-width: 4
  269. * c-basic-offset: 4
  270. * End:
  271. * vim600: sw=4 ts=4 fdm=marker
  272. * vim<600: sw=4 ts=4
  273. */