PHP Conference Japan 2024

openssl_seal

(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)

openssl_seal密封(加密)資料

說明

openssl_seal(
    #[\SensitiveParameter] 字串 $data,
    字串 &$sealed_data,
    陣列 &$encrypted_keys,
    陣列 $public_key,
    字串 $cipher_algo,
    字串 &$iv = null
): 整數 (int)|false

openssl_seal() 會使用指定的 cipher_algo 加密方法以及隨機產生的密鑰來封裝(加密)data。接著,密鑰會使用 public_key 陣列中的每個公鑰加密,每個加密的封裝密鑰會回傳至 encrypted_keys 中。這允許將封裝的資料傳送給多個收件者(前提是他們的公鑰可用)。每個收件者都必須收到使用收件者公鑰加密的封裝資料和封裝密鑰。系統會產生 IV(初始化向量),其值會回傳至 iv 中。

參數

data

要封裝的資料。

sealed_data

已封裝的資料。

encrypted_keys

已加密密鑰的陣列。

public_key

包含公鑰的 OpenSSLAsymmetricKey 實例陣列。

cipher_algo

加密方法。

注意事項

8.0 之前 PHP 版本的預設值是 ('RC4'),這被認為是不安全的。強烈建議明確指定安全的加密方法。

iv

用於解密 data 的初始化向量。如果加密方法需要 IV,則此參數為必需。可以透過使用 cipher_algo 呼叫 openssl_cipher_iv_length() 來確認是否需要 IV。

注意事項

IV 無法明確設定。任何設定的值都會被隨機產生的值覆寫。

回傳值

成功時回傳已封裝資料的長度,失敗時回傳 false。如果成功,已封裝的資料會回傳至 sealed_data 中,封裝密鑰會回傳至 encrypted_keys 中。

更新日誌

版本 說明
8.0.0 public_key 現在接受 OpenSSLAsymmetricKey 實例的 陣列;先前接受的是 OpenSSL key 類型 資源陣列
8.0.0 cipher_algo 不再是可選參數。
8.0.0 iv 現在可以為 null。

範例

範例 #1 openssl_seal() 範例

<?php
// $data 假設包含要被加密的資料
$data = "test";

// 取得公開金鑰
$pk1 = openssl_get_publickey("file://cert1.pem");
$pk2 = openssl_get_publickey("file://cert2.pem");

// 加密訊息,只有 $pk1 和 $pk2 的擁有者才能使用金鑰 $ekeys[0] 和 $ekeys[1] 分別解密 $sealed。
if (openssl_seal($data, $sealed, $ekeys, array($pk1, $pk2), 'AES256', $iv) > 0) {
// 可以儲存 $sealed 和 $iv 值,並稍後在 openssl_open 中使用
echo "success\n";
}
?>

另請參閱

新增註解

使用者貢獻的註解 6 則註解

Dominik M.
4 年前
請注意,openssl_seal() 無法用於 EC 加密。
我花了整整兩個小時才發現,因為 OpenSSL 的文件寫得太糟糕了。
amer.alhabsi AT gmail DOT com
8 年前
雖然預設使用 RC4,但可以使用其他更安全的演算法。這些演算法指定為第五個參數。此外,需要新增一個初始化向量(隨機位元組)。例如:

<?php
$data
= "這是最高機密。";
// 取得收件者的公鑰,並準備好
$cert = file_get_contents('./cert.pem');

$pk1 = openssl_get_publickey($cert);
$iv = openssl_random_pseudo_bytes(32);
openssl_seal($data, $sealed, $ekeys, array($pk1), "AES256", $iv);

// 從記憶體中釋放金鑰
openssl_free_key($pk1);
echo
base64_encode($sealed);
?>
aaron dot lawrence at umajin dot com
3 年前
一些文件中沒有,其他地方也鮮少提及的重要細節。

- 信封金鑰是一個隨機生成的 128 位元 RSA 金鑰。
- 資料使用信封金鑰以 (A)RC4 加密。
- 信封金鑰使用 PKCS1 v1.5 進行加密傳輸。它「不是」OAEP 填充變體。PKCS1 v1.5 更舊,而且現在已不廣泛支援。

至少我們使用的 PHP 7.2 中的 openssl_seal 是這樣。

(備註:在 Python 中,您可以使用 Cryptography 套件,搭配 padding.PKCS1v15() 來解密這個信封金鑰。)

在我看來,RC4 和 PKCS1 v1.5 的組合使得這個函式在安全性應用上實際上已半過時。
devel@no-spam
19 年前
「使用隨機產生的密鑰以 RC4 加密(封裝)資料」
應該注意的是,隨機產生的密鑰長度為 128 位元(openssl: EVP_rc4(void): RC4 串流加密法。這是一個可變金鑰長度的加密法,預設金鑰長度為 128 位元。)
bowfingermail at gmx dot net
9 年前
根據多個來源(例如 crypto101.io 或維基百科),RC4 並不安全,也不應該再使用。
那麼,openssl_seal 是否應該使用其他串流加密法來取代 RC4?
hfuecks at nospam dot org
17 年前
當您需要安全地將資料傳遞到其他平台/語言時,openssl_seal() 可以很好地運作。 openssl_seal() 的作用是:

1. 產生一個隨機金鑰
2. 使用隨機金鑰以 RC4 對稱加密資料
3. 使用公鑰/憑證以 RSA 加密隨機金鑰本身
4. 返回加密的資料和加密的金鑰

因此,解密步驟簡化為:

1. 使用 RSA 和您的私鑰解密金鑰
2. 使用 RC4 和解密後的金鑰解密資料

最棘手的部分可能是弄清楚如何處理私鑰 - BouncyCastle ( http://www.bouncycastle.org/ ) 為 Java 和 C# 提供了 PEMReader,而 Not Yet commons-ssl ( http://juliusdavies.ca/commons-ssl/ ) 則有一個 KeyStoreBuilder 可以從 PEM 憑證構建 Java 金鑰庫。

完整的 Java 範例說明於 http://blog.local.ch/archive/2007/10/29/openssl-php-to-java.html
To Top