PHPのOpenSSLで暗号化して復号する

OpenSSLを使った暗号化の実装にあたり、ざっと調べました。

    案件

    「ユーザーごとに一意なIDをパラメータに付けたURLを発行するが、IDは分からないように暗号化したうえで受信側で復号したい」という要件があり、OpenSSLを使用しました。

    PHPの暗号化:OpenSSLを選択

    PHPにおける暗号化はmcryptがありましたがPHP 7.1.0 で非推奨となり、 PHP 7.2.0 で削除されPECL(拡張モジュール)に移行されました。

    この機能は PHP 7.1.0 で 非推奨 となり、 PHP 7.2.0 で削除 されました。

    この機能の代替として、これらが使えます。

    • Sodium (PHP 7.2.0から利用可能)
    • OpenSSL
    PHP マニュアル > 関数リファレンス > 暗号 > Mcrypt > はじめに

    という訳でOpenSSLを使っていこうと思います。

    なお、そもそもの暗号化の概論というか用語については以下が簡潔で分かりやすくて良かった。押さえておくとググりが捗りました。

    OpenSSLの実装:openssl_encrypt/openssl_decrypt とパラメータ

    PHP
    // 暗号化
    openssl_encrypt( $data, $method, $key, $options, $iv );
    
    // 復号
    openssl_decrypt( $data, $method, $key, $options, $iv );

    $data

    暗号化/複合するデータ。

    $method

    暗号化メソッド。暗号化の方法もなんやら色々あるのでどれを使うかを指定する。

    環境によって使用可能なメソッドが異なる。openssl_get_cipher_methods()で使用可能なメソッドの一覧を取得できる。

    ローカルでは使えたけど本番環境では対応していないとか発生する可能性がある(実際した)ので、事前に確認しておくべき。

    どのmethodを使うのがベストか?

    $methodは何を使うのが最適かわからないが、AESが標準的っぽく、調べた感じでは AES-256-CBC が無難な人気どころのようである。

    AESのビット数とモード

    AESにもたくさんの種類があり、AES-ビット数-モードであらわされる。

    ビット数

    ビット数は128/192/256 から選択できる。大きいほど暗号強度が強くなる。暗号の長さには影響しない。

    モード

    モードについては以下の記事が分かりやすかった。

    主要モードのうちECB以外ではiv(初期ベクトル)を使用する。

    $key

    共通鍵。暗号化・復号に共通して使うパスフレーズ。

    $options

    ここは分かりにくい。以下を参照。

    調べた感じだと0(デフォルト)を使ってる人が多いように感じた。

    $iv

    初期化ベクトル。暗号を複雑化して平文を推測されにくくする。

    暗号化メソッドによって必要な長さが変わるので、openssl_cipher_iv_length()で暗号 iv の長さを取得する。

    暗号化と復号で同じ iv を使用する必要があるので、DBなどに保存するか、共通の値を元に何らかの規則で生成するのがよさそう。

    省略すると Warning が出るが、暗号化はやってくれる。

    初期化ベクトルに関する解説では以下が一番平易に感じた。

    URLのパラメータに渡す

    基本的にはPOSTで渡した方が良さそうだが、GETでやる場合は英数字のみに変換する。

    暗号化時はbin2hex、復号時はhex2binを用いる。

    PHP
    $enc_string = bin2hex( openssl_encrypt( $data , $method, $key, 0, $iv ) );
    $dec_string = openssl_decrypt( hex2bin( $data ), $method, $key, 0, $iv );

    なお、hex2bin()はPHP5.3以下にはない関数なので以下で対応する。

    PHP
    if ( !function_exists( 'hex2bin' ) ) {
    	function hex2bin( $str ) {
    		$sbin = "";
    		$len = strlen( $str );
    		for ( $i = 0; $i < $len; $i += 2 ) {
    				$sbin .= pack( "H*", substr( $str, $i, 2 ) );
    		}
    
    		return $sbin;
    	}
    }

    ※そもそもPHPのバージョンを上げるべきである。

    サポートが必要ですか?

    ご質問・お見積り依頼はお気軽にどうぞ

    お問い合わせはこちら
    シェア
    野良人 代表
    新免祥太
    1988年岡山生まれ。外食企業のWEB・EC担当を経験したのち、2013年12月より「野良人(のらんど)」の屋号で独立しWEBデザイン・プログラミングなどWEBサイト制作の工程全般を請け負っています。お気軽にご相談ください。
    広告
    次の記事(2021/03/09)
    【WordPress】サブメニューとして表示したカスタム投稿のカテゴリー表示
    前の記事(2021/01/09)
    WordPress自作テーマやプラグインを管理画面から更新できる「plugin-update-checker」でGitHubのprivateリポジトリから配信する
    記事一覧