2017-02-09 57 views
2

如果我想使用Crypto ++庫加密數據,並且用戶定義的密碼短於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 
    ) 
); 

正如你所看到的,aesKey比32個字節短。

要將完整的32字節應用於加密函數,我只需用零填充未使用的空間,但這似乎並不是我的最佳解決方案。

我錯過了關於創建AES密鑰的事情嗎?用用戶定義的密碼?

我的第二個問題是,如果用戶選擇的密碼長度超過32 Byte,該怎麼辦?在我的情況下,密碼會被截斷,這聽起來並不正確。

感謝您的幫助!

+0

你是如何解決這個問題的? – jww

回答

2

如果我想加密數據,使用Crypto ++庫並且用戶定義的密碼短於32字節,該怎麼辦?

使用密鑰導出函數(KDF)來消化密碼。現代的是Krawczyk和Eronen的HKDF,使用Extract-then-Expand模型。該論文位於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}對。由於密碼有效地修復了AES密鑰,因此需要使用IV來確保每條消息的唯一性。


如果什麼用戶選擇的密碼長度超過32字節?在我的情況下,密碼會被截斷,這聽起來並不正確。

KDF爲您處理它。無論多少或多少,它都會提取熵。


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

沒有必要指定填充模式。另請參閱BlockPaddingScheme的文檔。


你應該非常小心CTR模式。 CTR模式異或是純文本的密鑰流。如果有人在不同的消息上重用他們的密碼,那麼它可能恢復導致明文恢復的密鑰流。

如果ivText對於每條消息都是唯一的,那麼您應該將其添加到您的KDF以確保每條消息具有唯一的密鑰流。添加IV作爲HKDF的salt參數。這裏,「唯一」表示如果我有一條消息「Hello World」,那麼每次我加密消息時IV都不同。

如果 IV確實只是「Iv16BytesOfText ...」(即它的固定值),那麼就沒有什麼特別的了。只需從用戶密碼中獲取額外的16個字節。然後,爲了避免密鑰流xor攻擊,切換到CBC等模式。

最後,您應該使用CCM,EAX或GCM模式。現在,你只有保密。通常你也想要真實性。爲了獲得真實性,您經常選擇Authenticated Encryption操作模式。

相關問題