/**
* Generate the new key
*
* @param string $hash The hash algorithm to be used by HMAC
* @param string $password The source password/key
* @param int $bytes The output size in bytes
* @param string $salt The salt of the algorithm
* @throws Exception\InvalidArgumentException
* @return string
*/
public static function calc($hash, $password, $salt, $bytes)
{
if (!in_array($hash, array_keys(static::$supportedMhashAlgos))) {
throw new Exception\InvalidArgumentException("The hash algorihtm {$hash} is not supported by " . __CLASS__);
}
if (strlen($salt) < 8) {
throw new Exception\InvalidArgumentException('The salt size must be at least of 8 bytes');
}
return mhash_keygen_s2k(static::$supportedMhashAlgos[$hash], $password, $salt, $bytes);
}
/**
* Code originaly from the phpLDAPadmin development team
* http://phpldapadmin.sourceforge.net/
*
* Hashes a password and returns the hash based on the specified enc_type.
*
* @param string $passwordClear The password to hash in clear text.
* @param string $encodageType Standard LDAP encryption type which must be one of
* crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, or clear.
* @return string The hashed password.
*
*/
function hashPassword($passwordClear, $encodageType)
{
$encodageType = strtolower($encodageType);
switch ($encodageType) {
case 'crypt':
$cryptedPassword = '{CRYPT}' . crypt($passwordClear, randomSalt(2));
break;
case 'ext_des':
// extended des crypt. see OpenBSD crypt man page.
if (!defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0) {
// Your system crypt library does not support extended DES encryption.
return FALSE;
}
$cryptedPassword = '{CRYPT}' . crypt($passwordClear, '_' . randomSalt(8));
break;
case 'md5crypt':
if (!defined('CRYPT_MD5') || CRYPT_MD5 == 0) {
// Your system crypt library does not support md5crypt encryption.
return FALSE;
}
$cryptedPassword = '{CRYPT}' . crypt($passwordClear, '$1$' . randomSalt(9));
break;
case 'blowfish':
if (!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) {
// Your system crypt library does not support blowfish encryption.
return FALSE;
}
// hardcoded to second blowfish version and set number of rounds
$cryptedPassword = '{CRYPT}' . crypt($passwordClear, '$2a$12$' . randomSalt(13));
break;
case 'md5':
$cryptedPassword = '{MD5}' . base64_encode(pack('H*', md5($passwordClear)));
break;
case 'sha':
if (function_exists('sha1')) {
// use php 4.3.0+ sha1 function, if it is available.
$cryptedPassword = '{SHA}' . base64_encode(pack('H*', sha1($passwordClear)));
} elseif (function_exists('mhash')) {
$cryptedPassword = '{SHA}' . base64_encode(mhash(MHASH_SHA1, $passwordClear));
} else {
return FALSE;
//Your PHP install does not have the mhash() function. Cannot do SHA hashes.
}
break;
case 'ssha':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double) microtime() * 1000000);
$salt = mhash_keygen_s2k(MHASH_SHA1, $passwordClear, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
$cryptedPassword = '{SSHA}' . base64_encode(mhash(MHASH_SHA1, $passwordClear . $salt) . $salt);
} else {
return FALSE;
//Your PHP install does not have the mhash() function. Cannot do SHA hashes.
}
break;
case 'smd5':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double) microtime() * 1000000);
$salt = mhash_keygen_s2k(MHASH_MD5, $passwordClear, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
$cryptedPassword = '{SMD5}' . base64_encode(mhash(MHASH_MD5, $passwordClear . $salt) . $salt);
} else {
return FALSE;
//Your PHP install does not have the mhash() function. Cannot do SHA hashes.
}
break;
case 'samba':
if (function_exists('hash')) {
$cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE'));
$cryptedPassword = strtoupper($cryptedPassword);
} else {
/* Your PHP install does not have the hash() function */
return false;
}
break;
case 'clear':
default:
$cryptedPassword = $passwordClear;
}
return $cryptedPassword;
}
/**
* Stores this Crypt_KeyStore to the given output stream, and protects its
* integrity with the given password.
*
* @param string $filename path and file name of key store file
* @param string $password password used encrypt key store
* @param array $options store options
*
* @return void
*/
public function store($filename, $password, $options = array())
{
try {
// open the file in write mode, truncate any existing file, and go to
// the beginning
$fd = fopen($filename, 'w');
if ($fd == false) {
throw new Crypt_KeyStore_Exception("Failed to open key store");
}
$processedOpts = $this->_processSymmetricOptions($options);
/* Open the cipher */
$td = mcrypt_module_open($processedOpts[self::OPT_CIPHER], '', $processedOpts[self::OPT_MODE], '');
// Create the IV and determine the keysize length, use MCRYPT_RAND
// on Windows instead
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$salt = substr(pack('H*', md5(mt_rand())), 0, $processedOpts[self::OPT_SALTSIZE]);
/* Create key */
$enc_key = mhash_keygen_s2k($processedOpts[self::OPT_HASH], $password, $salt, mcrypt_enc_get_key_size($td));
/* Intialize encryption */
mcrypt_generic_init($td, $enc_key, $iv);
// the file contents will have 16 bytes of data - the IV and the
// key salt so we can decrypt the file later
fwrite($fd, bin2hex($iv));
fwrite($fd, bin2hex($salt));
foreach ($this->_entries as $alias => $entry) {
// each entry is stored as:
// |alias,type,encrypted_size_in_bytes,key algorithm,
// keysize,hex-encoded encrypted_data|
$strEntry = "" . $entry;
$entryType = $entry->getEntryType();
fwrite($fd, "|");
fwrite($fd, $alias);
fwrite($fd, ",");
fwrite($fd, $entryType);
fwrite($fd, ",");
fwrite($fd, count($strEntry));
fwrite($fd, ",");
switch ($entryType) {
case Crypt_KeyStore_BaseEntry::PRIVATEKEY_TYPE:
$algo = $entry->getPrivateKey()->getAlgorithm();
$keysize = $entry->getPrivateKey()->getSize();
break;
case Crypt_KeyStore_BaseEntry::SECRETKEY_TYPE:
$algo = $entry->getSecretKey()->getAlgorithm();
$keysize = $entry->getSecretKey()->getSize();
break;
case Crypt_KeyStore_BaseEntry::TRUSTEDCERT_TYPE:
$algo = '';
$keysize = 0;
break;
}
fwrite($fd, $algo);
fwrite($fd, ",");
fwrite($fd, $keysize);
fwrite($fd, ",");
fwrite($fd, bin2hex(mcrypt_generic($td, $strEntry)));
fwrite($fd, "|");
}
/* Terminate encryption handler */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
// close file desc
fclose($fd);
} catch (Crypt_KeyStore_Exception $e) {
throw $e;
} catch (Exception $e) {
// general exception handler
throw new Crypt_KeyStore_Exception($e);
}
return;
}
/**
* Hashes a password and returns the hash based on the specified enc_type.
*
* @param string The password to hash in clear text.
* @param string Standard LDAP encryption type which must be one of
* crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, sha512, or clear.
* @return string The hashed password.
*/
function pla_password_hash($password_clear, $enc_type)
{
if (DEBUG_ENABLED && (($fargs = func_get_args()) || ($fargs = 'NOARGS'))) {
debug_log('Entered (%%)', 1, 0, __FILE__, __LINE__, __METHOD__, $fargs);
}
$enc_type = strtolower($enc_type);
switch ($enc_type) {
case 'blowfish':
if (!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) {
error(_('Your system crypt library does not support blowfish encryption.'), 'error', 'index.php');
}
# Hardcoded to second blowfish version and set number of rounds
$new_value = sprintf('{CRYPT}%s', crypt($password_clear, '$2a$12$' . random_salt(13)));
break;
case 'crypt':
if ($_SESSION[APPCONFIG]->getValue('password', 'no_random_crypt_salt')) {
$new_value = sprintf('{CRYPT}%s', crypt($password_clear, substr($password_clear, 0, 2)));
} else {
$new_value = sprintf('{CRYPT}%s', crypt($password_clear, random_salt(2)));
}
break;
case 'ext_des':
# Extended des crypt. see OpenBSD crypt man page.
if (!defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0) {
error(_('Your system crypt library does not support extended DES encryption.'), 'error', 'index.php');
}
$new_value = sprintf('{CRYPT}%s', crypt($password_clear, '_' . random_salt(8)));
break;
case 'k5key':
$new_value = sprintf('{K5KEY}%s', $password_clear);
system_message(array('title' => _('Unable to Encrypt Password'), 'body' => 'phpLDAPadmin cannot encrypt K5KEY passwords', 'type' => 'warn'));
break;
case 'md5':
$new_value = sprintf('{MD5}%s', base64_encode(pack('H*', md5($password_clear))));
break;
case 'md5crypt':
if (!defined('CRYPT_MD5') || CRYPT_MD5 == 0) {
error(_('Your system crypt library does not support md5crypt encryption.'), 'error', 'index.php');
}
$new_value = sprintf('{CRYPT}%s', crypt($password_clear, '$1$' . random_salt(9)));
break;
case 'sha':
# Use php 4.3.0+ sha1 function, if it is available.
if (function_exists('sha1')) {
$new_value = sprintf('{SHA}%s', base64_encode(pack('H*', sha1($password_clear))));
} elseif (function_exists('mhash')) {
$new_value = sprintf('{SHA}%s', base64_encode(mhash(MHASH_SHA1, $password_clear)));
} else {
error(_('Your PHP install does not have the mhash() function. Cannot do SHA hashes.'), 'error', 'index.php');
}
break;
case 'ssha':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double) microtime() * 1000000);
$salt = mhash_keygen_s2k(MHASH_SHA1, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
$new_value = sprintf('{SSHA}%s', base64_encode(mhash(MHASH_SHA1, $password_clear . $salt) . $salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'), 'error', 'index.php');
}
break;
case 'smd5':
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
mt_srand((double) microtime() * 1000000);
$salt = mhash_keygen_s2k(MHASH_MD5, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
$new_value = sprintf('{SMD5}%s', base64_encode(mhash(MHASH_MD5, $password_clear . $salt) . $salt));
} else {
error(_('Your PHP install does not have the mhash() or mhash_keygen_s2k() function. Cannot do S2K hashes.'), 'error', 'index.php');
}
break;
case 'sha512':
if (function_exists('openssl_digest') && function_exists('base64_encode')) {
$new_value = sprintf('{SHA512}%s', base64_encode(openssl_digest($password_clear, 'sha512', true)));
} else {
error(_('Your PHP install doest not have the openssl_digest() or base64_encode() function. Cannot do SHA512 hashes. '), 'error', 'index.php');
}
break;
case 'clear':
default:
$new_value = $password_clear;
}
return $new_value;
}
/**
* Returns a salt for the appropriate kind of password encryption.
* Optionally takes a seed and a plaintext password, to extract the seed
* of an existing password, or for encryption types that use the plaintext
* in the generation of the salt.
*
* @param string $encryption The kind of password encryption to use.
* Defaults to md5-hex.
* @param string $seed The seed to get the salt from (probably a
* previously generated password). Defaults to
* generating a new seed.
* @param string $plaintext The plaintext password that we're generating
* a salt for. Defaults to none.
*
* @return string The generated or extracted salt.
*
* @since 11.1
* @note Default $encryption will be changed to 'bcrypt' in CMS 3.2 and will at
* the type used by the PHP PASSWORD_DEFAULT constant until 5.5 is the minimum
* version required. At that point the default will be PASSWORD_DEFAULT.
*/
public static function getSalt($encryption = 'md5-hex', $seed = '', $plaintext = '')
{
// Encrypt the password.
switch ($encryption) {
case 'crypt':
case 'crypt-des':
if ($seed) {
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 2);
} else {
return substr(md5(mt_rand()), 0, 2);
}
break;
case 'sha256':
if ($seed) {
return preg_replace('|^{sha256}|i', '', $seed);
} else {
return static::genRandomPassword(16);
}
break;
case 'crypt-md5':
if ($seed) {
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 12);
} else {
return '$1$' . substr(md5(JCrypt::genRandomBytes()), 0, 8) . '$';
}
break;
case 'crypt-blowfish':
if ($seed) {
return substr(preg_replace('|^{crypt}|i', '', $seed), 0, 16);
} else {
return '$2$' . substr(md5(JCrypt::genRandomBytes()), 0, 12) . '$';
}
break;
case 'ssha':
if ($seed) {
return substr(preg_replace('|^{SSHA}|', '', $seed), -20);
} else {
return mhash_keygen_s2k(MHASH_SHA1, $plaintext, substr(pack('h*', md5(JCrypt::genRandomBytes())), 0, 8), 4);
}
break;
case 'smd5':
if ($seed) {
return substr(preg_replace('|^{SMD5}|', '', $seed), -16);
} else {
return mhash_keygen_s2k(MHASH_MD5, $plaintext, substr(pack('h*', md5(JCrypt::genRandomBytes())), 0, 8), 4);
}
break;
case 'aprmd5':
/* 64 characters that are valid for APRMD5 passwords. */
$APRMD5 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($seed) {
return substr(preg_replace('/^\\$apr1\\$(.{8}).*/', '\\1', $seed), 0, 8);
} else {
$salt = '';
for ($i = 0; $i < 8; $i++) {
$salt .= $APRMD5[rand(0, 63)];
}
return $salt;
}
break;
// BCrypt is aliased because a BCrypt has may be requested when it is not present, and so it falls back to
// the default behavior of generating a salt.
// BCrypt is aliased because a BCrypt has may be requested when it is not present, and so it falls back to
// the default behavior of generating a salt.
case 'bcrypt':
default:
$salt = '';
if ($seed) {
$salt = $seed;
}
return $salt;
break;
}
}
请发表评论