openssl_seal

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

openssl_seal密封(加密)数据

说明

openssl_seal(
    #[\SensitiveParameter] string $data,
    string &$sealed_data,
    array &$encrypted_keys,
    array $public_key,
    string $cipher_algo,
    string &$iv = null
): int|false

openssl_seal() 使用给定的 cipher_algo 和随机生成的密钥来密封(加密)data。该密钥使用 public_key 中标识符关联的每个公钥进行加密,每个加密的密钥都返回在 encrypted_keys 中。这意味着可以将密封数据发送给多个接收者(前提是已获得他们的公钥)。每个接收者必须同时接收密封数据和用接收者公钥加密的信封密钥。

参数

data

要密封的数据。

sealed_data

密封后的数据。

encrypted_keys

加密密钥数组。

public_key

OpenSSLAsymmetricKey 实例的数组,包含公钥。

cipher_algo

密码方法。

注意

默认值 ('RC4') 被认为是不安全的。强烈建议显式指定安全密码方法。

iv

初始化向量。

返回值

成功时返回密封数据的长度,出错时返回 false。如果成功,密封后的数据将返回到 sealed_data 中,信封密钥将返回到 encrypted_keys 中。

变更日志

版本 说明
8.0.0 public_key 现在接受 arrayOpenSSLAsymmetricKey 实例;以前,接受 arrayresource 类型为 OpenSSL key
8.0.0 cipher_algo 不再是可选参数。
8.0.0 iv 现在可以为空。

范例

范例 #1 openssl_seal() 范例

<?php
// 假设 $data 包含要密封的数据

// 获取接收者的公钥并准备它们
$fp = fopen("/src/openssl-0.9.6/demos/maurice/cert.pem", "r");
$cert = fread($fp, 8192);
fclose($fp);
$pk1 = openssl_get_publickey($cert);
// 对第二个接收者重复
$fp = fopen("/src/openssl-0.9.6/demos/sign/cert.pem", "r");
$cert = fread($fp, 8192);
fclose($fp);
$pk2 = openssl_get_publickey($cert);

// 密封消息,只有 $pk1 和 $pk2 的所有者才能分别使用密钥 $ekeys[0] 和 $ekeys[1] 解密 $sealed。
openssl_seal($data, $sealed, $ekeys, array($pk1, $pk2));

// 从内存中释放密钥
openssl_free_key($pk1);
openssl_free_key($pk2);
?>

参见

添加注释

用户贡献注释 6 个注释

Dominik M.
3 年前
请注意,openssl_seal() 不能用于 EC 加密。
我花了整整两个小时才发现这一点,因为 OpenSSL 文档太糟糕了。
amer.alhabsi AT gmail DOT com
8 年前
虽然默认使用 RC4,但可以使用其他更安全的算法。这些算法在第五个参数中指定。此外,还需要添加初始化向量(随机字节)。例如:

<?php
$data
= "This is top secret.";
// 获取接收者的公钥并准备它们
$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
2 年前
一些文档中没有或其他地方没有广泛说明的关键细节。

- 信封密钥是 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
8 年前
根据多个来源(例如 crypto101.io 或维基百科),RC4 不安全,不应再使用。
因此,openssl_seal 是否应该使用另一个流密码来代替 RC4?
hfuecks at nospam dot org
16 年前
当您需要将数据安全地传递到其他平台/语言时,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