Skip to content

Commit f4847ef

Browse files
author
Scott MacVicar
committed
Add PBKDF2 support via openssl()
Summary: No easy way to put these in the hash extension since we don't really support optional parameters to certain algorithms. Implemented in openssl for now since it has it already and is pretty stable. Only SHA1 is confirmed to work as an algorithm but openssl has a parameter so it can be changed in the future. Will backport to 5.4 potentially with Stas' approval. Test Plan: Ran newly added tests which came from RFC 6070
1 parent b55e692 commit f4847ef

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

ext/openssl/openssl.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,14 @@ ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
242242
ZEND_ARG_INFO(0, key)
243243
ZEND_END_ARG_INFO()
244244

245+
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs5_pbkdf2_hmac, 0, 0, 4)
246+
ZEND_ARG_INFO(0, password)
247+
ZEND_ARG_INFO(0, salt)
248+
ZEND_ARG_INFO(0, key_length)
249+
ZEND_ARG_INFO(0, iterations)
250+
ZEND_ARG_INFO(0, digest_algorithm)
251+
ZEND_END_ARG_INFO()
252+
245253
ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
246254
ZEND_ARG_INFO(0, filename)
247255
ZEND_ARG_INFO(0, flags)
@@ -428,6 +436,8 @@ const zend_function_entry openssl_functions[] = {
428436
PHP_FE(openssl_seal, arginfo_openssl_seal)
429437
PHP_FE(openssl_open, arginfo_openssl_open)
430438

439+
PHP_FE(openssl_pkcs5_pbkdf2_hmac, arginfo_openssl_pkcs5_pbkdf2_hmac)
440+
431441
/* for S/MIME handling */
432442
PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify)
433443
PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
@@ -3317,6 +3327,53 @@ PHP_FUNCTION(openssl_pkey_get_details)
33173327

33183328
/* }}} */
33193329

3330+
/* {{{ proto string openssl_pkcs5_pbkdf2_hmac(string password, string salt, long key_length, long iterations [, string digest_method = "sha1"])
3331+
Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */
3332+
PHP_FUNCTION(openssl_pkcs5_pbkdf2_hmac)
3333+
{
3334+
long key_length = 0, iterations = 0;
3335+
char *password; int password_len;
3336+
char *salt; int salt_len;
3337+
char *method; int method_len = 0;
3338+
unsigned char *out_buffer;
3339+
3340+
const EVP_MD *digest;
3341+
3342+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssll|s",
3343+
&password, &password_len,
3344+
&salt, &salt_len,
3345+
&key_length, &iterations,
3346+
&method, &method_len) == FAILURE) {
3347+
return;
3348+
}
3349+
3350+
if (key_length <= 0) {
3351+
RETURN_FALSE;
3352+
}
3353+
3354+
if (method_len) {
3355+
digest = EVP_get_digestbyname(method);
3356+
} else {
3357+
digest = EVP_sha1();
3358+
}
3359+
3360+
if (!digest) {
3361+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
3362+
RETURN_FALSE;
3363+
}
3364+
3365+
out_buffer = emalloc(key_length + 1);
3366+
out_buffer[key_length] = '\0';
3367+
3368+
if (PKCS5_PBKDF2_HMAC(password, password_len, (unsigned char *)salt, salt_len, iterations, digest, key_length, out_buffer) == 1) {
3369+
RETVAL_STRINGL((char *)out_buffer, key_length, 0);
3370+
} else {
3371+
efree(out_buffer);
3372+
RETURN_FALSE;
3373+
}
3374+
}
3375+
/* }}} */
3376+
33203377
/* {{{ PKCS7 S/MIME functions */
33213378

33223379
/* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])

ext/openssl/php_openssl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ PHP_FUNCTION(openssl_private_decrypt);
5252
PHP_FUNCTION(openssl_public_encrypt);
5353
PHP_FUNCTION(openssl_public_decrypt);
5454

55+
PHP_FUNCTION(openssl_pkcs5_pbkdf2_hmac);
56+
5557
PHP_FUNCTION(openssl_pkcs7_verify);
5658
PHP_FUNCTION(openssl_pkcs7_decrypt);
5759
PHP_FUNCTION(openssl_pkcs7_sign);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
openssl_pkcs5_pbkdf2_hmac() tests
3+
--SKIPIF--
4+
<?php if (!extension_loaded("openssl")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
// official test vectors
8+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac('password', 'salt', 20, 1)));
9+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac('password', 'salt', 20, 2)));
10+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac('password', 'salt', 20, 4096)));
11+
12+
/* really slow but should be:
13+
string(40) "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"
14+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac('password', 'salt', 20, 16777216)));
15+
*/
16+
17+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac('passwordPASSWORDpassword', 'saltSALTsaltSALTsaltSALTsaltSALTsalt', 25, 4096)));
18+
var_dump(bin2hex(openssl_pkcs5_pbkdf2_hmac("pass\0word", "sa\0lt", 16, 4096)));
19+
20+
?>
21+
--EXPECTF--
22+
string(40) "0c60c80f961f0e71f3a9b524af6012062fe037a6"
23+
string(40) "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"
24+
string(40) "4b007901b765489abead49d926f721d065a429c1"
25+
string(50) "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"
26+
string(32) "56fa6aa75548099dcc37d7f03425e0c3"

0 commit comments

Comments
 (0)