/** * Encrypt data returning a JSON encoded array safe for storage in a database * or file. The array has the following structure before it is encoded: * array( * 'cdata' => 'Encrypted data, Base 64 encoded', * 'iv' => 'Base64 encoded IV', * 'algo' => 'Algorythm used', * 'mode' => 'Mode used', * 'mac' => 'Message Authentication Code' * ) * * @param mixed $data * Data to encrypt. * * @param string $key * Key to encrypt data with. * * @return string * Serialized array containing the encrypted data along with some meta data. */ public function encrypt($data, $key) { /* Make sure both algorithm and mode are either block or non-block. */ $isBlockCipher = mcrypt_module_is_block_algorithm($this->_algo); $isBlockMode = mcrypt_module_is_block_algorithm_mode($this->_mode); if ($isBlockCipher !== $isBlockMode) { throw new \phpSec\Exception\InvalidAlgorithmParameterException('You can not mix block and non-block ciphers and modes'); return false; } $td = mcrypt_module_open($this->_algo, '', $this->_mode, ''); /* Check key size. */ $keySize = strlen($key); $keySizes = mcrypt_enc_get_supported_key_sizes($td); if (count($keySizes) > 0) { /* Encryption method requires a specific key size. */ if (!in_array($keySize, $keySizes)) { throw new \phpSec\Exception\InvalidKeySpecException('Key is out of range. Should be one of: ' . implode(', ', $keySizes)); return false; } } else { /* No specific size is needed. */ if ($keySize == 0 || $keySize > mcrypt_enc_get_key_size($td)) { throw new \phpSec\Exception\InvalidKeySpecException('Key is out of range. Should be between 1 and ' . mcrypt_enc_get_key_size($td) . ' bytes.'); return false; } } /* Using PBKDF with constant salts dedicated to each purpose * can securely derivce two keys from one */ $key1 = $this->pbkdf2($key, "encrypt", 1, $keySize); $key2 = $this->pbkdf2($key, "HMAC", 1, $keySize); /* Create IV. */ $rnd = $this->psl['crypt/rand']; $iv = $rnd->bytes(mcrypt_enc_get_iv_size($td)); /* Init mcrypt. */ mcrypt_generic_init($td, $key1, $iv); /* Prepeare the array with data. */ $serializedData = serialize($data); /* Enable padding of data if block cipher moode. */ if (mcrypt_module_is_block_algorithm_mode($this->_mode) === true) { $this->_padding = true; } /* Add padding if enabled. */ if ($this->_padding === true) { $block = mcrypt_enc_get_block_size($td); $serializedData = $this->pad($block, $serializedData); $encrypted['padding'] = 'PKCS7'; } $encrypted['algo'] = $this->_algo; /* Algorithm used to encrypt. */ $encrypted['mode'] = $this->_mode; /* Algorithm mode. */ $encrypted['iv'] = base64_encode($iv); /* Initialization vector, just a bunch of randomness. */ $encrypted['cdata'] = base64_encode(mcrypt_generic($td, $serializedData)); /* The encrypted data. */ $encrypted['mac'] = base64_encode($this->pbkdf2($encrypted['cdata'], $key2, 1, 32)); return json_encode($encrypted); }
/** * Checks whether the given arguments are good to be used for encryption/decryption. * * @param string $cipher * @param binary $key * @param string $operationMode * @param bool $strict Whether to true exceptions upon failure. Defaults to false. * @throws Exception * @return bool */ public static function isCipherable($cipher, $key, $operationMode, $strict = false) { // Check whether the cipher is supported. $supportedCiphers = self::getSupportedCiphers(); if (in_array($cipher, $supportedCiphers) === false) { if ($strict === true) { throw new Exception("The cipher '{$cipher}' is not supported on this system. The following is a list of supported ciphers: " . implode(', ', $supportedCiphers)); } return false; } // Check whether the block mode is supported. $supportedModes = self::getSupportedModes(); if (in_array($operationMode, $supportedModes) === false) { if ($strict === true) { throw new Exception("The block mode '{$operationMode}' is not supported on this system. The following is a list of supported operation modes: " . implode(', ', $supportedModes)); } return false; } // We discourage ECB. if ($operationMode === 'ecb') { trigger_error("You should not use 'ecb' as your block mode due to its low strength.", E_USER_WARNING); } // Make sure the key size is okay. $supportedKeySizes = mcrypt_module_get_supported_key_sizes($cipher); $keySize = strlen((string) $key); if (in_array($keySize, $supportedKeySizes) === false) { if ($strict === true) { throw new Exception("The cipher '{$cipher}' does not support a key size of '{$keySize}'. The following is a list of supported key sizes for '{$cipher}': " . implode(', ', $supportedKeySizes)); } return false; } // Make sure the person is not mixing non-block cipher modes with block ciphers and vice versa. if (mcrypt_module_is_block_algorithm($cipher) === true) { // He must be using also a block algorithm mode. if (mcrypt_module_is_block_algorithm_mode($operationMode) === false) { if ($strict === true) { throw new Exception("You cannot encrypt with a block algorithm like '{$cipher}' using a non-block algorithm mode '{$operationMode}'."); } return false; } } else { // He must be using a non-block algorithm mode. if (mcrypt_module_is_block_algorithm_mode($operationMode) === true) { if ($strict === true) { throw new Exception("You cannot encrypt with a non-block algorithm like '{$cipher}' using a block algorithm mode '{$operationMode}'."); } return false; } } }
<tr><td><b>Data to be decrypted:</b></td></tr> <tr><td>Ciphertext:</td><td><input type="text" name="ciphertext" value="<?php echo isset($_REQUEST['ciphertext']) ? $_REQUEST['ciphertext'] : ''; ?> "></td></tr> </table> <input type="submit" id="submit" name="submit" value="Go!"> </form> <div id="results"> <?php if (isset($_REQUEST['submit'])) { //Crypto time! include '../includes/environ.inc.php'; //Set cipher mode to stream if algo is a stream cipher if (mcrypt_module_is_block_algorithm($_REQUEST['algorithm'])) { $cipher_mode = $_REQUEST['cipher_mode']; } else { $cipher_mode = 'stream'; } //Decode key from hex $key = pack('H*', $_REQUEST['key']); //Create cipher descriptor $cipher_descriptor = mcrypt_module_open($_REQUEST['algorithm'], '', $cipher_mode, ''); //Apply provided IV $iv = pack('H*', $_REQUEST['static_iv']); //Initialize cipher mcrypt_generic_init($cipher_descriptor, $key, $iv); //TODO: allow other types of output encodings //Encrypt data and output it echo mdecrypt_generic($cipher_descriptor, base64_decode($_REQUEST['ciphertext']));
<?php var_dump(mcrypt_module_is_block_algorithm(MCRYPT_RIJNDAEL_128)); var_dump(mcrypt_module_is_block_algorithm(MCRYPT_DES)); var_dump(mcrypt_module_is_block_algorithm(MCRYPT_WAKE)); var_dump(mcrypt_module_is_block_algorithm(MCRYPT_XTEA));
$encrypted = mcrypt_generic($td, "This is very important data"); VERIFY($encrypted !== "This is very important data"); mcrypt_generic_deinit($td); mcrypt_generic_init($td, $key, $iv); $decrypted = mdecrypt_generic($td, $encrypted); mcrypt_generic_end($td); mcrypt_module_close($td); VS($decrypted, "This is very important data"); VERIFY(in_array("blowfish", mcrypt_list_algorithms())); VERIFY(in_array("cbc", mcrypt_list_modes())); VS(mcrypt_module_get_algo_block_size("blowfish"), 8); VS(mcrypt_module_get_algo_key_size("blowfish"), 56); VS(mcrypt_module_get_supported_key_sizes("blowfish"), array()); VS(mcrypt_module_get_supported_key_sizes("twofish"), array(16, 24, 32)); VS(mcrypt_module_is_block_algorithm_mode("cbc"), true); VS(mcrypt_module_is_block_algorithm("blowfish"), true); VS(mcrypt_module_is_block_mode("cbc"), true); VS(mcrypt_module_self_test(MCRYPT_RIJNDAEL_128), true); VS(mcrypt_module_self_test("bogus"), false); $text = "boggles the inivisble monkey will rule the world"; $key = "very secret key"; $iv_size = mcrypt_get_iv_size(MCRYPT_XTEA, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); $enc = mcrypt_encrypt(MCRYPT_XTEA, $key, $text, MCRYPT_MODE_ECB, $iv); VS(bin2hex($enc), "f522c62002fa16129c8576bcddc6dd0f7ea81991103ba42962d94c8bfff3ee660d53b187d7e989540abf5a729c2f7baf"); $crypttext = mcrypt_decrypt(MCRYPT_XTEA, $key, $enc, MCRYPT_MODE_ECB, $iv); VS($crypttext, $text); ////////////////////////////////////////////////////////////////////// $key = "123456789012345678901234567890123456789012345678901234567890"; $CC = "4007000000027"; $encrypted = mcrypt_cbc(MCRYPT_RIJNDAEL_128, substr($key, 0, 32), $CC, MCRYPT_ENCRYPT, substr($key, 32, 16));
<?php $algorithms = mcrypt_list_algorithms(); printf("%-18s %s %8s\n", "算法名", "最大支持密钥长度(字节)", "分组(block)/流式(stream)"); foreach ($algorithms as $cipher) { $max_key_size = mcrypt_module_get_algo_key_size($cipher); $stream_mode = mcrypt_module_is_block_algorithm($cipher) == TRUE ? "block" : "stream"; printf("%-18s %3d %25s\n", $cipher, $max_key_size, $stream_mode); }