PHP Conference Japan 2024

mcrypt_module_open

(PHP 4 >= 4.0.2, PHP 5, PHP 7 < 7.2.0, PECL mcrypt >= 1.0.0)

mcrypt_module_open開啟要使用的演算法和模式的模組

警告

此函式在 PHP 7.1.0 已被棄用,並在 PHP 7.2.0 中移除。強烈不建議依賴此函式。

說明

mcrypt_module_open(
    string $algorithm,
    string $algorithm_directory,
    string $mode,
    string $mode_directory
): resource

此函式開啟要使用的演算法和模式的模組。演算法的名稱在 algorithm 中指定,例如 "twofish",或是 MCRYPT_ciphername 常數之一。模組透過呼叫 mcrypt_module_close() 關閉。

參數

algorithm

MCRYPT_ciphername 常數之一,或演算法名稱(字串)。

algorithm_directory

algorithm_directory 參數用於定位加密模組。當您提供目錄名稱時,將會使用它。當您將其設定為空字串("")時,將會使用 php.ini 指令 mcrypt.algorithms_dir 設定的值。如果未設定,則使用的預設目錄是編譯到 libmcrypt 中的目錄(通常是 /usr/local/lib/libmcrypt)。

mode

MCRYPT_MODE_modename 常數之一,或以下字串之一:"ecb"、"cbc"、"cfb"、"ofb"、"nofb" 或 "stream"。

mode_directory

mode_directory 參數用於定位加密模組。當您提供目錄名稱時,將會使用它。當您將其設定為空字串("")時,將會使用 php.ini 指令 mcrypt.modes_dir 設定的值。如果未設定,則使用的預設目錄是編譯到 libmcrypt 中的目錄(通常是 /usr/local/lib/libmcrypt)。

傳回值

正常情況下,它會傳回一個加密描述符,如果發生錯誤,則傳回 false

範例

範例 #1 mcrypt_module_open() 範例

<?php
$td
= mcrypt_module_open(MCRYPT_DES, '',
MCRYPT_MODE_ECB, '/usr/lib/mcrypt-modes');

$td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
?>

上述範例的第一行將嘗試從預設目錄開啟 DES 密碼,並從 /usr/lib/mcrypt-modes 目錄開啟 ECB 模式。第二個範例使用字串作為密碼和模式的名稱,只有在擴充功能連結到 libmcrypt 2.4.x 或 2.5.x 時才有效。

範例 #2 在加密中使用 mcrypt_module_open()

<?php
/* 開啟密碼 */
$td = mcrypt_module_open('rijndael-256', '', 'ofb', '');

/* 建立 IV 並確定金鑰大小長度,在 Windows 上使用 MCRYPT_RAND
* 代替 */
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
$ks = mcrypt_enc_get_key_size($td);

/* 建立金鑰(僅限範例:MD5 不是適合此用途的雜湊演算法) */
$key = substr(hash('md5', 'very secret key'), 0, $ks);

/* 初始化加密 */
mcrypt_generic_init($td, $key, $iv);

/* 加密資料 */
$encrypted = mcrypt_generic($td, 'This is very important data');

/* 終止加密處理常式 */
mcrypt_generic_deinit($td);

/* 初始化解密加密模組 */
mcrypt_generic_init($td, $key, $iv);

/* 解密加密字串 */
$decrypted = mdecrypt_generic($td, $encrypted);

/* 終止解密處理常式並關閉模組 */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

/* 顯示字串 */
echo trim($decrypted) . "\n";
?>

參見

新增註解

使用者提供的註解 7 則註解

匿名
21 年前
執行 trim($decrypted) 將會移除解密後可能發生的 Null 填充。

問題是,如果您加密的內容像是 MSWord 文件,它通常會以 Null 結尾。結果 $decrypted 將會小於原始明文,因此在 MSOffice 中開啟會失敗。

為了解決這個問題,請確保儲存原始明文的長度,並且在解密時執行以下操作:

$decrypted = substr(mdecrypt_generic($td, $encrypted), 0, $originalLength);
Mark
12 年前
對於像這樣的錯誤:
' mcrypt_module_open(): 無法在 '' 中開啟加密模組 '

請確保您使用正確的名稱。提供密碼清單的頁面不是表示每個密碼的正確方式(此處顯示:https://php.dev.org.tw/manual/en/mcrypt.ciphers.php)。

為了查看支援哪些密碼,請嘗試 phpinfo(); 並在 mcrypt 下尋找類似這樣的內容:

mcrypt 支援 => 已啟用
mcrypt_filter 支援 => 已啟用
版本 => 2.5.8
Api 編號 => 20021217
支援的加密演算法 => cast-128 gost rijndael-128 twofish arcfour cast-256 loki97 rijndael-192 saferplus wake blowfish-compat des rijndael-256
serpent xtea blowfish enigma rc2 tripledes
支援的模式 => cbc cfb ctr ecb ncfb nofb ofb stream
dinamic at gmail dot com
17 年前
還應指出,在為 mcrypt 建立金鑰時,不應使用 md5() 和/或 sha1()。這是因為十六進位編碼僅使用一組 16 個字元 [0-9a-f],相當於 4 位元,因此會使您的加密強度減半:4 x 32 = 128 位元。

我已重新編寫了顯示的範例,因此以下是我的建議,以獲得真正的 256 位元加密

<?php
$key1
= "this is a secret key";
$key2 = "this is the second secret key";
$input = "Let us meet at 9 o'clock at the secret place.";
$length = strlen($input);

/* 開啟加密演算法 */
$td = mcrypt_module_open('rijndael-256', '', 'cbc', '');

/* 建立初始化向量 (IV) 並確定金鑰大小長度,在 Windows 上使用 MCRYPT_RAND 取代 */
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$ks = mcrypt_enc_get_key_size($td);

/* 建立金鑰 */
$key1 = md5($key1);
$key2 = md5($key2);

$key = substr($key1, 0, $ks/2) . substr(strtoupper($key2), (round(strlen($key2) / 2)), $ks/2);

$key = substr($key.$key1.$key2.strtoupper($key1),0,$ks);

/* 初始化加密 */
mcrypt_generic_init($td, $key, $iv);

/* 加密資料 */
$encrypted = mcrypt_generic($td, $input);

/* 終止加密處理 */
mcrypt_generic_deinit($td);

/* 初始化解密模組 */
mcrypt_generic_init($td, $key, $iv);

/* 解密加密的字串 */
$decrypted = mdecrypt_generic($td, $encrypted);

/* 終止解密處理並關閉模組 */
mcrypt_generic_deinit($td);
mcrypt_module_close($td);

/* 顯示字串 */
echo "Text: ".substr($decrypted,0,$length) . "<br>";
echo
"Encoded: ".$encrypted ."<br>";
echo
"<br>key1: $key1 <br>key2: $key2<br>created key: $key";
?>
royconejo
15 年前
關於先前關於使用十六進位格式和大小寫來改進金鑰的評論

這似乎很明顯,但選擇僅限於十六進位字元 ([0-9a-z]);您可以從 md5() 或 sha1() 取得原始 RAW 輸出,而不是預設的可讀十六進位格式。

原始輸出的結果將是 16 或 20 個(取決於使用的雜湊函數)範圍在 0-255 的字元序列。比 [0-9a-z] 甚至 [0-9a-zA-Z] 好得多。

16 或 20 通常低於最大金鑰長度(範例中的 $ks),但您可以將兩個或多個金鑰附加在一起

<?php
$human_key1
= 'something very secret';
$human_key2 = 'something else very secret';

// 使用兩個「人類可讀」金鑰和 sha1 的 40 位元組二進位金鑰。
$bigger_binary_key = sha1($human_key1, true) . sha1($human_key2, true);

// 然後像您會做的那樣使用它(從範例中提取)
$key = substr($bigger_binary_key, 0, $ks);
?>

...或者您可以自動將一個大型「人類金鑰」分成兩個或多個部分,使用 sha1(原始輸出!)雜湊這些部分,然後將它們再次合併在一起(以原始順序或重新排列、加鹽、根據您的喜好轉換它們)以取得 40、60、80 或更多字元的二進位金鑰,具體取決於秘密金鑰已分割成的部分數目 =)
Anonymous
8 年前
關於使用 Windows 的 mcrypt_module_open() 錯誤的匿名後續

<?php
$M
= mcrypt_list_modes();
$A = mcrypt_list_algorithms();
foreach (
$M as $m)
foreach (
$A as $a) {
$t = @mcrypt_module_open($a,'',$m,'');
print
"$m, $a = ";
print (
$t)?"ok":"nope";
print
"<br>";
}
?>

這將顯示並非所有模式都適用於所有演算法。Cygwin 也沒有 'libmcrypt.dll',它也只能使用某些組合。

(第一次嘗試恰好是其中一個不起作用的!)
lehmann*at*arcor-so.net
15 年前
請記住,mcrypt 函數不實作像 pkcs#5 之類的填充。這會導致結尾處出現零位元組的問題,並且無法在其他環境中正確解碼字串。

有關如何新增 pkcs 5 填充的範例,請參閱 ref.mcrypt.php
ash
16 年前
稍微改進 dinamic 建立金鑰的函數

我認為弱點是字串的同一部分始終使用大寫字母。以下程式碼會將字串的隨機字元大寫,使金鑰更難預測

<?php
$key
= substr($key1, 0, $ks/2) . substr($key2, (round(strlen($key2) / 2)), $ks/2);
$key = substr($key.$key1.$key2.$key1,0,$ks);

$buffer = str_split($key);

$limit = count($buffer)-1;
srand((float)microtime() * 1000000);

$end = rand(0, $limit);
$a = 0;

// replace random chars with capitals
while ($a < $end) {
list(
$usec, $sec) = explode(' ', microtime());
$seed = ((float)$sec) + ((float) $usec * 100000);
mt_srand($seed);

$index = mt_rand(0,$limit);

$buffer[$index] = strtoupper($buffer[$index]);
$a++;
}

$key = join('', $buffer);
?>
To Top