使用C++和Crypto++庫進(jìn)行加密解密
在這篇博客中,我們將深入探討如何利用C++和Crypto++庫實現(xiàn)高效且安全的AES加密與解密機(jī)制。Crypto++是一款高度認(rèn)可的免費C++類庫,它包含了廣泛的密碼學(xué)算法實現(xiàn),包括但不限于AES和SHA-1。我們的討論將重點放在構(gòu)建一個強(qiáng)大的AES加密解密類結(jié)構(gòu)上,同時充分利用Crypto++庫的強(qiáng)大功能。
首先,我們引入了一個名為Crypt的基類。該類精心設(shè)計了四個純虛函數(shù),分別負(fù)責(zé)字符串和二進(jìn)制數(shù)據(jù)的加密與解密。這種設(shè)計遵循了策略模式的思想,它為運行時切換加密和解密的具體實現(xiàn)提供了靈活性。這不僅體現(xiàn)了面向?qū)ο缶幊痰亩鄳B(tài)特性,也為未來可能的擴(kuò)展提供了堅實的基礎(chǔ)。
class Crypt
{
public:
Crypt() = default;
virtual ~Crypt() = default;
virtual std::string Encrypt(const std::string& input) = 0;
virtual std::string Decrypt(const std::string& input) = 0;
virtual std::string Encrypt(const void* input, size_t size) = 0;
virtual std::string Decrypt(const void* input, size_t size) = 0;
};
繼而,我們引入了AEScrypt類,它是Crypt的一個具體實現(xiàn),專門負(fù)責(zé)AES加密和解密。此類的設(shè)計精巧地運用了Pimpl(Pointer to Implementation)模式,通過一個指向AESImpl類的智能指針impl_將接口和實現(xiàn)分離。這種模式不僅提升了代碼的可維護(hù)性,還有效地隔離了接口變更對實現(xiàn)的影響,是現(xiàn)代C++設(shè)計中的一種常見而有效的實踐。
class AEScrypt : public Crypt
{
public:
static std::string GetKey(const std::string& salt, const std::string& password);
explicit AEScrypt(const std::string& key);
~AEScrypt() override;
std::string Encrypt(const std::string& input) override;
std::string Decrypt(const std::string& input) override;
std::string Encrypt(const void* input, size_t size) override;
std::string Decrypt(const void* input, size_t size) override;
private:
std::unique_ptr<AESImpl> impl_;
};
AEScrypt類中包含的靜態(tài)函數(shù)GetKey,使用PBKDF2算法從鹽值和密碼生成AES密鑰。PBKDF2是一種基于密碼的密鑰導(dǎo)出函數(shù),其核心優(yōu)勢在于其高計算復(fù)雜度,這顯著增加了抵御暴力破解攻擊的難度。通過調(diào)整迭代次數(shù),可以進(jìn)一步提高安全性。
AEScrypt構(gòu)造函數(shù)接受一個AES密鑰,并利用這個密鑰初始化其impl_成員。隨后,Encrypt和Decrypt函數(shù)便可以調(diào)用impl_成員的對應(yīng)方法來執(zhí)行加密和解密操作。
class AESImpl
{
public:
explicit AESImpl(const std::string& key);
~AESImpl();
AESImpl(const AESImpl&) = delete;
AESImpl& operator=(const AESImpl&) = delete;
void Init(const char* key, size_t size);
std::string Encrypt(const void* input, size_t size);
std::string Decrypt(const void* input, size_t size);
private:
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc_;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec_;
byte iv_[CryptoPP::AES::BLOCKSIZE] = {0};
};
using byte = CryptoPP::byte;
class AESImpl
{
public:
explicit AESImpl(const std::string& key);
~AESImpl();
AESImpl(const AESImpl&) = delete;
AESImpl& operator=(const AESImpl&) = delete;
void Init(const char* key, size_t size);
std::string Encrypt(const void* input, size_t size);
std::string Decrypt(const void* input, size_t size);
private:
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption enc_;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption dec_;
byte iv_[CryptoPP::AES::BLOCKSIZE] = {0};
};
AESImpl::AESImpl(const std::string& key)
{
Init(key.data(), key.size());
}
AESImpl::~AESImpl() = default;
void AESImpl::Init(const char* key, size_t size)
{
enc_.SetKeyWithIV(reinterpret_cast<const byte*>(key), size, iv_);
dec_.SetKeyWithIV(reinterpret_cast<const byte*>(key), size, iv_);
}
std::string AESImpl::Encrypt(const void* input, size_t size)
{
std::string cipher;
try
{
CryptoPP::StringSource ss(reinterpret_cast<const byte*>(input), size, true,
new CryptoPP::StreamTransformationFilter(enc_,
new CryptoPP::StringSink(cipher),
CryptoPP::StreamTransformationFilter::PKCS_PADDING));
}
catch (const CryptoPP::Exception& e)
{
return "";
}
return cipher;
}
std::string AESImpl::Decrypt(const void* input, size_t size)
{
std::string recovered;
try
{
CryptoPP::StringSource ss(reinterpret_cast<const byte*>(input), size, true,
new CryptoPP::StreamTransformationFilter(dec_,
new CryptoPP::StringSink(recovered),
CryptoPP::StreamTransformationFilter::PKCS_PADDING));
}
catch (const CryptoPP::Exception& e)
{
return "";
}
return recovered;
}
std::string AEScrypt::GetKey(const std::string& salt, const std::string& password)
{
CryptoPP::SecByteBlock key(CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA256> pbkdf;
pbkdf.DeriveKey(key, key.size(), 0,
reinterpret_cast<const CryptoPP::byte*>(password.data()), password.size(),
reinterpret_cast<const CryptoPP::byte*>(salt.data()), salt.size(),
1000, 0.0);
return std::string(reinterpret_cast<char*>(key.BytePtr()), key.size());
}
AEScrypt::AEScrypt(const std::string& key) : impl_(std::make_unique<AESImpl>(key))
{
}
AEScrypt::~AEScrypt() = default;
std::string AEScrypt::Encrypt(const std::string& input)
{
return impl_->Encrypt(input.data(), input.size());
}
std::string AEScrypt::Decrypt(const std::string& input)
{
return impl_->Decrypt(input.data(), input.size());
}
std::string AEScrypt::Encrypt(const void* input, size_t size)
{
return impl_->Encrypt(input, size);
}
std::string AEScrypt::Decrypt(const void* input, size_t size)
{
return impl_->Decrypt(input, size);
}
在AESImpl類中,私有成員enc_和dec_分別用于AES的加密和解密操作。這兩個成員是`CryptoPP::CBC_Mode<CryptoPP::
AES>::Encryption和CryptoPP::CBC_ModeCryptoPP::AES::Decryption`的實例,代表AES的CBC(Cipher Block Chaining)模式。CBC模式是塊密碼的一種常見工作模式,它通過鏈?zhǔn)讲僮髟鰪?qiáng)了加密的安全性。