Openssl pkcs7 decrypt: примеры (PHP)

Расшифровка PKCS7 в PHP: функция openssl_pkcs7_decrypt
Раздел: Шифрование (OpenSSL)
openssl_pkcs7_decrypt(string $input_filename, string $output_filename, OpenSSLCertificate|string $certificate, OpenSSLAsymmetricKey|OpenSSLCertificate|array|string|null $private_key = null): bool

Функция openssl_pkcs7_decrypt

Функция openssl_pkcs7_decrypt() предназначена для расшифровки сообщения, которое было зашифровано по стандарту S/MIME (PKCS#7). Она применяется в задачах обработки защищенной электронной почты, расшифровки данных, подписанных цифровыми сертификатами, и в системах, где требуется работа с криптографическими контейнерами формата PKCS7.

Аргументы функции

Функция принимает четыре аргумента:

  1. $input_filename (string) – путь к файлу, содержащему зашифрованное сообщение в формате PKCS7.
  2. $output_filename (string) – путь к файлу, в который будет записан результат расшифровки.
  3. $certificate (mixed) – сертификат X.509 (может быть строкой с данными или путем к файлу), соответствующий закрытому ключу, который использовался для шифрования.
  4. $private_key (mixed) – закрытый ключ, соответствующий сертификату. Может быть строкой, ресурсом или массивом, содержащим ключ и пароль.
Необязательные параметры

В версиях PHP до 8.0 функция имела пятый необязательный параметр $encoding, который указывал кодировку входных данных (например, OPENSSL_ENCODING_SMIME, OPENSSL_ENCODING_DER, OPENSSL_ENCODING_PEM). Начиная с PHP 8.0.0, этот параметр удален, а функция автоматически определяет кодировку.

Примеры использования

Базовый пример расшифровки
<?php
// Пути к файлам
$encryptedFile = 'encrypted.p7m';
$decryptedFile = 'decrypted.txt';
$certificate = 'cert.pem';
$privateKey = 'private.pem';

// Расшифровка
$result = openssl_pkcs7_decrypt($encryptedFile, $decryptedFile, $certificate, $privateKey);

if ($result) {
    echo 'Файл успешно расшифрован.';
} else {
    echo 'Ошибка при расшифровке.';
}
?>
Файл успешно расшифрован.
Использование строкового сертификата и ключа
<?php
$encryptedData = file_get_contents('encrypted.p7m');
$tempInput = tempnam(sys_get_temp_dir(), 'enc');
file_put_contents($tempInput, $encryptedData);

$cert = '-----BEGIN CERTIFICATE-----...';
$key = '-----BEGIN PRIVATE KEY-----...';

$result = openssl_pkcs7_decrypt($tempInput, 'output.txt', $cert, $key);

if ($result) {
    echo 'Успешно';
}
unlink($tempInput);
?>
Успешно

Похожие функции в PHP

Функция для шифрования данных в формат PKCS7. Она является парной к openssl_pkcs7_decrypt и используется на этапе подготовки зашифрованных сообщений.

openssl_pkcs7_sign и openssl_pkcs7_verify

Эти функции предназначены для создания и проверки цифровых подписей в формате PKCS7. Их используют в случаях, когда требуется обеспечить целостность и аутентификацию данных, а не конфиденциальность.

Функция для расшифровки данных, зашифрованных открытым ключом. Она работает с сырыми данными, а не с контейнерами PKCS7, и подходит для простых сценариев шифрования небольших блоков данных.

Выбор функции зависит от формата данных. Для работы с S/MIME сообщениями и готовыми PKCS7 контейнерами используют openssl_pkcs7_decrypt, а для низкоуровневых операций – openssl_private_decrypt.

Типичные ошибки

Неверный путь к файлу
<?php
$result = openssl_pkcs7_decrypt('nonexistent.p7m', 'out.txt', 'cert.pem', 'key.pem');
if (!$result) {
    echo 'Ошибка: не удается открыть файл для чтения';
}
?>
Ошибка: не удается открыть файл для чтения
Неправильный закрытый ключ
<?php
// Использование ключа, не соответствующего сертификату
$result = openssl_pkcs7_decrypt('encrypted.p7m', 'out.txt', 'correct_cert.pem', 'wrong_key.pem');
var_dump($result); // false
?>
bool(false)
Некорректный формат PKCS7
<?php
// Передача обычного текстового файла вместо PKCS7
file_put_contents('plain.txt', 'Not encrypted data');
$result = openssl_pkcs7_decrypt('plain.txt', 'out.txt', 'cert.pem', 'key.pem');
var_dump($result);
?>
bool(false)

Для диагностики ошибок можно использовать функцию openssl_error_string() для получения подробного сообщения от библиотеки OpenSSL.

Изменения в версиях PHP

PHP 8.0.0

Удален параметр $encoding. Функция теперь автоматически определяет кодировку входных данных. Это изменение упрощает использование функции, но требует обновления кода, который явно передавал этот параметр в более ранних версиях PHP.

Предыдущие версии

В PHP 7.2 была улучшена обработка ошибок, связанных с некорректными сертификатами. Начиная с PHP 5.0, функция стабильно присутствует в расширении OpenSSL.

Расширенные примеры

Расшифровка с паролем для ключа
Пример php
<?php
// Закрытый ключ защищен паролем
$privateKey = ['file://private.pem', 'my_password'];

$result = openssl_pkcs7_decrypt('encrypted.p7m', 'decrypted.txt', 'cert.pem', $privateKey);
var_dump($result);
?>
bool(true)
Обработка вложенных S/MIME сообщений
Пример php
<?php
// Если PKCS7 контейнер содержит вложенные структуры
$tempDir = sys_get_temp_dir();
$encryptedFile = 'nested.p7m';
$outputFile = $tempDir . '/decrypted_part.txt';

if (openssl_pkcs7_decrypt($encryptedFile, $outputFile, 'cert.pem', 'key.pem')) {
    $content = file_get_contents($outputFile);
    // Проверка, является ли результат новым PKCS7 контейнером
    if (strpos($content, '-----BEGIN PKCS7-----') !== false) {
        // Повторная расшифровка
        $secondStage = $tempDir . '/final.txt';
        $tempInput = $tempDir . '/intermediate.p7m';
        file_put_contents($tempInput, $content);
        openssl_pkcs7_decrypt($tempInput, $secondStage, 'cert.pem', 'key.pem');
    }
}
?>
// Результат зависит от структуры исходного файла
Чтение результата без сохранения в файл
Пример php
<?php
// Использование временного файла для получения данных
$tempOutput = tempnam(sys_get_temp_dir(), 'dec');

if (openssl_pkcs7_decrypt('message.p7m', $tempOutput, $cert, $key)) {
    $decryptedContent = file_get_contents($tempOutput);
    echo $decryptedContent;
}
unlink($tempOutput);
?>
Содержимое расшифрованного сообщения...
Работа с данными в памяти (через потоки)
Пример php
<?php
// Через php://memory
$encrypted = file_get_contents('data.p7m');
file_put_contents('php://memory', $encrypted);
// Требуется использование временного файла, так как функция ожидает путь к файлу
// Прямая работа с памятью не поддерживается функцией.
?>
// Этот подход демонстрирует ограничение функции

Альтернативы в других языках

Python (cryptography)
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives import serialization
from cryptography import x509
import base64

# Загрузка ключа и сертификата
with open('private.pem', 'rb') as f:
    private_key = load_pem_private_key(f.read(), password=None)

with open('cert.pem', 'rb') as f:
    cert = x509.load_pem_x509_certificate(f.read())

# В Python для PKCS7 часто используют внешние библиотеки, например, pyOpenSSL или asn1crypto
# Пример с pyOpenSSL:
# from OpenSSL.crypto import FILETYPE_PEM, load_pkcs7_data
# ...
print('Аналогичные операции требуют дополнительных библиотек')
Аналогичные операции требуют дополнительных библиотек
JavaScript (Node.js с библиотекой node-forge)
const fs = require('fs');
const forge = require('node-forge');

// Чтение данных
const p7msg = fs.readFileSync('encrypted.p7m', 'binary');
const p7 = forge.pkcs7.messageFromPem(p7msg);

// Загрузка сертификата и ключа (упрощенный пример)
// p7.decrypt(...);
console.log('В JS требуется ручной разбор структуры PKCS7 или использование специфичных библиотек.');
В JS требуется ручной разбор структуры PKCS7 или использование специфичных библиотек.
Отличия от PHP

В PHP функция openssl_pkcs7_decrypt является встроенной и предоставляет простой интерфейс для расшифровки PKCS7. В Python и JavaScript часто требуется устанавливать дополнительные библиотеки и вручную работать с форматом контейнера. Кроме того, в этих языках может потребоваться больше шагов для извлечения данных из S/MIME сообщений.

PHP openssl_pkcs7_decrypt function comments

En
Openssl pkcs7 decrypt Decrypts an S/MIME encrypted message