【やさしく解説】PHP8上級試験の模擬問題(29)

PHP
スポンサーリンク

PHP8 上級/準上級試験の認定模擬問題として、プライム・ストラテジー様のPRIME STUDYが認定されているようです。ただ、この模擬問題には解説がありませんので解説をまとめていこうと思います。シリーズ第29回目です。

PHP初級レベルから脱却して中級/上級レベルにいきたい人にピッタリの内容ですね。

今回はOpenSSL関数群(暗号化・復号・証明書解析)に関する問題です。暗号化・復号時の初期化ベクトル (IV) の扱いや、利用可能な暗号方式の取得方法など、実務にも直結する重要なポイントが問われています。内容をしっかり理解して、確実に押さえていきましょう!

PRIME STUDY認定模擬問題のリンクはこちらです → https://study.prime-strategy.co.jp/ 

問題文

関数 に関する説明の中で、誤っているものを1つ選びなさい。
また、すべてのコードには下記のコードが適切な箇所に書かれているものとする。

declare(strict_types=1);
error_reporting(-1);
下記はマニュアルから一部引用した内容である。

openssl_encrypt ( string $data , string $method , string $key , int $options = 0 , string $iv = “” , string &$tag = NULL , string $aad = “” , int $tag_length = 16 ) : string|false
openssl_decrypt ( string $data , string $method , string $key , int $options = 0 , string $iv = “” , string $tag = “” , string $aad = “” ) : string|false
openssl_x509_parse ( mixed $x509cert , bool $shortnames = true ) : array

(1)
openssl_get_cipher_methods() 関数は利用可能な暗号メソッドを取得する。
そのため、以下のコード

var_dump( openssl_get_cipher_methods() );

を実行すると、結果は次のとおりとなる。

array(201) {
  [0]=>
  string(11) "AES-128-CBC"
  [1]=>
  string(21) "AES-128-CBC-HMAC-SHA1"
  [2]=>
  string(23) "AES-128-CBC-HMAC-SHA256"
  (中略)
  [199]=>
  string(8) "seed-ecb"
  [200]=>
  string(8) "seed-ofb"
}

(2)
openssl_encrypt() 関数はデータを暗号化する。
そのため、以下のコード

$method = 'AES-128-CBC';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
$crypt = openssl_encrypt('exam', $method, 'key', 0, $iv);
var_dump( $crypt );


を実行すると

string(24) "GoaKntvUhPOEl5VS92Uiyg=="


となる ( initialization vector が random なので、値は実行毎に変わる)。
なお、例えば CBC のような「initialization vector が必要な暗号利用モード」で initialization vector を指定しないと Warning が出る。
そのため以下のコード

$method = 'AES-128-CBC';
$crypt = openssl_encrypt('exam', $method, 'key', 0);
var_dump( $crypt );


を実行すると、結果は次のとおりとなる。

Warning: openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended in …
string(24) "5kBbn5hweqDYYT6VQjj2ag=="

(3)
openssl_decrypt() 関数はデータを復号する。
そのため、以下のコード

$method = 'AES-128-CBC';
$key = 'key';
$crypt = openssl_encrypt('exam', $method, $key, 0, openssl_random_pseudo_bytes(openssl_cipher_iv_length($method)));
var_dump( $crypt );
$decrypt_string = openssl_decrypt($crypt, $method, $key);
var_dump( $decrypt_string );


を実行すると

string(24) "MWFlUhetizqXeV321jVUvA=="
string(4) "exam"


となる。
initialization vector が random なので $crypt は実行毎に変わるが、復号された「exam」は常に同じになる。
また initialization vector は $crypt の中に含まれているため、引数として与えなくても正しく復号される。

(4)
openssl_x509_parse() 関数は X509 証明書をパースし、配列として情報を返す。
そのため、以下のコード

$resource = @stream_socket_client(
'ssl://www.phpexam.jp:443',
$errno,
$errstr,
60,
STREAM_CLIENT_CONNECT,
stream_context_create(['ssl' => ['capture_peer_cert' => true]]),
);
$cont = stream_context_get_params($resource);
$x509 = openssl_x509_parse($cont['options']['ssl']['peer_certificate']);
var_dump($x509);


を実行すると、結果は次のとおりとなる。

array(16) {
  ["name"]=>
  string(18) "/CN=www.phpexam.jp"
  ["subject"]=>
  array(1) {
    ["CN"]=>
    string(14) "www.phpexam.jp"
  }
  ["hash"]=>
  string(8) "491a204d"
  ["issuer"]=>
  array(3) {
    ["C"]=>
    string(2) "US"
    ["O"]=>
    string(13) "Let's Encrypt"
    ["CN"]=>
    string(2) "R3"
  }
  ["version"]=>
  int(2)
(後略)

解説

選択肢1の解説

正しいです。
openssl_get_cipher_methods()は「どんな暗号化の方法が使えるか?」 を確認するためのものです。
var_dump(openssl_get_cipher_methods());を実行すると、使える暗号方式がズラーッと表示されます。

例えば、AES-128-CBC(よく使われる暗号方式)、DES-EDE3-CBC(昔の方式)などです。openssl_encrypt() の第2引数 $method に指定する文字列もこの暗号方式を指定します。

選択肢2の解説

正しいです。
例えば以下のようなコードで

$method = 'AES-128-CBC';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
$crypt = openssl_encrypt('exam', $method, 'key', 0, $iv);

AES-128-CBCは暗号方式、keyは暗号化に使う鍵(簡略化のために ‘key’ という文字列を使用)、ivは初期化ベクトル(Initialization Vector)を意味します。

ivというのは、簡単に言うと「暗号を毎回違う結果にするためのランダムなデータ」です。ivがあると、同じ平文でも毎回違う暗号文になります。CBC モードなど一部の暗号方式では ivが必須となります。

IV を省略すると、PHP は空文字列 “” を使おうとします。このときWarningが出ます。

選択肢3の解説

誤りです。
openssl_decrypt()は暗号化された文字列を元に戻す(復号する)ためのものです。

暗号化のときはivを使っているのに

$crypt = openssl_encrypt('exam', $method, $key, 0, openssl_random_pseudo_bytes(openssl_cipher_iv_length($method)));

復号のときは指定していません。

$decrypt_string = openssl_decrypt($crypt, $method, $key);

暗号化・復号には同じ IV が必要です。このため誤りとなります。

選択肢4の解説

正しいです。
openssl_x509_parse()はX.509 証明書の中身を見るためのものです。

X.509 証明書というのは、インターネットで「このサイトは安全です!」と証明するために使われる証明書の形式のことです。

stream_socket_client(...); // SSL通信で接続
$cont = stream_context_get_params($resource);
$x509 = openssl_x509_parse($cont['options']['ssl']['peer_certificate']);

このコードにおいて、stream_socket_client()はSSL 接続、capture_peer_cert相手の証明書を取得、openssl_x509_parse()は証明書を分解して、名前や発行者などを配列で見る、とう動作になります。

正解選択肢

以上より選択肢3が正解となります。

他の問題へ

コメント

タイトルとURLをコピーしました