Created
August 19, 2013 19:20
-
-
Save kballenegger/6272937 to your computer and use it in GitHub Desktop.
PHP C modules for cb-pbkdf2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include "php.h" | |
| #include "php_cb_pbkdf2.h" | |
| #include <string.h> | |
| #include "cb-pbkdf2.h" | |
| static zend_function_entry cb_pbkdf2_functions[] = { | |
| PHP_FE(cb_pbkdf2_generate_key, NULL) | |
| PHP_FE(cb_pbkdf2_verify_password, NULL) | |
| {NULL, NULL, NULL} | |
| }; | |
| zend_module_entry cb_pbkdf2_module_entry = { | |
| #if ZEND_MODULE_API_NO >= 20010901 | |
| STANDARD_MODULE_HEADER, | |
| #endif | |
| PHP_CB_PBKDF2_EXTNAME, | |
| cb_pbkdf2_functions, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| #if ZEND_MODULE_API_NO >= 20010901 | |
| PHP_CB_PBKDF2_VERSION, | |
| #endif | |
| STANDARD_MODULE_PROPERTIES | |
| }; | |
| #ifdef COMPILE_DL_CB_PBKDF2 | |
| ZEND_GET_MODULE(cb_pbkdf2) | |
| #endif | |
| // utilities bin / hex conversion routines, copied from the binary | |
| // assumes correct input | |
| void util_hex2bytes(char *in, unsigned char *out) { | |
| for (unsigned int i = 0; i < strlen(in); i+=2) { | |
| char first = *(in+i); | |
| char second = *(in+i+1); | |
| unsigned char byte = 0; | |
| if ('0' <= first && first <= '9') { | |
| byte += (first-'0') * 16; | |
| } else if ('a' <= first && first <= 'f') { | |
| byte += (first-'a' + 10) * 16; | |
| } else if ('A' <= first && first <= 'F') { | |
| byte += (first-'A' + 10) * 16; | |
| } // else something bad is going on but i don't care... | |
| if ('0' <= second && second <= '9') { | |
| byte += second-'0'; | |
| } else if ('a' <= second && second <= 'f') { | |
| byte += second-'a' + 10; | |
| } else if ('A' <= second && second <= 'F') { | |
| byte += second-'A' + 10; | |
| } // else something bad is going on but i don't care... | |
| *(out+(i/2)) = byte; | |
| } | |
| } | |
| // assumes input of in_length and output buffer of in_length * 2 + 1 | |
| void util_bytes2hex(unsigned char *in, int in_length, char *out) { | |
| for (int i = 0; i < in_length; i++) { | |
| char b[3]; | |
| sprintf(b, "%02x", *(in+i)); | |
| *(out+(2*i)) = b[0]; | |
| *(out+(2*i)+1) = b[1]; | |
| } | |
| *(out+in_length*2) = 0; | |
| } | |
| // Actual implementation, finally. Fuck Zend, seriously. | |
| PHP_FUNCTION(cb_pbkdf2_generate_key) { | |
| // parameters | |
| char *password; | |
| int password_len; | |
| int iterations = 10000; | |
| if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &password, &password_len, &iterations) == FAILURE) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse arguments..."); | |
| RETURN_NULL(); | |
| } | |
| unsigned char salt_out[salt_length]; | |
| unsigned char key_out[key_length]; | |
| if(!generate_key(password, iterations, salt_out, key_out)) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Password generation failed."); | |
| RETURN_NULL(); | |
| } | |
| // What? Why? How? The fuck... | |
| array_init(return_value); | |
| char salt[salt_length * 2 + 1]; | |
| char key[key_length * 2 + 1]; | |
| util_bytes2hex(salt_out, salt_length, salt); | |
| util_bytes2hex(key_out, key_length, key); | |
| add_assoc_string(return_value, "salt", salt, 1); | |
| add_assoc_string(return_value, "key", key, 1); | |
| add_assoc_long(return_value, "iterations", iterations); | |
| // Should automatically be returned, I guess through magic pointer shit. | |
| } | |
| PHP_FUNCTION(cb_pbkdf2_verify_password) { | |
| // parameters | |
| char *password; | |
| int password_len; // unused | |
| zval *hash_val; | |
| if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &password, &password_len, &hash_val) == FAILURE) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse arguments..."); | |
| RETURN_NULL(); | |
| } | |
| HashTable *hash = Z_ARRVAL_P(hash_val); | |
| if (zend_hash_num_elements(hash) < 3) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hash does not appear to have 3 keys."); | |
| RETURN_NULL(); | |
| } | |
| // capturing hash keys as zvals | |
| zval **salt_hex_val; | |
| zval **key_hex_val; | |
| zval **iterations_val; | |
| if ( // getting values | |
| zend_hash_find(hash, "salt", strlen("salt") + 1, (void**)&salt_hex_val) == FAILURE || | |
| zend_hash_find(hash, "key", strlen("key") + 1, (void**)&key_hex_val) == FAILURE || | |
| zend_hash_find(hash, "iterations", strlen("iterations") + 1, (void**)&iterations_val) == FAILURE || | |
| // checking types | |
| Z_TYPE_PP(salt_hex_val) != IS_STRING || | |
| Z_TYPE_PP(key_hex_val) != IS_STRING || | |
| (Z_TYPE_PP(iterations_val) != IS_LONG && Z_TYPE_PP(iterations_val) != IS_DOUBLE) | |
| ) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract and check types on required values in hash: salt, key, and iterations."); | |
| RETURN_NULL(); | |
| } | |
| char *salt_hex; | |
| char *key_hex; | |
| if (Z_STRLEN_PP(salt_hex_val) != salt_length * 2 || | |
| Z_STRLEN_PP(key_hex_val) != key_length * 2) { | |
| php_error_docref(NULL TSRMLS_CC, E_WARNING, "Key or Salt length incorrect."); | |
| RETURN_NULL(); | |
| } | |
| salt_hex = Z_STRVAL_PP(salt_hex_val); | |
| key_hex = Z_STRVAL_PP(key_hex_val); | |
| int iterations = (Z_TYPE_PP(iterations_val) == IS_LONG ? | |
| (int)Z_LVAL_PP(iterations_val) : | |
| (int)Z_DVAL_PP(iterations_val)); | |
| unsigned char salt[salt_length]; | |
| unsigned char key[key_length]; | |
| util_hex2bytes(salt_hex, salt); | |
| util_hex2bytes(key_hex, key); | |
| if (verify_password(password, iterations, salt, key)) { | |
| RETURN_TRUE; | |
| } else { | |
| RETURN_FALSE; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment