RSA の実装には注意してください。実際、おそらく RSA をまったく使用すべきではありません。(代わりに libsodium を使用してください! )
ライブラリ (たとえば、PHP の OpenSSL 拡張機能を直接使用したり、最近まで使用していたもの) を使用している場合でも、Zend\Crypt
うまくいかないことがたくさんあります。特に:
- デフォルトの PKCS1v1.5 パディング(多くの場合、サポートされている唯一のパディング モード) は、パディング オラクルと呼ばれる選択暗号文攻撃のクラスに対して脆弱です。これは Daniel Bleichenbacher によって最初に発見されました。1998年。
- RSA は大きなメッセージの暗号化には適していないため、実装者がよく行うことは、長いメッセージを取得して固定サイズのブロックに分割し、各ブロックを個別に暗号化することです。これは遅いだけでなく、対称鍵暗号化の恐ろしい ECB モードに似ています。
Libsodium を使用する最善の方法
このルートに進む前に、 「 JavaScript 暗号化は有害であると見なされる」を数回読むことをお勧めします。しかし、そうは言っても...
- HSTS および HPKP で TLSv1.2 を使用します。できれば ChaCha20-Poly1305 および/または AES-GCM と ECDSA-P256 証明書を使用します (重要: IETF が Curve25519 および Ed25519 と名付けた場合は、代わりにそれに切り替えてください)。
- プロジェクトにlibsodium.jsを追加します。
crypto_box_seal()
クライアント側でメッセージを暗号化するために公開鍵とともに使用します。
- PHP では
\Sodium\crypto_box_seal_open()
、対応する公開鍵の秘密鍵と共に使用して、メッセージを復号化します。
この問題を解決するには、RSA を使用する必要があります。
しないでください。楕円曲線暗号は、サイドチャネルなしで実装するのがより速く、より簡単で、はるかに簡単です。ほとんどのライブラリは、すでにこれを行っています。(リボナトリウム!)
でもどうしてもRSAを使いたい!
よし、これらの推奨事項に従ってください。間違いを犯したとき ( SaltStack がしたように)、暗号化が役に立たなくなったときに、StackOverflow に泣かないでください。
シンプルで簡単な RSA 暗号化を提供することを目的とした 1 つのオプション (補完的な JavaScript 実装は付属していません。求めないでください) は、paragonie/easyrsaです。
EasyRSA 暗号化プロトコル
- EasyRSA は、対称キー暗号化 (AES 経由) 用にランダムな 128 ビット キーを生成します。
- 平文メッセージはdefuse/php-encryption で暗号化されます。
- AES キーは、正しいモード (上記) を使用して、phpseclibによって提供される RSA で暗号化されます。
- この情報は単純な文字列 (チェックサム付き) としてまとめられます。
しかし、実際には、公開鍵暗号化の有効な使用例を見つけた場合は、代わりに libsodium が必要です。
おまけ: JavaScript による暗号化、PHP による復号化
この目標を達成するために、ナトリウムプラスを使用します。(この投稿から採用。)
const publicKey = X25519PublicKey.from('fb1a219011c1e0d17699900ef22723e8a2b6e3b52ddbc268d763df4b0c002e73', 'hex');
async function sendEncryptedMessage() {
let key = await getExampleKey();
let message = $("#user-input").val();
let encrypted = await sodium.crypto_box_seal(message, publicKey);
$.post("/send-message", {"message": encrypted.toString('hex')}, function (response) {
console.log(response);
$("#output").append("<li><pre>" + response.message + "</pre></li>");
});
}
次に、一致する PHP コード:
<?php
declare(strict_types=1);
require 'vendor/autoload.php'; // Composer
header('Content-Type: application/json');
$keypair = sodium_hex2bin(
'0202040a9fbf98e1e712b0be8f4e46e73e4f72e25edb72e0cdec026b370f4787' .
'fb1a219011c1e0d17699900ef22723e8a2b6e3b52ddbc268d763df4b0c002e73'
);
$encrypted = $_POST['message'] ?? null;
if (!$encrypted) {
echo json_encode(
['message' => null, 'error' => 'no message provided'],
JSON_PRETTY_PRINT
);
exit(1);
}
$plaintext = sodium_crypto_box_seal_open(sodium_hex2bin($encrypted), $keypair);
echo json_encode(
['message' => $plaintext, 'original' => $encrypted],
JSON_PRETTY_PRINT
);