Return to crypt.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 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: ! 22: /* $Id: crypt.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 23: ! 24: #include <stdlib.h> ! 25: ! 26: #include "php.h" ! 27: #if HAVE_CRYPT ! 28: ! 29: #if HAVE_UNISTD_H ! 30: #include <unistd.h> ! 31: #endif ! 32: #if PHP_USE_PHP_CRYPT_R ! 33: # include "php_crypt_r.h" ! 34: # include "crypt_freesec.h" ! 35: #else ! 36: # if HAVE_CRYPT_H ! 37: # if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE) ! 38: # define _GNU_SOURCE ! 39: # endif ! 40: # include <crypt.h> ! 41: # endif ! 42: #endif ! 43: #if TM_IN_SYS_TIME ! 44: #include <sys/time.h> ! 45: #else ! 46: #include <time.h> ! 47: #endif ! 48: #if HAVE_STRING_H ! 49: #include <string.h> ! 50: #else ! 51: #include <strings.h> ! 52: #endif ! 53: ! 54: #ifdef PHP_WIN32 ! 55: #include <process.h> ! 56: #endif ! 57: ! 58: #include "php_lcg.h" ! 59: #include "php_crypt.h" ! 60: #include "php_rand.h" ! 61: ! 62: /* The capabilities of the crypt() function is determined by the test programs ! 63: * run by configure from aclocal.m4. They will set PHP_STD_DES_CRYPT, ! 64: * PHP_EXT_DES_CRYPT, PHP_MD5_CRYPT and PHP_BLOWFISH_CRYPT as appropriate ! 65: * for the target platform. */ ! 66: ! 67: #if PHP_STD_DES_CRYPT ! 68: #define PHP_MAX_SALT_LEN 2 ! 69: #endif ! 70: ! 71: #if PHP_EXT_DES_CRYPT ! 72: #undef PHP_MAX_SALT_LEN ! 73: #define PHP_MAX_SALT_LEN 9 ! 74: #endif ! 75: ! 76: #if PHP_MD5_CRYPT ! 77: #undef PHP_MAX_SALT_LEN ! 78: #define PHP_MAX_SALT_LEN 12 ! 79: #endif ! 80: ! 81: #if PHP_BLOWFISH_CRYPT ! 82: #undef PHP_MAX_SALT_LEN ! 83: #define PHP_MAX_SALT_LEN 60 ! 84: #endif ! 85: ! 86: #if PHP_SHA512_CRYPT ! 87: #undef PHP_MAX_SALT_LEN ! 88: #define PHP_MAX_SALT_LEN 123 ! 89: #endif ! 90: ! 91: ! 92: /* If the configure-time checks fail, we provide DES. ! 93: * XXX: This is a hack. Fix the real problem! */ ! 94: ! 95: #ifndef PHP_MAX_SALT_LEN ! 96: #define PHP_MAX_SALT_LEN 2 ! 97: #undef PHP_STD_DES_CRYPT ! 98: #define PHP_STD_DES_CRYPT 1 ! 99: #endif ! 100: ! 101: #define PHP_CRYPT_RAND php_rand(TSRMLS_C) ! 102: ! 103: PHP_MINIT_FUNCTION(crypt) /* {{{ */ ! 104: { ! 105: REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_CS | CONST_PERSISTENT); ! 106: REGISTER_LONG_CONSTANT("CRYPT_STD_DES", PHP_STD_DES_CRYPT, CONST_CS | CONST_PERSISTENT); ! 107: REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", PHP_EXT_DES_CRYPT, CONST_CS | CONST_PERSISTENT); ! 108: REGISTER_LONG_CONSTANT("CRYPT_MD5", PHP_MD5_CRYPT, CONST_CS | CONST_PERSISTENT); ! 109: REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", PHP_BLOWFISH_CRYPT, CONST_CS | CONST_PERSISTENT); ! 110: ! 111: #ifdef PHP_SHA256_CRYPT ! 112: REGISTER_LONG_CONSTANT("CRYPT_SHA256", PHP_SHA256_CRYPT, CONST_CS | CONST_PERSISTENT); ! 113: #endif ! 114: ! 115: #ifdef PHP_SHA512_CRYPT ! 116: REGISTER_LONG_CONSTANT("CRYPT_SHA512", PHP_SHA512_CRYPT, CONST_CS | CONST_PERSISTENT); ! 117: #endif ! 118: ! 119: #if PHP_USE_PHP_CRYPT_R ! 120: php_init_crypt_r(); ! 121: #endif ! 122: ! 123: return SUCCESS; ! 124: } ! 125: /* }}} */ ! 126: ! 127: PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */ ! 128: { ! 129: #if PHP_USE_PHP_CRYPT_R ! 130: php_shutdown_crypt_r(); ! 131: #endif ! 132: ! 133: return SUCCESS; ! 134: } ! 135: /* }}} */ ! 136: ! 137: static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; ! 138: ! 139: static void php_to64(char *s, long v, int n) /* {{{ */ ! 140: { ! 141: while (--n >= 0) { ! 142: *s++ = itoa64[v&0x3f]; ! 143: v >>= 6; ! 144: } ! 145: } ! 146: /* }}} */ ! 147: ! 148: /* {{{ proto string crypt(string str [, string salt]) ! 149: Hash a string */ ! 150: PHP_FUNCTION(crypt) ! 151: { ! 152: char salt[PHP_MAX_SALT_LEN + 1]; ! 153: char *str, *salt_in = NULL; ! 154: int str_len, salt_in_len = 0; ! 155: char *crypt_res; ! 156: salt[0] = salt[PHP_MAX_SALT_LEN] = '\0'; ! 157: ! 158: /* This will produce suitable results if people depend on DES-encryption ! 159: * available (passing always 2-character salt). At least for glibc6.1 */ ! 160: memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1); ! 161: ! 162: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) { ! 163: return; ! 164: } ! 165: ! 166: if (salt_in) { ! 167: memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len)); ! 168: } ! 169: ! 170: /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */ ! 171: if (!*salt) { ! 172: #if PHP_MD5_CRYPT ! 173: strncpy(salt, "$1$", PHP_MAX_SALT_LEN); ! 174: php_to64(&salt[3], PHP_CRYPT_RAND, 4); ! 175: php_to64(&salt[7], PHP_CRYPT_RAND, 4); ! 176: strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11); ! 177: #elif PHP_STD_DES_CRYPT ! 178: php_to64(&salt[0], PHP_CRYPT_RAND, 2); ! 179: salt[2] = '\0'; ! 180: #endif ! 181: salt_in_len = strlen(salt); ! 182: } else { ! 183: salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len); ! 184: } ! 185: ! 186: /* Windows (win32/crypt) has a stripped down version of libxcrypt and ! 187: a CryptoApi md5_crypt implementation */ ! 188: #if PHP_USE_PHP_CRYPT_R ! 189: { ! 190: struct php_crypt_extended_data buffer; ! 191: ! 192: if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') { ! 193: char output[MD5_HASH_MAX_LEN]; ! 194: ! 195: RETURN_STRING(php_md5_crypt_r(str, salt, output), 1); ! 196: } else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') { ! 197: const char sha512_salt_prefix[] = "$6$"; ! 198: const char sha512_rounds_prefix[] = "rounds="; ! 199: char *output; ! 200: int needed = (sizeof(sha512_salt_prefix) - 1 ! 201: + sizeof(sha512_rounds_prefix) + 9 + 1 ! 202: + strlen(salt) + 1 + 43 + 1); ! 203: output = emalloc(needed * sizeof(char *)); ! 204: salt[salt_in_len] = '\0'; ! 205: ! 206: crypt_res = php_sha512_crypt_r(str, salt, output, needed); ! 207: if (!crypt_res) { ! 208: if (salt[0]=='*' && salt[1]=='0') { ! 209: RETVAL_STRING("*1", 1); ! 210: } else { ! 211: RETVAL_STRING("*0", 1); ! 212: } ! 213: } else { ! 214: RETVAL_STRING(output, 1); ! 215: } ! 216: ! 217: memset(output, 0, PHP_MAX_SALT_LEN + 1); ! 218: efree(output); ! 219: } else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') { ! 220: const char sha256_salt_prefix[] = "$5$"; ! 221: const char sha256_rounds_prefix[] = "rounds="; ! 222: char *output; ! 223: int needed = (sizeof(sha256_salt_prefix) - 1 ! 224: + sizeof(sha256_rounds_prefix) + 9 + 1 ! 225: + strlen(salt) + 1 + 43 + 1); ! 226: output = emalloc(needed * sizeof(char *)); ! 227: salt[salt_in_len] = '\0'; ! 228: ! 229: crypt_res = php_sha256_crypt_r(str, salt, output, needed); ! 230: if (!crypt_res) { ! 231: if (salt[0]=='*' && salt[1]=='0') { ! 232: RETVAL_STRING("*1", 1); ! 233: } else { ! 234: RETVAL_STRING("*0", 1); ! 235: } ! 236: } else { ! 237: RETVAL_STRING(output, 1); ! 238: } ! 239: ! 240: memset(output, 0, PHP_MAX_SALT_LEN + 1); ! 241: efree(output); ! 242: } else if ( ! 243: salt[0] == '$' && ! 244: salt[1] == '2' && ! 245: salt[2] >= 'a' && salt[2] <= 'z' && ! 246: salt[3] == '$' && ! 247: salt[4] >= '0' && salt[4] <= '3' && ! 248: salt[5] >= '0' && salt[5] <= '9' && ! 249: salt[6] == '$') { ! 250: char output[PHP_MAX_SALT_LEN + 1]; ! 251: ! 252: memset(output, 0, PHP_MAX_SALT_LEN + 1); ! 253: ! 254: crypt_res = php_crypt_blowfish_rn(str, salt, output, sizeof(output)); ! 255: if (!crypt_res) { ! 256: if (salt[0]=='*' && salt[1]=='0') { ! 257: RETVAL_STRING("*1", 1); ! 258: } else { ! 259: RETVAL_STRING("*0", 1); ! 260: } ! 261: } else { ! 262: RETVAL_STRING(output, 1); ! 263: } ! 264: ! 265: memset(output, 0, PHP_MAX_SALT_LEN + 1); ! 266: } else { ! 267: memset(&buffer, 0, sizeof(buffer)); ! 268: _crypt_extended_init_r(); ! 269: ! 270: crypt_res = _crypt_extended_r(str, salt, &buffer); ! 271: if (!crypt_res) { ! 272: if (salt[0]=='*' && salt[1]=='0') { ! 273: RETURN_STRING("*1", 1); ! 274: } else { ! 275: RETURN_STRING("*0", 1); ! 276: } ! 277: } else { ! 278: RETURN_STRING(crypt_res, 1); ! 279: } ! 280: } ! 281: } ! 282: #else ! 283: ! 284: # if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE)) ! 285: { ! 286: # if defined(CRYPT_R_STRUCT_CRYPT_DATA) ! 287: struct crypt_data buffer; ! 288: memset(&buffer, 0, sizeof(buffer)); ! 289: # elif defined(CRYPT_R_CRYPTD) ! 290: CRYPTD buffer; ! 291: # else ! 292: # error Data struct used by crypt_r() is unknown. Please report. ! 293: # endif ! 294: crypt_res = crypt_r(str, salt, &buffer); ! 295: if (!crypt_res) { ! 296: if (salt[0]=='*' && salt[1]=='0') { ! 297: RETURN_STRING("*1", 1); ! 298: } else { ! 299: RETURN_STRING("*0", 1); ! 300: } ! 301: } else { ! 302: RETURN_STRING(crypt_res, 1); ! 303: } ! 304: } ! 305: # endif ! 306: #endif ! 307: } ! 308: /* }}} */ ! 309: #endif ! 310: ! 311: /* ! 312: * Local variables: ! 313: * tab-width: 4 ! 314: * c-basic-offset: 4 ! 315: * End: ! 316: * vim600: sw=4 ts=4 fdm=marker ! 317: * vim<600: sw=4 ts=4 ! 318: */