PHPで公開鍵・秘密鍵それぞれで、暗号化・復号化することがあったのでその時のメモ。

基本的には openssl_get_privatekey() や openssl_get_publickey() で秘密鍵・公開鍵のオブジェクトを作成し、openssl_private_encrypt() や openssl_private_decrypt() (公開鍵では openssl_public_***() メソッド) を使った暗号化・復号化すればいいだけ。

秘密鍵で暗号化し、公開鍵で復号化

function getPrivateKey($file, $passphrase = null) {
    $f = fopen($file, "r");
    $c = fread($f, filesize($file));
    return openssl_get_privatekey($c, $passphrase);
}

function getPublicKey($file) {
    $f = fopen($file, "r");
    $c = fread($f, filesize($file));
    return openssl_get_publickey($c);
}

$data = "Test data to be encrypted";
$privateKeyFile = __DIR__ . "/test_key";
$pubilcKeyFile = __DIR__ . "/test_key.pub";

// 秘密鍵で暗号化
$privatekey = getPrivateKey($privateKeyFile);
$encdata;
openssl_private_encrypt($data, $encdata, $privatekey);

// 暗号化されたデータ
var_dump($encdata);

// 公開鍵で復号化
$publickey = getPublicKey($pubilcKeyFile);
$decdata;
openssl_public_decrypt($encdata, $decdata, $publickey);

// 復号化されたデータ
var_dump($decdata);

公開鍵で暗号化、秘密鍵で復号化

// getPrivateKey(), getPublicKey()、その他共通部は上記参照

// 公開鍵で暗号化
$publickey = getPublicKey($pubilcKeyFile);
$encdata;
openssl_public_encrypt($data, $encdata, $publickey);

// 暗号化されたデータ
var_dump($encdata);

// 秘密鍵で復号化
$privatekey = getPrivateKey($privateKeyFile);
$decdata;
openssl_private_decrypt($encdata, $decdata, $privatekey);

// 復号化されたデータ
var_dump($decdata);

秘密鍵にパスフレーズをつけた場合

秘密鍵にパスフレーズをつけた場合は、openssl_get_privatekey() にパスフレーズを渡せば良い。

データ長が長い場合

公開鍵・秘密鍵で暗号化できるのは、データ長が鍵よりも短い場合のみ。データ長の大きいデータを暗号化する場合は、まずデータをランダムに生成した鍵で暗号化し、その暗号化鍵を公開鍵・秘密鍵で暗号化する。

暗号化する場合は以下のような感じ。

// AES-256-CBC アルゴリズムで暗号化するのが現在は一般的
// まず暗号化鍵を生成し、データを暗号化
$data = "暗号化するデータ";
$symmetricKey = openssl_random_pseudo_bytes(32); 
$iv = openssl_random_pseudo_bytes(16);
$encryptedData = openssl_encrypt($data, "AES-256-CBC", $symmetricKey, 0, $iv);

// 暗号化鍵を公開鍵で暗号化
$publicKey = openssl_get_publickey($publicKey);
$encryptedKey;
$result = openssl_public_encrypt($symmetricKey, $encryptedKey, $publicKey);

復号化する場合は逆にすればOK。

$encryptedKey = "公開鍵で暗号化された暗号化鍵";
$encryptedData = "暗号化されたデータ";
$iv = "暗号化時に生成した初期化ベクター";

// まず暗号化鍵を秘密鍵を使って復号化
$privateKey = openssl_get_privatekey($privateKey);
$symmetricKey;
$result = openssl_private_decrypt($encryptedKey, $symmetricKey, $privateKey);

// その後、復号化した鍵を使ってデータを復号化
$data = openssl_decrypt($encryptedData, "AES-256-CBC", $decryptedKey, 0, $iv);