Openssl pkcs7 encrypt: примеры (PHP)
openssl_pkcs7_encrypt(string $input_filename, string $output_filename, OpenSSLCertificate|array|string $certificate, array|null $headers, int $flags = 0, int $cipher_algo = OPENSSL_CIPHER_AES_128_CBC): boolФункция openssl_pkcs7_encrypt предназначена для шифрования сообщения с использованием сертификатов по стандарту S/MIME (PKCS #7). Основное применение - безопасная передача данных, например, шифрование электронной почты или файлов. Функция шифрует содержимое, которое может быть расшифровано только владельцем закрытого ключа, соответствующего указанному сертификату.
- input_filename (string) - путь к файлу, который содержит данные для шифрования.
- output_filename (string) - путь к файлу, в который будет записан результат шифрования.
- recipcerts (string|array) - сертификат или массив сертификатов получателей. Может быть путем к файлу, строкой с PEM-сертификатом или массивом таких значений.
- headers (array) - массив заголовков, которые добавляются в начало данных перед шифрованием. Часто используется для заголовков электронной почты.
- flags (int) - битовая маска флагов, изменяющих поведение шифрования.
- OPENSSL_PKCS7_TEXT - добавляет заголовок Content-type: text/plain и преобразует конец строки.
- OPENSSL_PKCS7_BINARY - предотвращает преобразование конца строки.
- OPENSSL_PKCS7_NOOLDMIMETYPE - использует тип application/pkcs7-mime вместо application/x-pkcs7-mime.
- cipher_algo (int) - шифр, используемый для шифрования. По умолчанию используется OPENSSL_CIPHER_AES_128_CBC. Возможные значения: OPENSSL_CIPHER_RC2_40, OPENSSL_CIPHER_RC2_128, OPENSSL_CIPHER_RC2_64, OPENSSL_CIPHER_DES, OPENSSL_CIPHER_3DES, OPENSSL_CIPHER_AES_128_CBC, OPENSSL_CIPHER_AES_192_CBC, OPENSSL_CIPHER_AES_256_CBC.
Пример 1: Базовое шифрование для одного получателя.
$data = "Конфиденциальное сообщение.";
file_put_contents('msg.txt', $data);
$cert = file_get_contents('recipient_cert.pem');
$headers = [];
$result = openssl_pkcs7_encrypt('msg.txt', 'encrypted.msg', $cert, $headers);
if ($result) {
echo "Шифрование успешно.";
} else {
echo "Ошибка шифрования.";
}
Шифрование успешно.
Пример 2: Шифрование с текстовым флагом и заголовками.
$data = "Конфиденциальное сообщение.\nНовая строка.";
file_put_contents('msg.txt', $data);
$cert = file_get_contents('recipient_cert.pem');
$headers = [
'From' => 'sender@example.com',
'To' => 'recipient@example.com',
'Subject' => 'Важное письмо'
];
$result = openssl_pkcs7_encrypt('msg.txt', 'encrypted.msg', $cert, $headers, OPENSSL_PKCS7_TEXT);
var_dump($result);
bool(true)
Пример 3: Шифрование для нескольких получателей с указанием шифра.
$certs = [
file_get_contents('recipient1_cert.pem'),
file_get_contents('recipient2_cert.pem')
];
$headers = ['Subject' => 'Множественное шифрование'];
$result = openssl_pkcs7_encrypt(
'plain.txt',
'multi_enc.msg',
$certs,
$headers,
0, // Без флагов
OPENSSL_CIPHER_AES_256_CBC
);
echo $result ? 'Успех' : 'Неудача';
Успех
Функция создает подпись PKCS #7 для указанного файла. Используется для цифровой подписи, а не для шифрования. Предпочтительна, когда требуется гарантировать целостность и аутентичность данных.
Обратная функция для расшифровки данных, зашифрованных с помощью openssl_pkcs7_encrypt. Требует закрытый ключ и сертификат получателя.
Функции для асимметричного шифрования небольших объемов данных (например, ключей сессии). Не используют формат PKCS #7. Подходят для шифрования данных в памяти, а не файлов.
Функции для симметричного шифрования с асимметричной защитой ключа. Генерируют случайный ключ, который шифруется открытым ключом каждого получателя. Более эффективны для шифрования больших данных, чем прямое асимметричное шифрование.
Выбор функции зависит от задачи. openssl_pkcs7_encrypt применяется для шифрования файлов или сообщений в стандартном формате S/MIME, часто для электронной почты. openssl_seal подходит для общего шифрования данных, когда требуется несколько получателей.
Ошибка 1: Неверный путь к файлу или отсутствие прав на чтение/запись.
$result = openssl_pkcs7_encrypt('missing.txt', 'output.msg', $cert, []);
if (!$result) {
echo openssl_error_string();
}
error:02001002:system library:fopen:No such file or directory
Ошибка 2: Некорректный или поврежденный сертификат.
$badCert = "-----BEGIN CERTIFICATE-----\nINVALID_DATA\n-----END CERTIFICATE-----";
$result = openssl_pkcs7_encrypt('msg.txt', 'output.msg', $badCert, []);
echo $result ? 'Ok' : openssl_error_string();
error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag
Ошибка 3: Попытка шифрования пустого файла.
file_put_contents('empty.txt', '');
$result = openssl_pkcs7_encrypt('empty.txt', 'output.msg', $cert, []);
var_dump($result);
bool(false)
Ошибка 4: Несовместимость флагов, например, одновременное использование OPENSSL_PKCS7_TEXT и OPENSSL_PKCS7_BINARY не имеет смысла, но не вызовет явной ошибки, а флаги будут интерпретированы согласно внутренней логике.
Для избежания ошибок стоит проверять существование файлов, валидность сертификатов с помощью openssl_x509_read и обрабатывать возвращаемое значение функции.
В PHP 8.0.0 параметр cipher_algo стал обязательным. В предыдущих версиях он был опциональным, и по умолчанию использовался OPENSSL_CIPHER_RC2_40, что считалось слабым шифром.
До PHP 8.0.0 можно было вызывать функцию без этого аргумента:
// Работало до PHP 8.0
openssl_pkcs7_encrypt('input.txt', 'output.msg', $cert, $headers);
Начиная с PHP 8.0.0, необходимо явно указывать шифр:
// PHP 8.0 и новее
openssl_pkcs7_encrypt('input.txt', 'output.msg', $cert, $headers, 0, OPENSSL_CIPHER_AES_128_CBC);
Это изменение повысило безопасность по умолчанию, заставляя разработчиков явно выбирать алгоритм шифрования. Рекомендуется использовать стойкие алгоритмы, такие как AES (OPENSSL_CIPHER_AES_128_CBC, OPENSSL_CIPHER_AES_256_CBC).
// Шифрование с явным указанием шифра и захватом вывода в переменную
$data = "Секретные данные для отчета №456.";
$inputFile = 'temp_input_' . uniqid() . '.txt';
$outputFile = 'temp_output_' . uniqid() . '.msg';
file_put_contents($inputFile, $data);
$cert = file_get_contents('recipient_cert.pem');
$headers = [
'Content-Type' => 'text/plain; charset=utf-8',
'X-Priority' => '1'
];
$success = openssl_pkcs7_encrypt(
$inputFile,
$outputFile,
$cert,
$headers,
OPENSSL_PKCS7_TEXT,
OPENSSL_CIPHER_AES_256_CBC
);
if ($success) {
$encryptedContent = file_get_contents($outputFile);
echo "Зашифрованное содержимое (первые 500 символов):\n";
echo htmlspecialchars(substr($encryptedContent, 0, 500)) . '...';
} else {
echo "Ошибка: " . openssl_error_string();
}
// Удаление временных файлов
unlink($inputFile);
unlink($outputFile);
Зашифрованное содержимое (первые 500 символов): MIME-Version: 1.0 Content-Disposition: attachment; filename="smime.p7m" Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHA6CAMIACAQAxggHXMIIB0wIBADCBpjCBmjELMAkGA1UEBhMCUlUxETAPBgNV BAgMCNCa0LvRjtC60LAxFDASBgNVBAcMC9CQ0L3QuNC80LAxGzAZBgNVBAoMEtCf0YDQvtGC0LXQ...
// Сначала шифруем, затем подписываем уже зашифрованный файл (реже наоборот).
$plainFile = 'document.txt';
$encryptedFile = 'encrypted.msg';
$signedFile = 'encrypted_signed.msg';
file_put_contents($plainFile, "Важный документ.");
// 1. Шифрование
$certEnc = file_get_contents('recipient_cert.pem');
$encResult = openssl_pkcs7_encrypt($plainFile, $encryptedFile, $certEnc, [], 0, OPENSSL_CIPHER_AES_128_CBC);
// 2. Подпись зашифрованного файла (отправителем)
$signerCert = file_get_contents('sender_cert.pem');
$signerKey = file_get_contents('sender_key.pem');
$signResult = openssl_pkcs7_sign($encryptedFile, $signedFile, $signerCert, [$signerKey], [], PKCS7_DETACHED);
echo "Шифрование: " . ($encResult ? 'OK' : 'FAIL') . "\n";
echo "Подпись: " . ($signResult ? 'OK' : 'FAIL') . "\n";
Шифрование: OK Подпись: OK
// Шифрование бинарного файла с флагом OPENSSL_PKCS7_BINARY
$binaryData = file_get_contents('image.jpg'); // Или любой бинарный контент
$inputBin = 'bin_input.dat';
$outputBin = 'bin_encrypted.msg';
file_put_contents($inputBin, $binaryData);
$cert = file_get_contents('recipient_cert.pem');
$headers = [
'Content-Description' => 'Encrypted Image',
'Content-Disposition' => 'attachment; filename="image.jpg"'
];
// Важно использовать OPENSSL_PKCS7_BINARY
$result = openssl_pkcs7_encrypt(
$inputBin,
$outputBin,
$cert,
$headers,
OPENSSL_PKCS7_BINARY,
OPENSSL_CIPHER_AES_128_CBC
);
if ($result) {
$size = filesize($outputBin);
echo "Файл зашифрован. Размер выходного файла: $size байт";
}
Файл зашифрован. Размер выходного файла: 3427 байт
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
# В Python нет прямой аналогии PKCS#7, обычно используют CMS (Cryptographic Message Syntax)
# или комбинируют шифрование. Пример гибридного шифрования:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os
# Генерация сессионного ключа
session_key = os.urandom(32)
# Загрузка сертификата получателя
with open("recipient_cert.pem", "rb") as cert_file:
cert = load_pem_public_key(cert_file.read())
# Шифрование сессионного ключа
encrypted_key = cert.encrypt(
session_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# Далее сессионным ключом шифруют данные симметричным алгоритмом (AES).
// Использование библиотеки 'node-forge' для работы с PKCS#7
const forge = require('node-forge');
// Шифрование аналогично, но API отличается.
// Пример создания CMS-сообщения (аналог PKCS#7):
const p7 = forge.pkcs7.createEnvelopedData();
p7.addRecipient(certificate);
p7.content = forge.util.createBuffer('Конфиденциальное сообщение.');
p7.encrypt();
const encrypted = forge.pkcs7.messageToPem(p7);
Openssl pkcs7 encrypt в MySQL
В MySQL нет встроенной функции для асимметричного шифрования в формате PKCS #7. Для шифрования данных обычно используются симметричные функции, такие как AES_ENCRYPT, или функции для работы с SSL-сертификатами на уровне соединения.
Основные отличия от PHP функции: в Python и JavaScript часто используется более низкоуровневый подход или библиотеки, реализующие стандарт CMS (преемник PKCS #7). Процесс часто разделяется на шифрование сессионного ключа и данных.