Skip to content

Commit 2cf96e4

Browse files
committed
Use CommonCrypto for PBKDF2-HMAC-SHA256 on Apple
1 parent 8378d8e commit 2cf96e4

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

ext/hash/hash.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
#include "ext/standard/file.h"
2727
#include "ext/standard/php_var.h"
2828

29+
#if defined(__APPLE__) && __has_include(<CommonCrypto/CommonKeyDerivation.h>)
30+
# include <CommonCrypto/CommonCryptoError.h>
31+
# include <CommonCrypto/CommonKeyDerivation.h>
32+
# define PHP_HASH_HAVE_COMMONCRYPTO_PBKDF2 1
33+
#endif
34+
2935
/* Internal helper from hash_sha.c, not part of the public hash API. */
3036
void php_hash_sha256_final32_from_context(unsigned char digest[32], const PHP_SHA256_CTX *context, const unsigned char data[32]);
3137

@@ -627,6 +633,51 @@ static zend_string *php_hash_pbkdf2_sha256(const char *pass, size_t pass_len, co
627633
return returnval;
628634
}
629635

636+
#ifdef PHP_HASH_HAVE_COMMONCRYPTO_PBKDF2
637+
static zend_string *php_hash_pbkdf2_sha256_commoncrypto(const char *pass, size_t pass_len, const char *salt, size_t salt_len, zend_long iterations, zend_long length, bool raw_output) {
638+
zend_string *returnval;
639+
unsigned char *derived = NULL;
640+
zend_long derived_len = 0;
641+
642+
if (iterations > UINT32_MAX) {
643+
return NULL;
644+
}
645+
646+
if (length == 0) {
647+
length = raw_output ? 32 : 64;
648+
}
649+
650+
derived_len = raw_output ? length : (zend_long) ceil((float) length / 2.0);
651+
if (derived_len <= 0) {
652+
return NULL;
653+
}
654+
655+
derived = safe_emalloc(derived_len, 1, 0);
656+
if (CCKeyDerivationPBKDF(
657+
kCCPBKDF2,
658+
pass, pass_len,
659+
(const uint8_t *) salt, salt_len,
660+
kCCPRFHmacAlgSHA256,
661+
(uint32_t) iterations,
662+
derived, (size_t) derived_len) != kCCSuccess) {
663+
efree(derived);
664+
return NULL;
665+
}
666+
667+
returnval = zend_string_alloc(length, 0);
668+
if (raw_output) {
669+
memcpy(ZSTR_VAL(returnval), derived, length);
670+
} else {
671+
php_hash_bin2hex(ZSTR_VAL(returnval), derived, derived_len);
672+
}
673+
ZSTR_VAL(returnval)[length] = 0;
674+
ZEND_SECURE_ZERO(derived, derived_len);
675+
efree(derived);
676+
677+
return returnval;
678+
}
679+
#endif
680+
630681
static void php_hash_do_hash_hmac(
631682
zval *return_value, zend_string *algo, char *data, size_t data_len, char *key, size_t key_len, bool raw_output, bool isfilename
632683
) /* {{{ */ {
@@ -1155,6 +1206,12 @@ PHP_FUNCTION(hash_pbkdf2)
11551206
}
11561207

11571208
if (ops == &php_hash_sha256_ops) {
1209+
#ifdef PHP_HASH_HAVE_COMMONCRYPTO_PBKDF2
1210+
zend_string *returnval_cc = php_hash_pbkdf2_sha256_commoncrypto(pass, pass_len, salt, salt_len, iterations, length, raw_output);
1211+
if (returnval_cc != NULL) {
1212+
RETURN_NEW_STR(returnval_cc);
1213+
}
1214+
#endif
11581215
RETURN_NEW_STR(php_hash_pbkdf2_sha256(pass, pass_len, salt, salt_len, iterations, length, raw_output));
11591216
}
11601217

0 commit comments

Comments
 (0)