PHP

【PHP】opensslを使ったAES-256-CBC方式の暗号化復号化を実装する方法

takanori-admin

暗号化は、情報セキュリティを確保する上で欠かせない技術です。

AES-256-CBC暗号化方式は、現在でも広く使用されている暗号化方式のひとつであり、安全性が高いため、多くの場面で採用されています。

本記事では、PHPのopensslライブラリを用いたAES-256-CBC暗号化と復号化の実装方法について解説します。

opensslを用いたAES-256-CBC暗号化

opensslを用いたAES-256-CBC暗号化

AES-256-CBC暗号化方式を用いた暗号化手順は、以下の通りです。

AES-256-CBC暗号化方式を用いた暗号化手順
  1. 暗号化対象のデータを用意する
  2. 暗号化に使用する鍵を用意する
  3. 暗号化に使用する初期化ベクトル(IV)を用意する
  4. openssl_encrypt()関数を使用して、データを暗号化する

openssl_encrypt()関数の使用方法

以下が、openssl_encrypt()関数の基本的な使用方法です。

1$encrypted_data = openssl_encrypt($data, $method, $key, $option, $iv);
  • $data:暗号化対象のデータ
  • $method:暗号化アルゴリズム
  • $key:暗号化に使用する鍵
  • $option:オプション
  • $iv:初期化ベクトル
opensslを用いたAES-256-CBC復号化

opensslを用いたAES-256-CBC復号化

AES-256-CBC暗号化方式を用いた復号化手順は、以下の通りです。

AES-256-CBC暗号化方式を用いた復号化手順
  1. 復号化対象のデータを用意する
  2. 復号化対象のデータの暗号化に使用した鍵を用意する
  3. 復号化対象のデータの暗号化に使用した初期化ベクトル(IV)を用意する
  4. openssl_decrypt()関数を使用して、データを暗号化する

openssl_decrypt()関数の使用方法

以下が、openssl_decrypt()関数の基本的な使用方法です。

1$decrypted_data = openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
  • $data:復号化対象のデータ
  • $method:暗号化アルゴリズム
  • $key復号化対象のデータの暗号化に使用した鍵
  • $option:オプション
  • $iv復号化対象のデータの暗号化に使用した初期化ベクトル
暗号化して復号化するサンプルコード

暗号化して復号化するサンプルコード

以下は、PHPのopenssl関数を使ったAES-256-CBC暗号化、復号化のサンプルコードです。

1$data = "暗号化の文字列";
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5$options = 0;
6
7// 暗号化する
8$encrypted = openssl_encrypt($data, $method, $key, $options, $iv);
9
10// 暗号化文字列
11var_dump($encrypted); 
12
13// 復号化する
14$decrypted = openssl_decrypt($encrypted, $method, $key, $options, $iv);
15
16// 元のデータに戻る
17var_dump($decrypted);
#実行結果
string(44) "Yw8Cbyeq0SCI/jGmqRd0G7OSwsOyP/UK3vF1LS23kvw="
string(21) "暗号化の文字列"

サンプルコードは、「暗号化の文字列」を暗号化して復号化しました。

$methodは、“AES-256-CBC”を指定しました。
$key$ivは、ランダムなバイト文字列を生成するopenssl_random_pseudo_bytes()を使用しました。引数に指定したbyte長のランダムな文字列を生成します。
$optionには、今回は「0:オプション指定なし」を設定しました。
暗号化後の出力形式は、次の項目「オプションについて」で解説します。

オプションについて

オプションについて

オプションの設定は、パディングの有無と暗号化後の出力形式を指定します。
openssl_encrypt()openssl_decrypt()関数のオプションは基本的には以下の4つを設定します。

$optionの設定
  • 0:オプション指定なし
  • 1:OPENSSL_RAW_DATA
  • 2:OPENSSL_ZERO_PADDING
  • 3:OPENSSL_ZERO_PADDINGとOPENSSL_RAW_DATAの両方

0:オプション指定なし

openssl_encrypt()openssl_decrypt()関数のオプションに0を設定すると、何もオプションが指定されていない状態になります。具体的には、以下のような状態になります。

  • openssl_encrypt()出力はBase64エンコードされた暗号化文字列
  • openssl_decrypt()入力はBase64エンコードされた暗号化文字列
  • パディングはPKCS#7方式

暗号化の際は、「元の文字列をPKCS#7方式でパディングする」ため、元の文字列のバイト長を気にする必要はありません
復号化の際は、「PKCS#7方式でパディングされた元の文字列」の暗号化文字列を受け取る必要があります
サンプルコードは上記と同じなので、省略します。
(※PKCS#7はPKCS#5と表現されることがあります)

1:OPENSSL_RAW_DATA

openssl_encrypt()openssl_decrypt()関数のオプションに1を設定すると、”OPENSSL_RAW_DATA“フラグが指定された状態になります。具体的には、以下のような状態になります。

  • openssl_encrypt()出力はバイナリ形式(バイト列)
  • openssl_decrypt()入力はバイナリ形式(バイト列)
  • パディングはPKCS#7方式

暗号化の際は、「元の文字列をPKCS#7方式でパディングする」ため、元の文字列のバイト長を気にする必要はありません
復号化の際は、「PKCS#7方式でパディングされた元の文字列」の暗号化文字列を受け取る必要があります
(※PKCS#7はPKCS#5と表現されることがあります)
サンプルコードは以下のようになります。

1$data = "暗号化の文字列";
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5$options = OPENSSL_RAW_DATA; // 1の代わりにOPENSSL_RAW_DATAと指定することもできます
6
7// 暗号化する
8$encrypted = openssl_encrypt($data, $method, $key, $options, $iv);
9
10// 暗号化文字列
11var_dump($encrypted); 
12
13// 復号化する
14$decrypted = openssl_decrypt($encrypted, $method, $key, $options, $iv);
15
16// 元のデータに戻る
17var_dump($decrypted);
#実行結果
string(32) "�t$]#�`�x��/v��X�,��W�)��"
string(21) "暗号化の文字列"

※暗号化文字列はバイナリ形式なので文字化けしました。

2:OPENSSL_ZERO_PADDING

openssl_encrypt()openssl_decrypt()関数のオプションに2を設定すると、”OPENSSL_ZERO_PADDING“フラグが指定された状態になります。具体的には、以下のような状態になります。

  • openssl_encrypt()出力はBase64エンコードされた暗号化文字列
  • openssl_decrypt()入力はBase64エンコードされた暗号化文字列
  • パディングしない

暗号化の際は、パディングをしないため、元の文字列のバイト長を16byteの倍数にする必要ががあります。16byteの倍数に満たない場合はエラーとなります。
復号化の際は、パディングの有無に限らず正しく暗号化されていればなんでも復号化できますが、PKCS#7などでパディングされている場合、末尾にパディングの分不要な文字が出力されます。

サンプルコードは以下のようになります。
◆OPENSSL_ZERO_PADDINGで暗号化、復号化

1$data = "暗号化の文字列あいうえおかきくけ"; //全角文字16文字(48byte)
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5$options = OPENSSL_ZERO_PADDING; // 2の代わりにOPENSSL_ZERO_PADDINGと指定することもできます
6
7// 暗号化する
8$encrypted = openssl_encrypt($data, $method, $key, $options, $iv);
9
10// 暗号化文字列
11var_dump($encrypted); 
12
13// 復号化する
14$decrypted = openssl_decrypt($encrypted, $method, $key, $options, $iv);
15
16// 元のデータに戻る
17var_dump($decrypted);
#実行結果
string(64) "iM0QjOB1VAIxe+luZGl63uxA2n4TOgn+HL5Gov+s+8Y8OJn+LeajDnHvOeG+GfoJ"
string(48) "暗号化の文字列あいうえおかきくけ"

◆オプション指定なしで暗号化、OPENSSL_ZERO_PADDINGで復号化

1$data = "暗号化の文字列"; 
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5
6// 暗号化する
7$encrypted = openssl_encrypt($data, $method, $key, 0, $iv);
8
9// 暗号化文字列
10var_dump($encrypted); 
11
12// 復号化する
13$decrypted = openssl_decrypt($encrypted, $method, $key, OPENSSL_ZERO_PADDING, $iv);
14
15// 元のデータに戻る
16var_dump($decrypted);
#実行結果
string(44) "JTpPfdncE0aZ0AKoSvROHPu//gnWyplyrJyccxfuLqo="
string(32) "暗号化の文字列"

パディングの分だけ不要な文字が出力する。

3:OPENSSL_ZERO_PADDINGとOPENSSL_RAW_DATAの両方

openssl_encrypt()openssl_decrypt()関数のオプションに3を設定すると、"OPENSSL_ZERO_PADDING""OPENSSL_RAW_DATA“の両方のフラグが指定された状態になります。値としては、両方のフラグのビットORになります。具体的には、以下のような状態になります。

  • openssl_encrypt()出力はバイナリ形式(バイト列)
  • openssl_decrypt()入力はバイナリ形式(バイト列)
  • パディングしない

暗号化の際は、パディングをしないため、元の文字列のバイト長を16byteの倍数にする必要ががあります。16byteの倍数に満たない場合はエラーとなります。
復号化の際は、パディングの有無に限らず正しく暗号化されていればなんでも復号化できますが、PKCS#7などでパディングされている場合、末尾にパディングの分不要な文字が出力されます。

サンプルコードは以下のようになります。
◆OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATAで暗号化、復号化

1$data = "暗号化の文字列あいうえおかきくけ"; //全角文字16文字(48byte)
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5$options = OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA; // 3の代わりにOPENSSL_ZERO_PADDING | OPENSSL_RAW_DATAと指定することもできます
6
7// 暗号化する
8$encrypted = openssl_encrypt($data, $method, $key, $options, $iv);
9
10// 暗号化文字列
11var_dump($encrypted); 
12
13// 復号化する
14$decrypted = openssl_decrypt($encrypted, $method, $key, $options, $iv);
15
16// 元のデータに戻る
17var_dump($decrypted);
#実行結果
string(48) ":\C�7A�tÉJ���~����{��2����T�¬f����^Y�q"
string(48) "暗号化の文字列あいうえおかきくけ"

※暗号化文字列はバイナリ形式なので文字化けしました。

OPENSSL_RAW_DATAで暗号化、OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATAで復号化

1$data = "暗号化の文字列";
2$method = "AES-256-CBC";
3$key = openssl_random_pseudo_bytes(16);
4$iv = openssl_random_pseudo_bytes(16);
5
6// 暗号化する
7$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
8
9// 暗号化文字列
10var_dump($encrypted); 
11
12// 復号化する
13$decrypted = openssl_decrypt($encrypted, $method, $key, OPENSSL_ZERO_PADDING | OPENSSL_RAW_DATA, $iv);
14
15// 元のデータに戻る
16var_dump($decrypted);
#実行結果
string(32) "���&�BLC�IYY�iR��<n}C���mE�"
string(32) "暗号化の文字列"

パディングの分だけ不要な文字が出力する。
※暗号化文字列はバイナリ形式なので文字化けしました。

まとめ

まとめ

本記事では、PHPのopensslを使ったAES-256-CBC方式での暗号化・復号化について解説しました。

AES-256-CBCは、高度なセキュリティが求められる場面で使用されることが多く、PHPでも簡単に実装することができます。

暗号化や復号化を行う前には、適切な鍵の生成や保存、安全な通信の確保など、様々な準備が必要です。また、暗号化方式によっては、脆弱性や攻撃手法があるため、セキュリティに十分注意が必要です。

最後に、本記事がPHPでの暗号化・復号化の理解に役立ち、より安全なプログラミングに貢献できることを願っています。

ABOUT ME
たかのり
たかのり
会社員
2018年4月からシステムエンジニアとして働いています。
5年間で2度の転職を経て、SESから自社開発で開発などやってるJava屋さんです。

ところで、このプロフィール欄は自分で改行タグ入れないと改行されないんですね。
記事URLをコピーしました