马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
问题
加密
- 输入:<plaintext> <key> <iv>
-
- 输出:<ciphertext>
-
- 例如
-
- 输入:<i love you, sunsiqi> <0123456789ABCDEF> <FEDCBA0123456789>
-
- 输出:<4e152ec964f73950dfc7a3d833bdaeffd6f0b8a727c13c29>
复制代码 解密
- 输入:<ciphertext> <key> <iv>
-
- 输出:<plaintext>
-
- 例如
-
- 输入:<4e152ec964f73950dfc7a3d833bdaeffd6f0b8a727c13c29> <0123456789ABCDEF> <FEDCBA0123456789>
-
- 输出:<i love you, sunsiqi>
复制代码 要求
- 举行安全内存管理
- 加密或解密操作完成后清算敏感数据
介绍
CTR模式
CTR(Counter)模式即计数器模式,是一种流暗码模式。它将一个递增的计数器值通过加密算法加密后与明文举行异或运算得到密文,解密时使用相同的计数器值加密后再与密文异或得到明文。计数器模式把块暗码转换为流暗码,可并行处理数据,并且支持随机访问。
特点
- 流暗码特性:DES - CTR 模式将 DES 块暗码转换为流暗码,答应对任意长度的数据举行加密,而不必要对数据举行填充。
- 并行处理:由于每个计数器值的加密操作是相互独立的,因此可以并行处理,进步加密息争密的效率。
- 随机访问:可以在任意位置开始解密,而不必要解密前面的所有数据块,这在必要随机访问加密数据的应用中非常有效。
工作原理
- 初始化计数器:选择一个初始计数器值(通常称为初始向量,IV),计数器的长度通常与 DES 算法的块长度相同(64 位)。
- 计数器递增:在每次加密或解密操作前,计数器的值递增。
- 加密计数器值:使用 DES 算法对当前计数器值举行加密,得到一个 64 位的加密块。
- 异或运算:将加密块与明文数据的相应部分举行异或运算,得到密文数据。解密时,使用相同的计数器值举行加密,然后与密文数据举行异或运算,得到明文数据。
特性
特性CTR模式初始化向量称为计数器(Counter)填充要求无需填充并行性支持并行加密/解密错误流传只影响单个字节密钥流重用绝对禁止(计数器必须唯一)典范应用场景实时流加密、随机访问 长处
- 高效性:支持并行处理,加密息争密速度快。
- 机动性:不必要对数据举行填充,可处理任意长度的数据。
- 随机访问:可以在任意位置开始解密,实用于随机访问场景。
缺点
- 密钥管理:必要确保计数器值的唯一性,否则大概会导致安全毛病。如果两个差异的加密操作使用了相同的计数器值,攻击者可以通过异或两个密文来恢复部分明文信息。
- 安全性依靠:DES 算法自己的密钥长度较短,存在被暴力破解的风险,因此 DES - CTR 模式的安全性也受到一定影响。在对安全性要求较高的场景中,建议使用更安全的加密算法。
分析
为什么要清算敏感数据?
敏感数据(如加密密钥、明文数据、初始化向量等)在使用完毕后如果不及时清算,大概会残留在内存中,存在安全风险。攻击者有大概通过某些本领从内存中恢复这些敏感信息,从而造成数据泄露。
在加密或解密操作完成后必要清算敏感数据,本文主要描述两种操作方式:
- 在方法体内立即实验。在加密或解密方法的加密或解密操作之后添加安全清算敏感数据的代码。使用volatile指针防止编译器优化清零操作。
- volatile char* volatile_key = reinterpret_cast<volatile char*>(&key[0]);
- volatile char* volatile_iv = reinterpret_cast<volatile char*>(&iv[0]);
- std::fill(volatile_key, volatile_key + key.size(), 0);
- std::fill(volatile_iv, volatile_iv + iv.size(), 0);
复制代码 - 使用RAII方式。
- RAII(Resource Acquisition Is Initialization)即 “资源获取即初始化”,是 C++ 中管理资源、避免资源泄漏的一种编程惯用法。
- RAII 使用对象的生命周期来管理资源。当一个对象被创建时,它会自动获取所需的资源;当对象的生命周期竣事时(例如,对象脱离其作用域),它会自动开释这些资源。这里的资源可以是各种必要手动管理的东西,如内存、文件句柄、网络连接、数据库连接等。
- RAII 的核心原理基于 C++ 的构造函数和析构函数机制:
构造函数:在对象创建时自动调用,负责资源的获取。
析构函数:在对象销毁时自动调用,负责资源的开释。
通过这种方式,资源的生命周期与对象的生命周期绑定在一起,从而确保资源在不必要时被精确开释。
- // 新增安全擦除类,在namespace SymCryptoUtilities中添加安全擦除类
- class SecureWiper {
- public:
- SecureWiper(std::string& data) : m_data(data) {}
- ~SecureWiper() {
- // 添加调试输出验证清理操作
- std::cout << "Wiping data at: " << (void*)&m_data[0] << std::endl;
- if (!m_data.empty()) {
- // 使用volatile指针防止编译器优化清零操作
- volatile char* ptr = reinterpret_cast<volatile char*>(&m_data[0]);
- std::fill(ptr, ptr + m_data.size(), 0);
- }
- }
- private:
- std::string& m_data;
- };
复制代码 在main函数解码key和iv之后创建安全擦除对象,在此之后实验加密或解密操作,在return 0;之后自动调用wipe_key和wipe_iv的析构函数完成清算
- // 创建安全擦除对象,在main函数的解码key和iv之后创建安全擦除对象,在此之后执行加密或解密操作,在return 0;之后自动调用wipe_key和wipe_iv的析构函数完成清理
- SymCryptoUtilities::SecureWiper wipe_key(key);
- SymCryptoUtilities::SecureWiper wipe_iv(iv);
复制代码 在main函数中必要移除const修饰符,答应修改key和iv。
- // 原代码
- const std::string key = SymCryptoUtilities::hexDecode(keyHex);
- const std::string iv = SymCryptoUtilities::hexDecode(ivHex);
- // 修改为
- std::string key = SymCryptoUtilities::hexDecode(keyHex);
- std::string iv = SymCryptoUtilities::hexDecode(ivHex);
复制代码 安全擦除机制
- 使用volatile指针防止编译器优化清零操作
- 通过RAII确保脱离作用域自动清算,清算操作在栈展开时自动实验,即使加密过程中抛出异常,RAII对象也会保证清算内存
- 覆盖所有内存区域(包括短字符串优化的栈内存)
内存管理优化
在main函数中使用Crypto++的SecByteBlock替代std::string,SecByteBlock会在析构时自动安全擦除内存。
SecByteBlock 是 Crypto++ 库中用于管理字节数组的类,它在一定水平上提供了自动内存管理功能。当 SecByteBlock 对象的生命周期竣事时,其析构函数会自动开释所占用的内存。然而,这并不意味着内存中的数据会被安全地清算。为了确保敏感数据不会残留在内存中,仍旧必要在对象销毁前自动清算数据。可以通过自定义一个类,使用其构造函数和析构函数来实现 RAII 方式的敏感数据清算。
- CryptoPP::SecByteBlock key = SymCryptoUtilities::hexDecode(keyHex);
- CryptoPP::SecByteBlock iv = SymCryptoUtilities::hexDecode(ivHex);
复制代码 代码
头文件
- #include <iostream>
- #include <string>
- #include <cctype>
- #include <cryptopp/des.h>
- #include <cryptopp/modes.h>
- #include <cryptopp/filters.h>
- #include <cryptopp/hex.h>
- #include <stdexcept>
复制代码 主函数
- int main(int argc, char* argv[]) {
- if (argc != 4) {
- if (argc != 4) {
- std::cerr << "Usage: " << argv[0] << " <plaintext> <hex_key> <hex_counter>\n"
- << "Example: " << argv[0] << " "SecretData" 0123456789ABCDEF FEDCBA9876543210\n"
- << "Note: Key and Counter must be 16-character hexadecimal strings (8 bytes)\n"
- << "Note: support arbitrary binary data such as Chinese characters\n"
- << "Note: no padding is required when using the CTR mode."
- << std::endl;
- return 1;
- }
- }
- const std::string plaintext = argv[1];
- const std::string keyHex = argv[2];
- const std::string counterHex = argv[3];
- try {
- // 输入验证
- if (keyHex.length() != 16 || !SymCryptoUtilities::isValidHex(keyHex)) {
- throw std::invalid_argument("Key must be 16-character hex string (8 bytes)");
- }
- if (counterHex.length() != 16 || !SymCryptoUtilities::isValidHex(counterHex)) {
- throw std::invalid_argument("Counter must be 16-character hex string (8 bytes)");
- }
- /*
- 内存管理优化,在main函数中使用Crypto++的SecByteBlock替代std::string,SecByteBlock会在析构时自动安全擦除内存。
- SecByteBlock 是 Crypto++ 库中用于管理字节数组的类,它在一定程度上提供了自动内存管理功能。当 SecByteBlock 对象的生命周期结束时,其析构函数会自动释放所占用的内存。然而,这并不意味着内存中的数据会被安全地清理。为了确保敏感数据不会残留在内存中,仍然需要在对象销毁前主动清理数据。可以通过自定义一个类,利用其构造函数和析构函数来实现 RAII 方式的敏感数据清理。
-
- CryptoPP::SecByteBlock key = SymCryptoUtilities::hexDecode(keyHex);
- CryptoPP::SecByteBlock iv = SymCryptoUtilities::hexDecode(ivHex);
- */
- // 十六进制解码密钥和计数器,移除const设置,允许修改
- std::string key = SymCryptoUtilities::hexDecode(keyHex);
- std::string counter = SymCryptoUtilities::hexDecode(counterHex);
- /* RAII安全擦除
- 创建安全擦除对象。在解码之后创建安全擦除对象,在此之后执行加密或解密操作。
- 程序运行完return 0;之后,自动调用wipe_key和wipe_counter的析构函数完成清理
- */
- SymCryptoUtilities::SecureWiper wipe_key(key);
- SymCryptoUtilities::SecureWiper wipe_counter(counter);
- // 执行加密
- const std::string ciphertext = SymCryptoUtilities::desCTREncrypt(plaintext, key, counter);
- std::cout << "Ciphertext (hex): " << ciphertext << std::endl;
- } catch (const std::exception& e) {
- std::cerr << "Error: ";
- try {
- std::rethrow_if_nested(e);
- } catch (const std::exception& nested) {
- std::cerr << nested.what() << std::endl;
- return 2;
- }
- std::cerr << e.what() << std::endl;
- return 1;
- }
- return 0;
- }
复制代码 加密
方法
- namespace SymCryptoUtilities {
- bool isValidHex(const std::string& hexStr) {
- if (hexStr.empty()) return false;
- for (char c : hexStr) {
- if (!std::isxdigit(c)) return false;
- }
- return true;
- }
- std::string hexDecode(const std::string& hexStr) {
- if (hexStr.length() % 2 != 0) {
- throw std::invalid_argument("Hex string must have even length");
- }
- std::string decoded;
- CryptoPP::StringSource ss(
- hexStr, true,
- new CryptoPP::HexDecoder(
- new CryptoPP::StringSink(decoded)
- )
- );
- return decoded;
- }
- std::string hexEncode(const std::string& data) {
- std::string encoded;
- CryptoPP::StringSource ss(
- data, true,
- new CryptoPP::HexEncoder(
- new CryptoPP::StringSink(encoded),
- false // 无换行符
- )
- );
- return encoded;
- }
- /*
- RAII(Resource Acquisition Is Initialization)即 “资源获取即初始化”,是 C++ 中管理资源、避免资源泄漏的一种编程惯用法。
- RAII 利用对象的生命周期来管理资源。当一个对象被创建时,它会自动获取所需的资源;当对象的生命周期结束时(例如,对象离开其作用域),它会自动释放这些资源。这里的资源可以是各种需要手动管理的东西,如内存、文件句柄、网络连接、数据库连接等。
- RAII 的核心原理基于 C++ 的构造函数和析构函数机制:
- 构造函数:在对象创建时自动调用,负责资源的获取。
- 析构函数:在对象销毁时自动调用,负责资源的释放。
- 通过这种方式,资源的生命周期与对象的生命周期绑定在一起,从而确保资源在不需要时被正确释放。
- 通过RAII确保离开作用域自动清理,清理操作在栈展开时自动执行,即使加密过程中抛出异常,RAII对象也会保证清理内存
- */
- // 安全擦除类(RAII)
- class SecureWiper {
- public:
- SecureWiper(std::string& data) : m_data(data) {}
- ~SecureWiper() {
- // 添加调试输出验证清理操作
- std::cout << "Wiping data at: " << (void*)&m_data[0] << std::endl;
- if (!m_data.empty()) {
- // 使用volatile指针防止编译器优化清零操作
- volatile char* ptr = reinterpret_cast<volatile char*>(&m_data[0]);
- std::fill(ptr, ptr + m_data.size(), 0);
- }
- }
- private:
- std::string& m_data;
- };
- // DES-CTR加密函数
- std::string desCTREncrypt(const std::string& plaintext,
- const std::string& key,
- const std::string& counter) {
- try {
- // 参数验证
- if (key.size() != CryptoPP::DES::DEFAULT_KEYLENGTH) {
- throw std::invalid_argument("Invalid key size. Expected 8 bytes");
- }
- if (counter.size() != CryptoPP::DES::BLOCKSIZE) {
- throw std::invalid_argument("Invalid counter size. Expected 8 bytes");
- }
- // 设置加密器
- CryptoPP::CTR_Mode<CryptoPP::DES>::Encryption encryptor;
- encryptor.SetKeyWithIV(
- reinterpret_cast<const CryptoPP::byte*>(key.data()), key.size(),
- reinterpret_cast<const CryptoPP::byte*>(counter.data())
- );
- // 执行加密
- std::string ciphertext;
- CryptoPP::StringSource ss(
- plaintext, true,
- new CryptoPP::StreamTransformationFilter(
- encryptor,
- new CryptoPP::StringSink(ciphertext) //无填充参数
- )
- );
- /*
- // 安全清理敏感数据(立即执行)
- volatile char* volatile_key = reinterpret_cast<volatile char*>(&key[0]);
- volatile char* volatile_iv = reinterpret_cast<volatile char*>(&iv[0]);
- std::fill(volatile_key, volatile_key + key.size(), 0);
- std::fill(volatile_iv, volatile_iv + iv.size(), 0);
- */
- return hexEncode(ciphertext);
- } catch (const CryptoPP::Exception& e) {
- std::throw_with_nested(std::runtime_error("Crypto++错误: " + std::string(e.what())));
- }catch (const std::exception& e) {
- std::cerr << "Standard Exception: " << e.what() << std::endl;
- throw;
- }
- }
- }
复制代码 解密
方法
- // DES-CTR解密函数
- std::string desCTRDecrypt(const std::string& ciphertextHex,
- const std::string& key,
- const std::string& counter) {
- try {
- // 参数验证
- if (key.size() != CryptoPP::DES::DEFAULT_KEYLENGTH) {
- throw std::invalid_argument("Invalid key size. Expected 8 bytes");
- }
- if (counter.size() != CryptoPP::DES::BLOCKSIZE) {
- throw std::invalid_argument("Invalid counter size. Expected 8 bytes");
- }
- if (!isValidHex(ciphertextHex)) {
- throw std::invalid_argument("Invalid Hexadecimal ciphertext");
- }
- // 解码十六进制
- const std::string ciphertext = hexDecode(ciphertextHex);
- // 设置解密器(CTR模式加密解密使用相同对象)
- CryptoPP::CTR_Mode<CryptoPP::DES>::Decryption decryptor;
- decryptor.SetKeyWithIV(
- reinterpret_cast<const CryptoPP::byte*>(key.data()), key.size(),
- reinterpret_cast<const CryptoPP::byte*>(counter.data())
- );
- // 执行解密
- std::string decrypted;
- CryptoPP::StringSource ss(
- ciphertext, true,
- new CryptoPP::StreamTransformationFilter(
- decryptor,
- new CryptoPP::StringSink(decrypted)
- )
- );
- return decrypted;
- }catch (const CryptoPP::Exception& e) {
- std::throw_with_nested(std::runtime_error("Crypto++错误: " + std::string(e.what())));
- }catch (const std::exception& e) {
- std::cerr << "Standard Exception: " << e.what() << std::endl;
- throw;
- }
- }
复制代码 运行
- g++ DES64-CTR-decrypt.cpp -o decrypt -lcryptopp
- g++ DES64-CTR-encrypt.cpp -o encrypt -lcryptopp
复制代码 测试
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |