PHP文字列をどのように暗号化および復号化しますか?


225

つまり、

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が、うまくいきませんでした。


35
@Rogue彼はハッシュを望んでおらず、対称暗号化(AESなど)を望んでいます。(そして今彼はそうします:))
Patashu 2013年

安全性はどの程度必要ですか?

3
@夏期劇場、対称暗号化を「ソルト」するのではなく、キーを使用します。鍵は秘密にしておく必要があります。ソルトは、セキュリティを損なうことなく公開でき(全員のソルトが異なる限り)、パスワードのハッシュに使用される用語です。
Patashu 2013年

2
Salt(秘密鍵)、公開鍵、AES-256のような暗号化アルゴリズムが必要です:wpy.me/blog/15-encrypt-and-decrypt-data-in-php-using-aes-256
wappy

8
@CristianFloreaそのブログ投稿の作成者は、対称暗号化のコンテキストで少しでも意味をなさない用語を使用しています。AESには公開鍵もなければソルトもありません。単一のキーがあります。それは秘密にされなければなりません。一部の操作モードでは、シークレットである必要はないIVがありますが、IVはソルトではなく(モードによっては、まったく異なる要件を持つ可能性があります)、シークレットである必要はありませんが、実際の暗号化キーは完全に公開することはできません。公開/秘密鍵は非対称暗号に適用されますが、AESとは関係ありません。
cpast 2015年

回答:


410

あなたはさらに何かをする前に、理解しようとの違いの暗号化認証を、あなたはおそらくしたい理由は、認証済みの暗号化だけではなく、暗号化を

認証された暗号化を実装するには、暗号化してからMACを使用します。暗号化と認証の順序は非常に重要です。この質問に対する既存の回答の1つがこの間違いを犯しました。PHPで書かれた多くの暗号化ライブラリと同様に。

独自の暗号化を実装することは避け、代わりに暗号化の専門家によって作成およびレビューされた安全なライブラリを使用してください

更新:PHP 7.2はlibsodiumを提供します!最高のセキュリティを確保するには、PHP 7.2以降を使用するようにシステムを更新し、この回答のlibsodiumのアドバイスのみに従ってください。

PECLアクセス権がある場合はlibsodiumを使用しますPECLなしでlibsodiumが必要な場合はodium_compat)。それ以外の場合...
defuse / php-encryptionを使用します。独自の暗号化を行わないでください。

上記のリンクされたライブラリはどちらも、認証された暗号化を独自のライブラリに実装することを簡単かつ容易にします。

それでも独自の暗号化ライブラリを作成して展開したい場合は、インターネット上のすべての暗号化の専門家の常識に反して、これらの手順を実行する必要があります。

暗号化:

  1. CTRモードでAESを使用して暗号化します。GCMを使用することもできます(これにより、個別のMACが不要になります)。さらに、ChaCha20およびSalsa20(libsodiumによって提供)はストリーム暗号であり、特別なモードを必要としません。
  2. 上記のGCMを選択しない限り、HMAC-SHA-256で暗号文を認証する必要があります(または、ストリーム暗号の場合は、Poly1305-ほとんどのlibsodium APIがこれを行います)。MACはIVと暗号文をカバーする必要があります!

解読:

  1. Poly1305またはGCMが使用されていない限り、暗号文のMACを再計算し、それをを使用して送信されたMACと比較しhash_equals()ます。失敗した場合は中止します。
  2. メッセージを復号化します。

その他の設計上の考慮事項:

  1. これまで何も圧縮しないでください。暗号文は圧縮できません。暗号化の前に平文を圧縮すると、情報漏えいが発生する可能性があります(TLSでのCRIMEやBREACHなど)。
  2. 問題の発生を防ぐために、文字セットモードを使用してmb_strlen()およびを使用していることを確認してください。mb_substr()'8bit'mbstring.func_overload
  3. IVはCSPRNGを使用して生成する必要があります。あなたが使用している場合はmcrypt_create_iv()使用をしないでくださいMCRYPT_RAND
  4. AEADコンストラクトを使用している場合を除き、常にMACを暗号化します。
  5. bin2hex()base64_encode()などは、キャッシュタイミングを介して暗号化キーに関する情報を漏洩する可能性があります。可能であれば避けてください。

ここで与えられたアドバイスに従ったとしても、暗号化で多くのことが失敗する可能性があります。暗号化の専門家に常に実装をレビューしてもらいます。あなたの地元の大学の暗号学の学生と個人的な友達になるほど幸運ではない場合は、いつでも暗号化スタック交換フォーラムを試してアドバイスを受けることができます。

実装の専門的な分析が必要な場合は、常に信頼できるセキュリティコンサルタントのチームを雇って、PHP暗号化コードを確認することができます(開示:私の雇用主)。

重要:暗号化を使用しない場合

パスワードを暗号化しないでください。あなたはしたいハッシュこれらのパスワードハッシュアルゴリズムのいずれかを使用して、代わりにそれら:

パスワードの保存には、汎用ハッシュ関数(MD5、SHA256)を使用しないでください。

URLパラメータを暗号化しませんそれは仕事にとって間違ったツールです。

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);

Halite-Libsodiumがより簡単に

私が取り組んできたプロジェクトの1つは、libsodiumをより簡単かつ直感的にすることを目的としたHaliteと呼ばれる暗号化ライブラリです。

<?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);

キーとして(またはキーを派生させるために)、あらゆる種類のパスワードの代わりに、長期間使用するためにランダムに生成されたキーを保存することを強くお勧めします。

Defuseのライブラリを使用している場合:

「しかし、私は本当にパスワードを使いたいのです。」

それは悪い考えですが、大丈夫、安全にそれを行う方法を次に示します。

まず、ランダムなキーを生成して定数に格納します。

/**
 * 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文字のパスワードを使用しないでください。暗号化キーは破壊されます。


3
パスワードを暗号化しないでください。ハッシュしてパスワードpassword_hash()を確認してくださいpassword_verify()
Scott Arciszewski、2015

2
「これまで何も圧縮しないでください。」HTTP、spdy、その他のプロトコルのようにですか?TLSの前?絶対主義者のアドバイスはたくさん?
Tiberiu-Ionuț Stan

1
@ScottArciszewskiキーについてのコメントが好きです "//これを一度保存​​して、どうにかして保存します:" ..どういうわけか、笑:))この「キー」(オブジェクト)をプレーンコードのハードコードとして保存するのはどうですか?キー自体が文字列として必要です。このオブジェクトからどうにかして取得できますか?ありがとう
アンドリュー

2
Thx、ナトリウムの例を機能させるために1行変更するだけでした:function getKeyFromPassword($password, $keysize = \Sodium\CRYPTO_SECRETBOX_KEYBYTES)
Alexey

1
うわー!+1は、URLパラメータを暗号化しないことを言及します。:私は本当にあなたが提供する記事を気に入っparagonie.com/blog/2015/09/...
Lynnellエマニュエル・ネリ

73

私はパーティーに遅れましたが、正しい方法を探していると、このページに出くわしました。これはGoogle検索のリターンのトップの1つだったので、問題についての私の見解を共有したいと思います。この投稿を執筆している時点での最新情報(2017年の初め)。PHP 7.1.0以降mcrypt_decryptおよびmcrypt_encryptは非推奨となるため、将来のプルーフコードの作成にはopenssl_encryptおよび openssl_decryptます。

次のようなことができます:

$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);

重要:これは、安全ではないECBモードを使用します。暗号工学の短期コースを受講せずに簡単な解決策が必要な場合は、自分で書くのではなく、ライブラリを使用してください。

セキュリティのニーズに応じて、他のチッパー方式も使用できます。利用可能なチッパーメソッドを見つけるには、openssl_get_cipher_methods関数を参照してください。


10
ありがとう、私はこの単純で明確な答えがこれ以上賛成されないことに驚いています。単純な文字列を暗号化/復号化することだけが必要な場合は、トップアンサーのようにこの件に関する10ページのディスカッションを読みたくありません。
laurent

4
これは安全な答えではありません。ECBモードは使用しないでください。「シンプルで明確な答え」が必要な場合は、ライブラリを使用してください
Scott Arciszewski 2017

2
@ScottArciszewski、はい、いくつかの簡単なコードを探している間、私はあまりにも早く話したことを認めます。それ以来、IVを追加し、自分のコードでCBCを使用しています。これで十分です。
laurent

これを読んで再考してください。CBCモードでは、攻撃者はメッセージを完全に変更できます。メッセージがファイルの場合、攻撃者はビットをめくってcalc.exeを開くことができます。認証されていない暗号化のリスクは深刻です。
Scott Arciszewski 2017

7
それはすべてユースケースに依存します!これが完全にFINEの場合があります。たとえば、ページ間でGETパラメータを渡したいとしましょう。たとえばprod_id=123、123をだれもが読めるようにしたくないのですが、たとえそれを読むことができたとしても、問題にはなりません。攻撃者が123をカスタム値に置き換えることができる場合、害はありません。攻撃者は他の製品の詳細のみを取得できますが、Joe Average Userは詳細を取得する方法の手がかりがありません。たとえば製品124。このようなシナリオでは、これは完璧なソリューションであり、セキュリティについてはそれはノーゴーです!
エミールボルコーニ2017

43

してはいけないこと

警告:
この回答ではECBを使用しています。ECBは暗号化モードではなく、単なるビルディングブロックです。この回答で示されているようにECBを使用しても、実際には文字列を安全に暗号化できません。コードでECBを使用しないでください。良い解決策についてはスコットの答えを見てください。

私は自分でそれを手に入れました。実際に私はグーグルでいくつかの答えを見つけ、何かを変更しました。ただし、結果は完全に安全ではありません。

<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";

echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);

/**
 * Returns an encrypted & utf8-encoded
 */
function encrypt($pure_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    return $encrypted_string;
}

/**
 * Returns decrypted original string
 */
function decrypt($encrypted_string, $encryption_key) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
    return $decrypted_string;
}
?>

8
「MCRYPT_MODE_ECB」の代わりに「MCRYPT_MODE_CBC」を使用して、セキュリティを強化できます。
Parixit 2013

10
Ramesh、これは生の暗号化データを取得しているためです。あなたはこのように、BASE64を使用して暗号化されたデータのよりよいバージョンを取得することができますbase64_encode(encrypt($string))-それを復号化するには:decrypt(base64_decode($encrypted))
mendezcode

82
警告:これは安全ではありません。ECBモードは文字列に使用しないでください。ECBはIVを取りません。これは認証されません。AESの代わりに古い暗号(Blowfish)を使用します。キーはバイナリではありませんなど。SOコミュニティは暗号化の提案を停止する必要があります/単に「機能」し、安全であることがわかっている回答に賛成投票を開始する復号化。それが確かにわからない場合は、投票しないでください。
Maarten Bodewes、2015

3
私は、php.netmcrypt_encrypt / manual / en / function.mcrypt-encrypt.phpのサンプルコードを置き換えることですでにこれをやっていました。今それをレビューすると、おそらく最後にrtrimfor文字があるはず"\0"です。
Maarten Bodewes、2015

4
正解は、独自のmcryptコードを作成する代わりに、defuse / php-encryptionのようなものを使用することです。
Scott Arciszewski、2015年

18

Laravelフレームワークの場合

Laravelフレームワークを使用している場合は、内部関数を使用して暗号化および復号化する方が簡単です。

$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);

var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);

注:config / app.phpファイルのkeyオプションには、16、24、または32文字のランダム文字列を設定してください。そうしないと、暗号化された値は保護されません。


1
もちろん、使いやすいかもしれません。しかし、それは安全ですか?stackoverflow.com/a/30159120/781723の問題にどのように対処しますか?認証された暗号化を使用していますか?サイドチャネルの脆弱性を回避し、一定時間の等価チェックを保証しますか?パスワード/パスフレーズではなく、本当にランダムなキーを使用していますか?適切な操作モードを使用していますか?ランダムIVは適切に生成されますか?
DW 2016

10

更新しました

PHP 7の準備バージョン。PHP OpenSSL Libraryのopenssl_encrypt関数を使用します

class Openssl_EncryptDecrypt {
    function encrypt ($pure_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $ciphertext_raw = openssl_encrypt($pure_string, $cipher, $encryption_key, $options, $iv);
        $hmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        return $iv.$hmac.$ciphertext_raw;
    }
    function decrypt ($encrypted_string, $encryption_key) {
        $cipher     = 'AES-256-CBC';
        $options    = OPENSSL_RAW_DATA;
        $hash_algo  = 'sha256';
        $sha2len    = 32;
        $ivlen = openssl_cipher_iv_length($cipher);
        $iv = substr($encrypted_string, 0, $ivlen);
        $hmac = substr($encrypted_string, $ivlen, $sha2len);
        $ciphertext_raw = substr($encrypted_string, $ivlen+$sha2len);
        $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $encryption_key, $options, $iv);
        $calcmac = hash_hmac($hash_algo, $ciphertext_raw, $encryption_key, true);
        if(function_exists('hash_equals')) {
            if (hash_equals($hmac, $calcmac)) return $original_plaintext;
        } else {
            if ($this->hash_equals_custom($hmac, $calcmac)) return $original_plaintext;
        }
    }
    /**
     * (Optional)
     * hash_equals() function polyfilling.
     * PHP 5.6+ timing attack safe comparison
     */
    function hash_equals_custom($knownString, $userString) {
        if (function_exists('mb_strlen')) {
            $kLen = mb_strlen($knownString, '8bit');
            $uLen = mb_strlen($userString, '8bit');
        } else {
            $kLen = strlen($knownString);
            $uLen = strlen($userString);
        }
        if ($kLen !== $uLen) {
            return false;
        }
        $result = 0;
        for ($i = 0; $i < $kLen; $i++) {
            $result |= (ord($knownString[$i]) ^ ord($userString[$i]));
        }
        return 0 === $result;
    }
}

define('ENCRYPTION_KEY', '__^%&Q@$&*!@#$%^&*^__');
$string = "This is the original string!";

$OpensslEncryption = new Openssl_EncryptDecrypt;
$encrypted = $OpensslEncryption->encrypt($string, ENCRYPTION_KEY);
$decrypted = $OpensslEncryption->decrypt($encrypted, ENCRYPTION_KEY);

1
これはより良く、はるかに安全なバージョンです。おかげで、それも期待どおりに動作します。

1
どのように作成し、暗号化キーをどこに保存しますか?
user2800464

7

歴史的注記:これはPHP4の時に書かれました。これは、現在「レガシーコード」と呼ばれています。

私は歴史的な目的のためにこの回答を残しました-しかし、いくつかの方法は現在非推奨であり、DES暗号化方法は推奨される方法ではありませんなど。

次の2つの理由でこのコードを更新していません。1)PHPで手動で暗号化メソッドを操作しなくなった、2)このコードは、それが意図した目的を果たします。 PHPで。

同様に単純化された「ダミーのPHP暗号化」ソースを見つけて、10〜20行以下のコードで人々を始めることができる場合は、コメントで知らせてください。

それ以上に、初期のPHP4ミニマルな暗号化の答えのこのクラシックエピソードをお楽しみください。


理想的には、mcrypt PHPライブラリへのアクセス権を持っている、または取得できることが理想的です。ここでは、さまざまな種類の暗号化といくつかのサンプルコードの概要を示します。PHPでの暗号化テクニック

//Listing 3: Encrypting Data Using the mcrypt_ecb Function 

<?php 
echo("<h3> Symmetric Encryption </h3>"); 
$key_value = "KEYVALUE"; 
$plain_text = "PLAINTEXT"; 
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT); 
echo ("<p><b> Text after encryption : </b>"); 
echo ( $encrypted_text ); 
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT); 
echo ("<p><b> Text after decryption : </b>"); 
echo ( $decrypted_text ); 
?> 

いくつかの警告:

1)一方向ハッシュが行う場合は、リバーシブルまたは「対称」暗号化を使用しないでください。

2)データがクレジットカードや社会保障番号のように本当に機密情報である場合は、停止します。単純なコードのチャンクが提供する以上のものが必要ですが、この目的のために設計された暗号ライブラリと、必要な方法を研究するためのかなりの時間が必要です。さらに、ソフトウェア暗号はおそらく機密データのセキュリティの10%未満です。それは、原子力発電所を再配線するようなものです。もしそうなら、その作業は危険で困難であり、あなたの知識を超えていることを受け入れてください。金銭的罰金は計り知れないものになる可能性があるため、サービスを利用して責任を船に送ったほうがよいでしょう。

3)簡単に実装できる暗号化は、ここにリストされているように、偶発的/意図的な漏洩の場合に、覗き見したくない、または露出を制限したい、軽度に重要な情報を合理的に保護できます。しかし、キーがWebサーバーにプレーンテキストでどのように格納されているかを見ると、データを取得できれば、復号化キーを取得できます。

それがそうであるように、楽しんでください:)


9
ええ、DES。AESはどこですか
Patashu 2013年

2
ありがとう!しかし、いくつかの問題。M�������f=�_=暗号化されたものとして奇妙な文字を取得しています。単純な文字を取得できませんか?のように:2a2ffa8f13220befbe30819047e23b2c。また、$key_value(8に固定???)の長さと出力の長さを変更できません$encrypted_textか?(32または64にできませんか?それ以上長くすることはできませんか??)
夏期劇場

3
@夏期劇場暗号化の結果はバイナリデータです。人間が読めるようにする必要がある場合は、base64または16進エンコーディングを使用してください。「キー値の長さを変更できませんか?」対称暗号化アルゴリズムが異なれば、キー値の要件も異なります。「および出力の長さ...」暗号化されたテキストの長さは、少なくとも元のテキストと同じ長さである必要があります。そうでない場合、元のテキストを再作成するのに十分な情報がありません。(これはピジョンホールの原則の適用です。)ところで、DESの代わりにAESを使用する必要があります。DESは壊れやすく、安全ではありません。
Patashu 2013年

8
mcrypt_ecbは、PHP 5.5.0で非推奨になりました。この関数に依存することはお勧めしません。php.net/manual/en/function.mcrypt-ecb.php
Hafez Divandari 2015年

1
@BrianDHallこれが依然として反対票を投じる理由は、ECBモードが安全ではない(CBC、CTR、GCM、またはPoly1305を使用する)、DESが弱い(AESが必要MCRYPT_RIJNDAEL_128)、そして暗号文を認証する必要があるためです(hash_hmac()、検証済み)でhash_equals())。
Scott Arciszewski、2015年

7

ライブラリを使用したくない場合は(次のようにする必要があります)、次のようなものを使用します(PHP 7)。

function sign($message, $key) {
    return hash_hmac('sha256', $message, $key) . $message;
}

function verify($bundle, $key) {
    return hash_equals(
      hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
      mb_substr($bundle, 0, 64, '8bit')
    );
}

function getKey($password, $keysize = 16) {
    return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}

function encrypt($message, $password) {
    $iv = random_bytes(16);
    $key = getKey($password);
    $result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
    return bin2hex($iv).bin2hex($result);
}

function decrypt($hash, $password) {
    $iv = hex2bin(substr($hash, 0, 32));
    $data = hex2bin(substr($hash, 32));
    $key = getKey($password);
    if (!verify($data, $key)) {
      return null;
    }
    return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}

$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);

これは、stackoverflow.com / a / 16606352/126833の代わりになるものですか?ホストをPHP 7.2にアップグレードするまで、前者を使用しました。
anjanesh

@anjaneshあなたはこれで古いデータを復号化することができなくなります(異なるアルゴリズム+これは署名もチェックします)
Ascon

2
あなたの場合、おそらくこれでうまくいくでしょう:define("ENCRYPTION_KEY", "123456*"); $string = "This is the original data string!"; $encrypted = openssl_encrypt($string, 'BF-ECB', ENCRYPTION_KEY); $decrypted = openssl_decrypt($encrypted,'BF-ECB',ENCRYPTION_KEY);
Ascon

これはスーパーです!
anjanesh

2

これらは、AES256 CBCを使用してPHPで文字列を暗号化/復号化するコンパクトな方法です。

function encryptString($plaintext, $password, $encoding = null) {
    $iv = openssl_random_pseudo_bytes(16);
    $ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, $iv);
    $hmac = hash_hmac('sha256', $ciphertext.$iv, hash('sha256', $password, true), true);
    return $encoding == "hex" ? bin2hex($iv.$hmac.$ciphertext) : ($encoding == "base64" ? base64_encode($iv.$hmac.$ciphertext) : $iv.$hmac.$ciphertext);
}

function decryptString($ciphertext, $password, $encoding = null) {
    $ciphertext = $encoding == "hex" ? hex2bin($ciphertext) : ($encoding == "base64" ? base64_decode($ciphertext) : $ciphertext);
    if (!hash_equals(hash_hmac('sha256', substr($ciphertext, 48).substr($ciphertext, 0, 16), hash('sha256', $password, true), true), substr($ciphertext, 16, 32))) return null;
    return openssl_decrypt(substr($ciphertext, 48), "AES-256-CBC", hash('sha256', $password, true), OPENSSL_RAW_DATA, substr($ciphertext, 0, 16));
}

使用法:

$enc = encryptString("mysecretText", "myPassword");
$dec = decryptString($enc, "myPassword");

0

以下のコードは、特殊文字を含むすべての文字列に対してphpで機能します

   // Encrypt text --

    $token = "9611222007552";

      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);  
      $enc_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher_method));  
      $crypted_token = openssl_encrypt($token, $cipher_method, $enc_key, 0, $enc_iv) . "::" . bin2hex($enc_iv);
    echo    $crypted_token;
    //unset($token, $cipher_method, $enc_key, $enc_iv);

    // Decrypt text  -- 

    list($crypted_token, $enc_iv) = explode("::", $crypted_token);  
      $cipher_method = 'aes-128-ctr';
      $enc_key = openssl_digest(php_uname(), 'SHA256', TRUE);
      $token = openssl_decrypt($crypted_token, $cipher_method, $enc_key, 0, hex2bin($enc_iv));
    echo   $token;
    //unset($crypted_token, $cipher_method, $enc_key, $enc_iv);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.