我尝试使用 PHP 7.4 Sodium 加密消息。
此功能:
sodium_crypto_box_seal('Hello World', $pemPublicKey);
返回错误:
“参数 2 必须为 CRYPTO_BOX_PUBLICKEYBYTES 长。”
$pemPublicKey 存储在文件 public33.pem 中,我像这样检索它:
$pemPublicKey = file_get_contents(PEM_FILES_PATH . '/public33.pem');
$pemPublicKey = str_replace('-----BEGIN PUBLIC KEY-----', '', $pemPublicKey);
$pemPublicKey = str_replace('-----END PUBLIC KEY-----', '', $pemPublicKey);
$pemPublicKey = trim($pemPublicKey);
$pemPublicKey = base64_decode($pemPublicKey);
$enc = sodium_crypto_box_seal('Hello World', $pemPublicKey);
public33.pem 文件的内容是:
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA5d3iW1eV66LJbBub+hrZinr2Uky6RfqYG3VNxQnCl4U=
-----END PUBLIC KEY-----
我已经检查过,文件内容读取正确。 主密钥和公钥文件是这样创建的:
1. openssl genpkey -algorithm Ed25519 -out private33.bin
2. openssl pkey -in private33.pem -pubout -out public33.pem
我被困住了,不知道该往哪里看。
sodium_crypto_box_seal()
不需要 X.509/SPKI 格式的 PEM 公钥,而是原始的 32 字节公钥。您可以从 PEM 公钥中提取该密钥作为 Base64 解码主体的最后 32 个字节。
但是,您为
sodium_crypto_box_seal()
使用了错误类型的密钥对。您不需要 Ed25519 密钥对,而是 X25519 密钥对,因此您必须调整 OpenSSL 语句并生成新密钥:
openssl genpkey -algorithm X25519 -out private33.pem
...
PHP代码:
<?php
// Encryption
$pemSPKI = "-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEACK2b1mIhIdgont5UdtboDiHQYMJlrJKjCBaWk1LbFS8=
-----END PUBLIC KEY-----";
$pemSPKI = str_replace('-----BEGIN PUBLIC KEY-----', '', $pemSPKI);
$pemSPKI = str_replace('-----END PUBLIC KEY-----', '', $pemSPKI);
$pemSPKI = trim($pemSPKI);
$derSPKI = base64_decode($pemSPKI);
$rawPublic = substr($derSPKI, -32); // Fix: extract raw public X25519 key
$ct = sodium_crypto_box_seal('Hello World', $rawPublic);
print("ciphertext: " . bin2hex($ct) . PHP_EOL);
// Decryption
$pemPkcs8 = "-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIFAjP8X4es8alPOfr7ew/JKePnBvA49xiz2R0ZxO5wBZ
-----END PRIVATE KEY-----";
$pemPkcs8 = str_replace('-----BEGIN PRIVATE KEY-----', '', $pemPkcs8);
$pemPkcs8 = str_replace('-----END PRIVATE KEY-----', '', $pemPkcs8);
$pemPkcs8 = trim($pemPkcs8);
$derPkcs8 = base64_decode($pemPkcs8);
$rawPrivate = substr($derPkcs8, -32);
$dt = sodium_crypto_box_seal_open($ct, $rawPrivate . $rawPublic);
print("decrypted: " . $dt . PHP_EOL);
?>