Skip to content

Instantly share code, notes, and snippets.

@kballenegger
Created August 19, 2013 19:20
Show Gist options
  • Select an option

  • Save kballenegger/6272937 to your computer and use it in GitHub Desktop.

Select an option

Save kballenegger/6272937 to your computer and use it in GitHub Desktop.
PHP C modules for cb-pbkdf2.
#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