質問: 暗号化および復号化する方法 php 文字列? つまり、original string + salt or key --> encrypted string encrypted string + salt or key --> decrypted (original string) たぶん何かのような:"hello world!" + "abcd1234" --> encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g) "2a2ffa8f13220befbe30819047e23b2c" --> decrypt with "abcd1234" --> "hello world!" phpでは、どうすればこれができますか? crypt_blowfish を使おうとしましたが、うまくいきませんでした。
回答: さらに何かをする前に、 encryptionとauthenticationの違い と、おそらくなぜ認証された暗号化が必要かを理解するように努めてくださいだけではなくencryption。認証された暗号化を実装するには、暗号化してからmacにする必要があります。 暗号化と認証の順序は非常に重要です! この質問に対する既存の回答の1つがこの間違いを犯しました。 phpで書かれた多くの暗号化ライブラリがそうであるように。 独自の暗号化の実装を避ける を使用し、代わりに暗号化の専門家によって作成およびレビューされた安全なライブラリを使用する必要があります。 更新:php 7.2はlibsodiumを提供するようになりました!最高のセキュリティを確保するには、php 7.2以降を使用するようにシステムを更新し、この回答のlibsodiumアドバイスのみに従ってください。 peclアクセスがある場合はlibsodiumを使用 (または sodium_compat peclなしのlibsodiumが必要な場合);そうでなければ... defuse/php-encryptionを使用 ;独自の暗号を転がさないでください!上記の両方のライブラリを使用すると、認証された暗号化を独自のライブラリに簡単に実装できます。インターネット上のすべての暗号化の専門家の常識に反して、独自の暗号化ライブラリを作成および展開したい場合は、これらの手順を実行する必要があります。暗号化: ctrモードでaesを使用して暗号化します。 gcmを使用することもできます(これにより、別個のmacが不要になります)。さらに、chacha20およびsalsa20( libsodium で提供)はストリーム暗号であり、特別なモードを必要としません。 上記のgcmを選択した場合を除き、hmac-sha-256で暗号文を認証する必要があります(または、ストリーム暗号の場合はpoly1305-ほとんどのlibsodium apiがこれを行います)。 macはivと暗号文をカバーする必要があります! 復号化: poly1305またはgcmを使用しない限り、暗号文のmacを再計算し、 hash_equals() を使用して送信されたmacと比較します。失敗した場合は中止します。 メッセージを解読します。 その他の設計上の考慮事項: 何も圧縮しないでください。暗号文は圧縮できません。暗号化の前にプレーンテキストを圧縮すると、情報漏えいにつながる可能性があります(たとえば、tlsでのcrimeおよびbreach)。 '8bit'文字セットモードを使用して、mbstring.func_overloadの問題を防ぐために、必ずmb_strlen()およびmb_substr()を使用してください。 ivは csprng ;を使用して生成する必要があります。 mcrypt_create_iv()を使用している場合は、mcrypt_randを使用しないでください! random_compat も確認してください。 aeadコンストラクトを使用していない限り、 常に暗号化してからmac! bin2hex()、base64_encode()などは、キャッシュのタイミングを介して暗号化キーに関する情報を漏らす可能性があります。可能な場合は避けてください。 ここで与えられたアドバイスに従ったとしても、暗号化に関して多くのことがうまくいかない可能性があります。 暗号化の専門家に実装のレビューを常に依頼してください。地元の大学で暗号化の学生と個人的な友達になれなかった場合、いつでも試すことができます cryptography stack exchange アドバイスのためのフォーラム。実装の専門的な分析が必要な場合は、いつでも php暗号化コードを確認するための信頼できるセキュリティコンサルタントチーム (開示:雇用主)を雇うことができます。重要:暗号化を使用しない場合 do n'tencryptpasswords 。代わりに、これらのパスワードハッシュアルゴリズムのいずれかを使用してhashしたい: argon2 暗号化 bcrypt 86,000反復のpbkdf2-sha256 パスワードの保存に汎用ハッシュ関数(md5、sha256)を使用しないでください。 rlパラメータを暗号化しない 。これは、ジョブにとっては間違ったツールです。libsodiumを使用したphp文字列暗号化の例php <7.2を使用している場合、またはlibsodiumがインストールされていない場合は、 sodium_compat を使用して同じ結果を得ることができます(ただし遅い)。<?php declare(strict_types=1); /** * encrypt a message * * @param string $message - message to encrypt * @param string $key - encryption key * @return string * @throws rangeexception */ function safeencrypt(string $message, string $key): string { if (mb_strlen($key, '8bit') !== sodium_crypto_secretbox_keybytes) { throw new rangeexception('key is not the correct size (must be 32 bytes).'); } $nonce = random_bytes(sodium_crypto_secretbox_noncebytes); $cipher = base64_encode( $nonce. sodium_crypto_secretbox( $message, $nonce, $key ) ); sodium_memzero($message); sodium_memzero($key); return $cipher; } /** * decrypt a message * * @param string $encrypted - message encrypted with safeencrypt() * @param string $key - encryption key * @return string * @throws exception */ function safedecrypt(string $encrypted, string $key): string { $decoded = base64_decode($encrypted); $nonce = mb_substr($decoded, 0, sodium_crypto_secretbox_noncebytes, '8bit'); $ciphertext = mb_substr($decoded, sodium_crypto_secretbox_noncebytes, null, '8bit'); $plain = sodium_crypto_secretbox_open( $ciphertext, $nonce, $key ); if (!is_string($plain)) { throw new exception('invalid mac'); } sodium_memzero($ciphertext); sodium_memzero($key); return $plain; } それをテストするには:<?php // this refers to the previous code block. require "safecrypto.php"; // do this once then store it somehow: $key = random_bytes(sodium_crypto_secretbox_keybytes); $message = 'we are all living in a yellow submarine'; $ciphertext = safeencrypt($message, $key); $plaintext = safedecrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext); ハライト-libsodiumがより簡単に私が取り組んできたプロジェクトの1つは、 halite と呼ばれる暗号化ライブラリです。これは、libsodiumをより簡単で直感的にすることを目的としています。<?php use \paragonie\halite\keyfactory; use \paragonie\halite\symmetric\crypto as symmetriccrypto; // generate a new random symmetric-key encryption key. you're going to want to store this: $key = new keyfactory::generateencryptionkey(); // to save your encryption key: keyfactory::save($key, '/path/to/secret.key'); // to load it again: $loadedkey = keyfactory::loadencryptionkey('/path/to/secret.key'); $message = 'we are all living in a yellow submarine'; $ciphertext = symmetriccrypto::encrypt($message, $key); $plaintext = symmetriccrypto::decrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext); 基礎となる暗号化はすべてlibsodiumによって処理されます。defuse/php-encryptionを使用した例<?php /** * this requires https://github.com/defuse/php-encryption * php composer.phar require defuse/php-encryption */ use defuse\crypto\crypto; use defuse\crypto\key; require "vendor/autoload.php"; // do this once then store it somehow: $key = key::createnewrandomkey(); $message = 'we are all living in a yellow submarine'; $ciphertext = crypto::encrypt($message, $key); $plaintext = crypto::decrypt($ciphertext, $key); var_dump($ciphertext); var_dump($plaintext); 注:crypto::encrypt()は、16進数でエンコードされた出力を返します。暗号化キー管理「パスワード」を使用したい場合は、今すぐ停止してください。人間が記憶できるパスワードではなく、ランダムな128ビット暗号化キーが必要です。次のような長期使用のために暗号化キーを保存できます。$storeme = bin2hex($key); そして、オンデマンドで、次のように取得できます。$key = hex2bin($storeme); i strongly任意の種類のパスワードをキーとして使用する代わりに、ランダムに生成されたキーを長期間使用するために保存することをお勧めします(またはキーを導出します)。defuseのライブラリを使用している場合: $string = $keyobject->savetoasciisafestring() $loaded = key::loadfromasciisafestring($string); 「しかし、私は本当にパスワードを使いたい」それは悪い考えですが、大丈夫、ここでそれを安全に行う方法です。まず、ランダムキーを生成し、定数に保存します。/** * replace this with your own salt! * use bin2hex() then add \x before every 2 hex characters, like so: */ define('my_pbkdf2_salt', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf"); 余分な作業を追加することに注意してください。この定数をキーとして使用するだけで、多くの苦痛を軽減できます。次に、pbkdf2(など)を使用して、パスワードで直接暗号化するのではなく、パスワードから適切な暗号化キーを取得します。/** * get an aes key from a static password and a secret salt * * @param string $password your weak password here * @param int $keysize number of bytes in encryption key */ function getkeyfrompassword($password, $keysize = 16) { return hash_pbkdf2( 'sha256', $password, my_pbkdf2_salt, 100000, // number of iterations $keysize, true ); } 16文字のパスワードを使用しないでください。暗号化キーはコミカルに壊れます。