2017-02-09 10 views
2

データを暗号化し、Crypto ++ライブラリを使用し、32バイト未満のユーザ定義パスワードを使用する場合はどうなりますか?あなたが見ることができるようにaesKeyが32バイトより短い場合、ユーザ定義のパスワードでAES-256キーを初期化する方法

byte passwordBytes[AES::MAX_KEYLENGTH]; 
byte ivBytes[AES::BLOCKSIZE]; 
std::string textToEncrypt("encryptMe"); 
std::string aesKey("passwordFromUser"); 
std::string ivText("Iv16BytesOfText..."); 

memset(passwordBytes, 0, sizeof(passwordBytes)); //fill with zeroes first 
memcpy(passwordBytes, aesKey.data(), aesKey.size()); //fill with key data 
memcpy(ivBytes, ivText.data(), CryptoPP::AES::BLOCKSIZE); //fill iv bytes 

CTR_Mode<AES>::Encryption encryption; 
encryption.SetKeyWithIV(passwordBytes, sizeof(passwordBytes), ivBytes); 

StringSource encryptor(textToEncrypt, true, 
    new StreamTransformationFilter(encryption, 
      new StringSink(verschluesselterText) 
     ,StreamTransformationFilter::NO_PADDING 
    ) 
); 

今私は、次のコードを持っています。

暗号化機能に完全な32バイトを適用するには、使用されていない領域にゼロを書きますが、これは私にとって最善の解決策ではありません。

AESキーの作成に関して何か不足していますか?ユーザー定義のパスワードを使用していますか?

私の2番目の質問は、ユーザーが32バイト以上のパスワードを選択するとどうなりますか?私の場合、パスワードは切り捨てられますが、それは私には正しいとは言えません。

ありがとうございました!

+0

この問題をどのように解決しましたか? – jww

答えて

2

Crypto ++ライブラリを使用してデータを暗号化し、ユーザー定義のパスワードが32バイト未満の場合はどうなりますか?

パスワード派生機能(KDF)を使用してパスワードを消化します。現代のものは、Extract-then-Expandモデルを使用するKrawczykとEronenのHKDFです。論文はCryptographic Extraction and Key Derivation: The HKDF Schemeにあります。

IVにも使用することを検討する必要があります。 32バイト(AES::MAX_KEYLENGTH)を導出するのではなく、代わりに48バイト(AES::MAX_KEYLENGTH+AES::BLOCKSIZE)を派生させます。デザイン内のIVは、KDFのパラメータsaltに使用できます。

たぶんのようなもの:

#include <iostream> 
#include <string> 
using namespace std; 

#include "cryptlib.h" 
#include "aes.h" 
#include "sha.h" 
#include "hkdf.h" 
#include "modes.h" 
#include "filters.h" 
using namespace CryptoPP; 

int main(int argc, char* argv[]) 
{ 
    SecByteBlock key(AES::MAX_KEYLENGTH+AES::BLOCKSIZE); 
    string password("passwordFromUser"), iv("<random value>"), message("encryptMe"); 
    string encrypted, recovered; 

    try 
    { 
    HKDF<SHA256> hkdf; 
    hkdf.DeriveKey(key, key.size(), (const byte*)password.data(), password.size(), (const byte*)iv.data(), iv.size(), NULL, 0); 

    /////////////////////////////////////////////////////////////////////// 

    CTR_Mode<AES>::Encryption encryption; 
    encryption.SetKeyWithIV(key, AES::MAX_KEYLENGTH, key+AES::MAX_KEYLENGTH); 

    StringSource encryptor(message, true, 
     new StreamTransformationFilter(encryption, 
     new StringSink(encrypted)) 
    ); 

    /////////////////////////////////////////////////////////////////////// 

    CTR_Mode<AES>::Decryption decryption; 
    decryption.SetKeyWithIV(key, AES::MAX_KEYLENGTH, key+AES::MAX_KEYLENGTH); 

    StringSource decryptor(encrypted, true, 
     new StreamTransformationFilter(decryption, 
     new StringSink(recovered)) 
    ); 

    cout << "Message: " << message << endl; 
    cout << "Recovered: " << recovered << endl; 
    } 
    catch(const Exception& ex) 
    { 
    cerr << ex.what() << endl; 
    return 1; 
    } 

    return 0; 
} 

上記の暗号化方式を使用している場合、あなたは{iv,message}ペアを追跡する必要があります。 IVは、パスワードが効果的にAESキーを修正するため、メッセージごとの一意性を保証するために必要です。


何ユーザーは、その後長い32バイトであるパスワードを選択した場合?私の場合、パスワードは切り捨てられてしまいますが、それは私には正しいとは言えません。

KDFがそれを処理します。エントロピーは、どれほどか、どれくらいかにかかわらず抽出されます。


StringSource encryptor(textToEncrypt, true, 
    new StreamTransformationFilter(encryption, 
     new StringSink(verschluesselterText), 
     StreamTransformationFilter::NO_PADDING 
    ) 

パディングモードを指定する必要はありません。 BlockPaddingSchemeのドキュメントも参照してください。


CTRなどのモードには注意が必要です。 CTRモードxorはプレーンテキストのキーストリームです。誰かが別のメッセージでパスワードを再利用すると、キーストリームを回復して平文回復につながる可能性があります。

ivTextが各メッセージに固有の場合は、メッセージごとに一意のキーストリームを確保するためにKDFに追加する必要があります。 IVをHKDFのsaltパラメータとして追加します。ここで「ユニーク」は、メッセージ「」が「Hello World」の場合、メッセージを暗号化するたびにIVが異なることを意味します。

IVはまさに "Iv16BytesOfText ..."(つまりその固定)ですが、それに固有のものは何もありません。ユーザーのパスワードからさらに16バイトを派生させるだけです。その後、キーストロークxor攻撃を避けるために、CBCのようなモードに切り替えます。

最後に、おそらくCCM、EAX、またはGCMモードを使用する必要があります。今、あなたは秘密を持っています。通常、真偽も欲しい。信頼性を得るために、多くの場合、Authenticated Encryptionモードを選択します。

関連する問題