0

次の関数を使用して、Qt の OpenSSL ライブラリ経由でデータを暗号化しています。

QByteArray Crypto::Encrypt(QByteArray source, QString password)
{
  EVP_CIPHER_CTX en;

  unsigned char *key_data;
  int key_data_len;

  QByteArray ba = password.toLatin1();
  key_data = (unsigned char*)ba.data();
  key_data_len = strlen((char*)key_data);

  int nrounds = 28;
  unsigned char key[32], iv[32];

  EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, key_data, key_data_len, nrounds, key, iv);

QByteArray bkey = reinterpret_cast<const char*>(key) //EDIT: Contains the key afterwards
QByteArray biv = reinterpret_cast<const char*>(iv) //EDIT: Is Null afterwards

  EVP_CIPHER_CTX_init(&en);
  EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);

  char *input = source.data();
  char *out;
  int len = source.size();

  int c_len = len + 16, f_len = 0;
  unsigned char *ciphertext = (unsigned char *)malloc(c_len);

  EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL);
  EVP_EncryptUpdate(&en, ciphertext, &c_len, (unsigned char *)input, len);
  EVP_EncryptFinal_ex(&en, ciphertext+c_len, &f_len);

  len = c_len + f_len;

  out = (char*)ciphertext;

  EVP_CIPHER_CTX_cleanup(&en);

  return QByteArray(out, len);
}

その場合、「ソース」は「12345678901234567890123456789012abc」です。
「パスワード」「1hA!dh==sJAh48S8Ak!?skiitFi120xX」です。

だから....私がその権利を得た場合、 EVP_BytesToKey() はパスワードからキーを生成し、後で文字列を復号化するためのデータを提供する必要があります。

Base64 でエンコードされたキーは次のようになります

そのため、Base64 の QByteArray bkey は"aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE="
QByteArray bvi からNullが返されます

暗号化テキストは"CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr"です。

現在、次の PHP 関数を使用して、生成されたキーで暗号文を再度復号化しています。

<?php
function decrypt_data($data, $iv, $key) {
    $cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

    //if(is_null($iv)) {
    //    $ivlen = mcrypt_enc_get_iv_size($cypher);
    //    $iv = substr($data, 0, $ivlen);
    //    $data = substr($data, $ivlen);
    //}

    // initialize encryption handle
    if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
            // decrypt
            $decrypted = mdecrypt_generic($cypher, $data);

            // clean up
            mcrypt_generic_deinit($cypher);
            mcrypt_module_close($cypher);

            return $decrypted;
    }

    return false;
}

$ctext = "CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr";
$key = "aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE=";

$res = decrypt_data(base64_decode($ctext), null, base64_decode($key));

echo $res;
?>

これで、 "12345678901234567890123456789012abc"のような応答が期待できます。
私が得るのは"7890123456789012abc"です。

私の文字列は正しい方法で復号化されているようですが、半分にカットされ、最後の 19 文字だけが表示されます。誰かが私を助けてくれますか?私は暗号化に不慣れで、正確にどこが間違っていたのか本当にわかりません。

4

2 に答える 2

0

試行錯誤で空の初期化ベクトルの問題を解決しましたが、以下が問題であった理由はまったくわかりません。誰かが私にそれを説明できるかもしれません。

行の変更: int nrounds = 28; トリックをしました。

そこに28以外の数字を入力すると、IV が生成され、後で mcrypt で使用すると、暗号文は正しい方法で復号化されます。openssl-function EVP_BytesToKey()を使用して28ラウンドでキーを生成することが問題だったのはなぜですか? 今は5ラウンドに減らしましたが、このような Null-IV を生成する可能性のあるパスワード ラウンドの組み合わせで、この問題が再び発生する可能性があるかどうかに興味があります。

この関数で IV 生成のプロセスがどのように処理されるかはよくわかりません。

于 2013-08-27T11:21:08.137 に答える
0

これはおそらく、あなたの側の誤解によるものです。あなたは言う:

私はソルトを使用しないので、IV はありません (null にする必要があります)。

しかし、なぜそうなるのかという理由はまったくありません。このEVP_BytesToKey方法では、キーと IV の両方が提供されました。キーは明らかに正しいですが、IV は正しくありません。これにより、プレーン テキストでランダムな文字が生成されます (IV は最初のブロックのみを変更します)。このブロックには制御文字などが含まれている可能性が高いため、うまく表示されない場合があります。

ソルトと IV にはいくつかの共通点があるかもしれませんが (繰り返してはならない、パブリックにすることができるなど)、暗号化ではまったく異なる概念であることを忘れないでください。

Qt コードでもう一度試してください。今度は IV とキーを出力してください...

于 2013-08-21T00:31:09.123 に答える