如何使用用户定义的密码初始化AES-256密钥

问题描述 投票:2回答:1

如果我想使用Crypto ++库加密数据并使用短于32字节的用户定义密码,该怎么办?

现在我有以下代码:

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字节怎么办?在我的情况下,密码将被截断,这听起来不对我。

谢谢你的帮助!

c++ encryption aes crypto++
1个回答
4
投票

如果我想使用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模式xor是具有纯文本的密钥流。如果有人在不同的消息上重复使用他们的密码,那么可以恢复密钥流,从而导致明文恢复。

如果ivText对于每条消息都是唯一的,那么您应该将其添加到KDF以确保每条消息的唯一密钥流。将IV添加为HKDF的salt参数。这里,“唯一”意味着如果我有一个消息“Hello World”,那么每次加密消息时IV都不同。

如果IV真的只是“Iv16BytesOfText ...”(即它的固定),那么它没有什么独特之处。只需从用户密码中获取额外的16个字节。然后,为了避免密钥流xor攻击,切换到类似CBC的模式。

最后,您应该使用CCM,EAX或GCM模式。现在,你只有机密性。通常你也想要真实性。为了获得真实性,您经常选择Authenticated Encryption操作模式。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.