Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】openssl_cms_encrypt()関数の使い方

openssl_cms_encrypt関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

openssl_cms_encrypt関数は、OpenSSL拡張の一部として、Cryptographic Message Syntax(CMS)形式でデータを暗号化するために使用される関数です。

この関数は、指定された入力データ(ファイルまたは文字列)を、一人以上の受信者の公開鍵証明書を用いて暗号化します。これにより、暗号化されたデータは、対応する秘密鍵を持つ正規の受信者のみが復号できる状態となり、データの機密性(秘匿性)を確保できます。

さらに、オプションとして送信者の秘密鍵と証明書を提供することで、暗号化と同時にデジタル署名を適用することも可能です。デジタル署名は、データの改ざんを検知し、送信者の身元を証明するために利用され、データの完全性と真正性を向上させます。

暗号化されたデータは通常、DER形式またはPEM形式のCMS構造として指定された出力ファイルに保存されます。この関数は、セキュアなファイル配布システム、機密性の高い情報交換、あるいはセキュアな電子メール通信など、高度なセキュリティ要件を持つアプリケーションにおいて重要な役割を果たします。利用にあたっては、適切な公開鍵証明書の管理と、秘密鍵の厳重な保護が不可欠です。

構文(syntax)

1openssl_cms_encrypt(string $input_filename, string $output_filename, mixed $certificate, array $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME): bool

引数(parameters)

string $input_filename, string $output_filename, mixed $certificate, mixed $headers, int $flags = 0, int $encoding = OPENSSL_ENCODING_SMIME, int $cipher_algo = OPENSSL_CIPHER_AES128_GCM

  • string $input_filename: 暗号化する元のファイル名を指定します
  • string $output_filename: 暗号化されたファイルを保存するファイル名を指定します
  • mixed $certificate: 受信者の公開鍵証明書を指定します。PEM形式の文字列またはファイルパスを指定できます
  • mixed $headers: CMSヘッダーを指定します。配列形式で、'subject'、'issuer'、'serialNumber'、'url'などのキーを持つことができます
  • int $flags = 0: 暗号化のフラグを指定します。例えば、OPENSSL_CMS_SIGNは署名を追加する場合に使用します
  • int $encoding = OPENSSL_ENCODING_SMIME: 出力ファイルのエンコーディングを指定します。デフォルトはSMIME形式です
  • int $cipher_algo = OPENSSL_CIPHER_AES128_GCM: 使用する対称暗号アルゴリズムを指定します。デフォルトはAES128_GCMです

戻り値(return)

string|false

openssl_cms_encrypt 関数は、指定されたデータと証明書を使用して CMS (Cryptographic Message Syntax) 形式の暗号化されたメッセージを生成し、その結果を文字列として返します。処理が失敗した場合は false を返します。

サンプルコード

PHPでOpenSSL CMS暗号化・復号化する

1<?php
2
3/**
4 * openssl_cms_encrypt および openssl_cms_decrypt の使用例を示す関数です。
5 *
6 * この関数は、システムエンジニアを目指す初心者の方でも理解できるよう、
7 * 自己署名証明書の生成からファイルの暗号化、復号化、そして内容の検証までの一連の流れを
8 * 簡潔なPHPコードで示します。
9 * 暗号化と復号化のペアで動作することで、セキュリティ機能の基本的な利用方法を学習できます。
10 *
11 * @return void
12 */
13function demoOpensslCmsEncryptDecrypt(): void
14{
15    echo "--- openssl_cms_encrypt/decrypt デモ開始 ---\n\n";
16
17    // 1. 一時ディレクトリとファイルのパスを定義
18    // ユニークなディレクトリ名を作成し、他のファイルと競合しないようにします。
19    $tempDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'php_cms_demo_' . uniqid();
20    if (!mkdir($tempDir) && !is_dir($tempDir)) {
21        echo "エラー: 一時ディレクトリの作成に失敗しました: {$tempDir}\n";
22        return;
23    }
24
25    $plainTextFilePath   = $tempDir . DIRECTORY_SEPARATOR . 'original_data.txt';
26    $encryptedFilePath   = $tempDir . DIRECTORY_SEPARATOR . 'encrypted_data.cms';
27    $decryptedFilePath   = $tempDir . DIRECTORY_SEPARATOR . 'decrypted_data.txt';
28    $certificateFilePath = $tempDir . DIRECTORY_SEPARATOR . 'cert.pem';
29    $privateKeyFilePath  = $tempDir . DIRECTORY_SEPARATOR . 'privkey.pem';
30
31    // 2. 暗号化する元のプレーンテキストファイルを作成
32    $originalContent = "これはOpenSSL CMS暗号化/復号化のテストデータです。\n" .
33                       "機密情報が含まれる可能性のあるデータを想定しています。\n" .
34                       "タイムスタンプ: " . date('Y-m-d H:i:s') . "\n";
35    if (file_put_contents($plainTextFilePath, $originalContent) === false) {
36        echo "エラー: 元のファイル作成に失敗しました: {$plainTextFilePath}\n";
37        cleanUp($tempDir);
38        return;
39    }
40    echo "ステップ1: 元のプレーンテキストファイルを作成しました。\n";
41    echo "  ファイルパス: {$plainTextFilePath}\n";
42    echo "  内容の一部: \"" . substr($originalContent, 0, 50) . "...\"\n\n";
43
44    // 3. CMS暗号化/復号化に必要な自己署名証明書と秘密鍵を生成
45    // 実際の運用では、認証局から発行された証明書を使用します。
46    // デモ目的のため、PHPのOpenSSL拡張機能で自己署名証明書を生成します。
47    $dn = [
48        "countryName"          => "JP",
49        "stateOrProvinceName"  => "Tokyo",
50        "localityName"         => "Shinjuku",
51        "organizationName"     => "PHP CMS Demo",
52        "organizationalUnitName" => "IT",
53        "commonName"           => "localhost",
54        "emailAddress"         => "admin@example.com",
55    ];
56
57    // 新しい秘密鍵を生成 (RSA 2048ビット)
58    $privateKey = openssl_pkey_new([
59        "private_key_bits" => 2048,
60        "private_key_type" => OPENSSL_KEYTYPE_RSA,
61    ]);
62    if (!$privateKey) {
63        echo "エラー: 秘密鍵の生成に失敗しました。\n";
64        cleanUp($tempDir);
65        return;
66    }
67
68    // 証明書署名要求 (CSR) を生成
69    $csr = openssl_csr_new($dn, $privateKey);
70    if (!$csr) {
71        echo "エラー: CSRの生成に失敗しました。\n";
72        cleanUp($tempDir);
73        return;
74    }
75
76    // CSRを自己署名して証明書を生成 (有効期限1日)
77    $certificate = openssl_csr_sign($csr, null, $privateKey, 1, [], time());
78    if (!$certificate) {
79        echo "エラー: 証明書の生成に失敗しました。\n";
80        cleanUp($tempDir);
81        return;
82    }
83
84    // 生成した証明書と秘密鍵をファイルに保存
85    if (!openssl_x509_export_to_file($certificate, $certificateFilePath)) {
86        echo "エラー: 証明書のエクスポートに失敗しました: {$certificateFilePath}\n";
87        cleanUp($tempDir);
88        return;
89    }
90    if (!openssl_pkey_export_to_file($privateKey, $privateKeyFilePath)) {
91        echo "エラー: 秘密鍵のエクスポートに失敗しました: {$privateKeyFilePath}\n";
92        cleanUp($tempDir);
93        return;
94    }
95    echo "ステップ2: 自己署名証明書と秘密鍵を生成し、保存しました。\n";
96    echo "  証明書: {$certificateFilePath}\n";
97    echo "  秘密鍵: {$privateKeyFilePath}\n\n";
98
99    // 4. openssl_cms_encrypt を使用してファイルを暗号化
100    // - `$input_filename`: 暗号化する元のファイルパス
101    // - `$output_filename`: 暗号化結果を保存するファイルパス
102    // - `$certificate`: 暗号化に使用する証明書 (ファイルパス)
103    // - `$headers`: 追加ヘッダ (今回は空配列)
104    // - `$flags`: 暗号化のオプション。
105    //    - OPENSSL_CMS_BINARY: 入力データがバイナリであることを示します。
106    //    - OPENSSL_CMS_PARTIAL: 出力にS/MIMEヘッダの一部を省略し、他のOpenSSL CMS関数との互換性を高めます。
107    // - `$encoding`: エンコーディング形式 (S/MIME形式を使用)
108    // - `$cipher_algo`: 使用する暗号アルゴリズム (AES-128 GCMを使用)
109    $encryptResult = openssl_cms_encrypt(
110        $plainTextFilePath,
111        $encryptedFilePath,
112        $certificateFilePath,
113        [],
114        OPENSSL_CMS_BINARY | OPENSSL_CMS_PARTIAL,
115        OPENSSL_ENCODING_SMIME,
116        OPENSSL_CIPHER_AES128_GCM
117    );
118
119    if ($encryptResult === false) {
120        echo "エラー: ファイルの暗号化に失敗しました。\n";
121        cleanUp($tempDir);
122        return;
123    }
124    echo "ステップ3: ファイルをCMS形式で暗号化しました。\n";
125    echo "  暗号化ファイル: {$encryptedFilePath}\n\n";
126
127    // 5. openssl_cms_decrypt を使用して暗号化されたファイルを復号化
128    // - `$input_filename`: 復号化する暗号化されたファイルパス
129    // - `$output_filename`: 復号化結果を保存するファイルパス
130    // - `$certificate`: 暗号化に使用された証明書または証明書バンドル (ファイルパス)
131    // - `$private_key`: 復号化に使用する秘密鍵 (ファイルパス)
132    $decryptResult = openssl_cms_decrypt(
133        $encryptedFilePath,
134        $decryptedFilePath,
135        $certificateFilePath,
136        $privateKeyFilePath
137    );
138
139    if ($decryptResult === false) {
140        echo "エラー: ファイルの復号化に失敗しました。\n";
141        cleanUp($tempDir);
142        return;
143    }
144    echo "ステップ4: 暗号化されたファイルを復号化しました。\n";
145    echo "  復号化ファイル: {$decryptedFilePath}\n\n";
146
147    // 6. 復号化された内容が元の内容と一致するかを検証
148    $decryptedContent = file_get_contents($decryptedFilePath);
149    if ($decryptedContent === false) {
150        echo "エラー: 復号化されたファイルの読み込みに失敗しました。\n";
151        cleanUp($tempDir);
152        return;
153    }
154
155    echo "ステップ5: 復号化された内容を検証中...\n";
156    echo "  復号化された内容の一部: \"" . substr($decryptedContent, 0, 50) . "...\"\n";
157    if ($originalContent === $decryptedContent) {
158        echo "  検証成功: 元のファイルと復号化されたファイルの内容は完全に一致します。\n\n";
159    } else {
160        echo "  検証失敗: 元のファイルと復号化されたファイルの内容が一致しません。\n\n";
161    }
162
163    echo "--- openssl_cms_encrypt/decrypt デモ完了 ---\n";
164
165    // 7. デモで生成された一時ファイルとディレクトリをクリーンアップ
166    cleanUp($tempDir);
167}
168
169/**
170 * 指定されたディレクトリとその内容を再帰的に削除するヘルパー関数です。
171 * デモで作成された一時ファイルを削除するために使用します。
172 *
173 * @param string $dirPath 削除するディレクトリのパス
174 * @return void
175 */
176function cleanUp(string $dirPath): void
177{
178    if (!is_dir($dirPath)) {
179        return;
180    }
181
182    $files = array_diff(scandir($dirPath), ['.', '..']);
183    foreach ($files as $file) {
184        $filePath = $dirPath . DIRECTORY_SEPARATOR . $file;
185        if (is_dir($filePath)) {
186            cleanUp($filePath); // ディレクトリの場合は再帰的に削除
187        } else {
188            unlink($filePath); // ファイルを削除
189        }
190    }
191    rmdir($dirPath); // 空になったディレクトリを削除
192    echo "一時ディレクトリとファイルをクリーンアップしました: {$dirPath}\n";
193}
194
195// デモ関数を実行
196demoOpensslCmsEncryptDecrypt();

PHP 8のopenssl_cms_encrypt関数は、指定されたファイルをCMS (Cryptographic Message Syntax) 形式で暗号化するために使用されます。これは、機密情報を安全に保護し、特定の受信者のみが内容を閲覧できるようにする際に利用される機能です。この関数は、$input_filenameで指定された元のファイルの内容を、$output_filenameに暗号化されたデータとして書き出します。暗号化には$certificateで指定された受信者の証明書(公開鍵)が用いられ、この証明書に対応する秘密鍵を持つユーザーだけがデータを復号できます。$headersはMIMEヘッダに追加する情報を、$flagsOPENSSL_CMS_BINARYOPENSSL_CMS_PARTIALといった暗号化の動作に関するオプションを指定します。また、$encodingでエンコード形式(S/MIMEなど)を、$cipher_algoでAES-128 GCMのような具体的な暗号アルゴリズムを選択可能です。処理が成功すると暗号化されたデータの文字列が、失敗するとfalseが戻り値として返されます。サンプルコードでは、この関数で暗号化したファイルをopenssl_cms_decrypt関数で復号する一連のプロセスを通じて、データの安全なやり取りの基本的な仕組みを学ぶことができます。

このサンプルコードは、CMS暗号化の基本的な流れを理解するのに役立ちます。特に、秘密鍵と証明書は本番環境では認証局が発行したものを利用し、厳重に管理することが重要です。openssl_cms_encryptopenssl_cms_decryptfalseを返した場合のエラー処理は必ず行い、openssl_error_string()で詳細を確認してください。ファイルの入出力パスは、適切な権限設定と一時ファイルの安全な削除を考慮し、アプリケーションの要件に合わせて慎重に指定してください。また、利用する暗号アルゴリズムは、常に最新のセキュリティガイドラインに準拠しているか確認し、選択することが推奨されます。

PHP openssl_cms_encryptでファイルをCMS暗号化する

1<?php
2
3/**
4 * openssl_cms_encrypt を使用してファイルをCMS (Cryptographic Message Syntax) 形式で暗号化します。
5 *
6 * この関数は、指定された入力ファイルをX.509証明書を用いて暗号化し、その結果をCMS形式で
7 * 出力ファイルに保存します。主に機密データの安全な転送や保存に使用されます。
8 *
9 * @param string $inputFilePath 暗号化する元のファイルのパス。
10 * @param string $outputFilePath 暗号化されたデータを保存するファイルのパス。
11 * @param string $certificatePath 暗号化に使用する受信者のX.509証明書ファイルのパス。
12 *                                  この証明書の公開鍵でデータが暗号化されます。
13 * @return bool 暗号化が成功した場合は true、失敗した場合は false を返します。
14 *              失敗時には、OpenSSLのエラーキューから詳細なエラーメッセージが出力されます。
15 */
16function encryptFileWithCms(string $inputFilePath, string $outputFilePath, string $certificatePath): bool
17{
18    // --- 事前準備と検証 ---
19    // このサンプルコードを実行するには、以下の手順でテスト用の自己署名証明書と秘密鍵を生成し、
20    // $certificatePath にその証明書ファイル (例: cert.pem) を指定してください。
21    //
22    // 1. 秘密鍵の生成:
23    //    openssl genrsa -out privkey.pem 2048
24    // 2. 自己署名証明書の生成 (鍵を使用し、CN (Common Name) は任意):
25    //    openssl req -new -x509 -key privkey.pem -out cert.pem -days 365 -subj "/CN=Test User/O=Example Corp"
26    //
27    // 生成された `cert.pem` を $certificatePath に指定してください。
28
29    if (!file_exists($inputFilePath)) {
30        echo "エラー: 入力ファイル '{$inputFilePath}' が見つかりません。\n";
31        return false;
32    }
33
34    if (!file_exists($certificatePath)) {
35        echo "エラー: 証明書ファイル '{$certificatePath}' が見つかりません。\n";
36        return false;
37    }
38
39    // --- ファイルのCMS暗号化 ---
40    // openssl_cms_encrypt 関数は、指定された入力ファイルを証明書で暗号化し、結果をファイルに書き込みます。
41    // 第4引数 ($headers) は通常空の配列で構いませんが、必要に応じてCMSヘッダー情報を追加できます。
42    // 第5引数 ($flags) は追加のオプションを指定します (例: OPENSSL_CMS_BINARY, OPENSSL_CMS_DETACHED)。
43    // 第6引数 ($encoding) はエンコーディング形式で、OPENSSL_ENCODING_SMIME が一般的です。
44    // 第7引数 ($cipher_algo) は使用する暗号化アルゴリズムで、OPENSSL_CIPHER_AES128_GCM がデフォルトです。
45    $result = openssl_cms_encrypt(
46        $inputFilePath,        // 暗号化する元のデータファイル
47        $outputFilePath,       // 暗号化されたデータを書き込むファイル
48        $certificatePath,      // 受信者の証明書
49        [],                     // CMSヘッダー (通常は空の配列)
50        0,                      // フラグ (デフォルトは0)
51        OPENSSL_ENCODING_SMIME, // エンコーディング形式
52        OPENSSL_CIPHER_AES128_GCM // 暗号化アルゴリズム
53    );
54
55    // --- 結果の確認とエラーハンドリング ---
56    // openssl_cms_encrypt は成功した場合に暗号化されたデータの文字列を返し、
57    // 失敗した場合は false を返します。
58    if ($result === false) {
59        echo "エラー: ファイルのCMS暗号化に失敗しました。\n";
60        // OpenSSLのエラーキューから詳細なエラーメッセージを取得し表示します。
61        // これにより、失敗の原因を特定しやすくなります。
62        while ($msg = openssl_error_string()) {
63            echo "OpenSSLエラー: " . $msg . "\n";
64        }
65        return false;
66    }
67
68    echo "ファイル '{$inputFilePath}' は正常にCMS形式で暗号化され、'{$outputFilePath}' に保存されました。\n";
69    return true;
70}
71
72// --- サンプルコードの実行例 ---
73
74// 1. テスト用の入力ファイルを作成します。
75$inputFileName = 'sensitive_data.txt';
76file_put_contents($inputFileName, 'これは機密性の高い情報です。CMS暗号化で保護します。');
77
78// 2. 証明書ファイルのパスを指定します。
79//    上記の「事前準備と検証」コメントに従って、`cert.pem` ファイルを生成してください。
80$certificateFileName = 'cert.pem';
81
82// 3. 暗号化されたデータが保存される出力ファイル名を指定します。
83$outputFileName = 'encrypted_message.cms';
84
85// 4. 暗号化関数を実行します。
86if (encryptFileWithCms($inputFileName, $outputFileName, $certificateFileName)) {
87    echo "CMS暗号化処理が正常に完了しました。\n";
88    echo "出力ファイル: {$outputFileName}\n";
89} else {
90    echo "CMS暗号化処理中に問題が発生しました。\n";
91}
92
93// 5. (オプション) テスト後に生成されたファイルを削除する場合
94// unlink($inputFileName);
95// unlink($outputFileName);
96// unlink($certificateFileName); // 必要に応じて
97// unlink('privkey.pem'); // 必要に応じて
98?>

PHPのopenssl_cms_encrypt関数は、ファイルをCMS (Cryptographic Message Syntax) 形式で暗号化し、その結果を指定したファイルに保存する際に利用されます。この機能は、インターネット上での安全なデータの送受信や保存など、機密性の高い情報を保護するために広く用いられる標準的な方法を提供します。

この関数は、暗号化したい元のファイルパス、暗号化されたデータを書き出す出力ファイルパス、そして暗号化に使用する受信者のX.509証明書のパスを主要な引数として受け取ります。提供された証明書の公開鍵がデータの暗号化に用いられます。その他にも、CMSヘッダー情報、追加の挙動を制御するフラグ、エンコーディング形式、暗号化アルゴリズムなどをオプションで指定できます。

処理が成功した場合、関数は暗号化されたデータの文字列を返しますが、通常は出力ファイルに直接書き込まれるため、この戻り値を直接扱うことは稀です。もし暗号化に失敗した場合は、戻り値としてfalseが返されます。失敗の原因は、openssl_error_string()関数を使用してOpenSSLのエラーキューから詳細なメッセージを取得することで確認できます。サンプルコードは、ファイルの存在確認から証明書の準備、実際の暗号化処理、そしてエラーハンドリングまで、一連のCMS暗号化の流れを具体的に示しています。

openssl_cms_encrypt関数は、暗号化に失敗した場合にfalseを返します。その際は、必ずopenssl_error_string()関数でOpenSSLのエラーキューを確認し、具体的な失敗原因を特定することが重要です。サンプルコードで示す証明書と秘密鍵の生成はテスト目的であり、本番環境では信頼できる認証局が発行したX.509証明書を使用し、秘密鍵は厳重に管理し、漏洩しないように徹底してください。入力ファイル、出力ファイル、証明書ファイルのパスは、PHPが読み書きできる適切な権限を持つ場所に指定してください。また、cipher_algoに指定する暗号化アルゴリズムは、常に最新のセキュリティ要件を満たす推奨されるものを選ぶようにしてください。これらの点に留意し、安全かつ正確な実装を心がけてください。

関連コンテンツ

関連IT用語

関連プログラミング言語