问题
加密
输入:<plaintext> <key> <iv> 输出:<ciphertext> 例如 输入:<i love you, sunsiqi> <0123456789ABCDEF> <FEDCBA0123456789> 输出:<4e152ec964f73950dfc7a3d833bdaeffd6f0b8a727c13c29>
解
输入:<ciphertext> <key> <iv> 输出:<plaintext> 例如 输入:<4e152ec964f73950dfc7a3d833bdaeffd6f0b8a727c13c29> <0123456789ABCDEF> <FEDCBA0123456789> 输出:<i love you, sunsiqi>
要求
- 中英文混合内容处理
正确处理任意长度的明文输入
自动进行PKCS#7填充
验证所有输入参数的合法性
提供清晰的错误信息
保证加密过程的安全性
正确处理边界情况(如空输入、最大长度输入等)
跨平台编码支持
WIN平台支持
#include <> ... ... #ifdef _WIN32 #include <windows.h> #endif
在主函数中设置控制台编码格式为UTF-8
int main(){ // 设置控制台编码为UTF-8 #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif ... ... }
代码
头文件
#include <iostream> #include <string> #include <cctype> // <cctype>包含字符处理库,用于字符类型判断等操作,在 isValidHex 函数中使用 std::isxdigit 来判断字符是否为十六进制字符 #include <cryptopp/des.h> #include <cryptopp/modes.h> #include <cryptopp/filters.h>// <cryptopp/filters.h>包含 Crypto++ 库中数据过滤器的头文件,用于处理加密解密过程中的数据转换和流操作 #include <cryptopp/hex.h> #include <cryptopp/pwdbased.h> #include <stdexcept>
加密
// 命名空间,用于组织相关功能 namespace SymCryptoUtilities { /** * @brief 验证十六进制字符串的有效性 * * 该函数遍历输入的字符串,检查每个字符是否为有效的十六进制字符(0-9, A-F, a-f)。 * * @param hexStr 待验证的十六进制字符串 * @return 如果字符串中的所有字符都是有效的十六进制字符,则返回 true;否则返回 false */ bool isValidHex(const std::string& hexStr) { for (char c : hexStr) { if (!std::isxdigit(c)) return false; } return true; } /** * @brief 将十六进制字符串解码为字节数组 * * 该函数首先检查输入的十六进制字符串长度是否为偶数,因为每个字节由两个十六进制字符表示。 * 然后使用 Crypto++ 库的 HexDecoder 进行解码操作。 * * @param hexStr 待解码的十六进制字符串 * @return 解码后的字节数组,以 std::string 形式表示 * @throws std::invalid_argument 如果输入的十六进制字符串长度不是偶数 */ 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; } /** * @brief 将字节数组编码为十六进制字符串 * * 该函数使用 Crypto++ 库的 HexEncoder 对输入的字节数组进行编码操作,不添加换行符。 * * @param data 待编码的字节数组,以 std::string 形式表示 * @return 编码后的十六进制字符串 */ 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; } /** * @brief 执行 DES-CBC 加密操作 * * 该函数使用 DES(Data Encryption Standard)算法的 CBC(Cipher Block Chaining)模式对明文进行加密。 * 明文长度标准为 64bit,少于则进行填充,多于则进行截断。 * 分组长度为 64bit,密文长度为 64bit,密钥长度为 64bit(包含 8bit 奇偶校验,不参与加解密过程)。 * * @param plaintext 待加密的明文,以 std::string 形式表示 * @param key 加密使用的密钥,以字节数组形式表示,长度必须为 8 字节 * @param iv 初始化向量(IV),以字节数组形式表示,长度必须为 8 字节 * @return 加密后的密文,以十六进制字符串形式表示 * @throws std::invalid_argument 如果密钥或 IV 的长度不符合要求 * @throws std::runtime_error 如果 Crypto++ 库在加密过程中抛出异常 */ std::string desCBCEncrypt(const std::string& plaintext, const std::string& key, const std::string& iv) { try { // 参数验证,检查参数的合法性 if (key.size() != CryptoPP::DES::DEFAULT_KEYLENGTH) { throw std::invalid_argument("Invalid key size. Expected 8 bytes"); } if (iv.size() != CryptoPP::DES::BLOCKSIZE) { throw std::invalid_argument("Invalid IV size. Expected 8 bytes"); } // 设置加密参数,创建CBC模式加密对象encryptor // CryptoPP::CBC_Mode<>时一个模板类,需要传入具体的算法类型,如<CryptoPP::DES> CryptoPP::CBC_Mode<CryptoPP::DES>::Encryption encryptor; /* CryptoPP::CBC_Mode<CryptoPP::DES>::Encryption::SetKeyWithIV用于设置加密所需的密钥和初始化向量 */ encryptor.SetKeyWithIV( // CryptoPP::byte是库中定义的字节类型,通常等同于unsigned char // 将密钥字符串转换为 Crypto++ 的字节指针 reinterpret_cast<const CryptoPP::byte*>(key.data()), key.size(), reinterpret_cast<const CryptoPP::byte*>(iv.data()), iv.size() ); // 用于存储密文的字符串 std::string ciphertext; // 执行加密操作 // CryptoPP::StringSource是库中的一个数据源类,用于从std::string对象中读取数据 /*构造函数参数分别是: std:string类型的数据源; bool value: true:自动删除过滤器链中的对象 false:不自动删除过滤器链中的对象,需要手动调用delete释放CryptoPP::StreamTransformationFilter 对象的内存 指向过滤器对象的指针 */ CryptoPP::StringSource ss( plaintext, true, /* 使用 StreamTransformationFilter 进行流转换过滤,将明文加密为密文 CryptoPP::StreamTransformationFilter是一个过滤器类,用于对数据流进行加密和解密操作。 构造函数参数: 指向加密或解密对象的指针 指向数据接收器对象的指针 可选参数:填充方案 返回值: 返回指向CryptoPP::StreamTransformationFilter类对象的指针 类的对象可以作为指针类型传递给其他对象 */ new CryptoPP::StreamTransformationFilter( encryptor, // CryptoPP::StringSink是一个数据接收器类,用于将处理后的数据存储到std:string对象中 // 将加密后的密文存储到 ciphertext 字符串中 new CryptoPP::StringSink(ciphertext), // 使用 PKCS#7 填充方案,确保明文长度是块大小的整数倍 CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING ) ); // 将加密后的密文编码为十六进制字符串并返回 return hexEncode(ciphertext); } catch (const CryptoPP::Exception& e) { // 处理crypto++库相关异常 std::throw_with_nested(std::runtime_error("Crypto++ error: " + std::string(e.what()))); } catch (const std::exception& e) { std::cerr << "Standard Exception: " << e.what() << std::endl; throw; } } }
解密
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; } // DES-CBC解密核心实现 std::string desCBCDecrypt(const std::string& ciphertextHex, const std::string& key, const std::string& iv) { try { // 参数验证 if (key.size() != CryptoPP::DES::DEFAULT_KEYLENGTH) { throw std::invalid_argument("Invalid key size. Expected 8 bytes"); } if (iv.size() != CryptoPP::DES::BLOCKSIZE) { throw std::invalid_argument("Invalid IV size. Expected 8 bytes"); } if (!isValidHex(ciphertextHex)) { throw std::invalid_argument("Invalid hexadecimal ciphertext"); } // 解码十六进制密文 const std::string ciphertext = hexDecode(ciphertextHex); // 检查密文长度有效性 if (ciphertext.empty() || (ciphertext.size() % CryptoPP::DES::BLOCKSIZE != 0)) { throw std::invalid_argument("Invalid ciphertext length"); } // 设置解密参数 CryptoPP::CBC_Mode<CryptoPP::DES>::Decryption decryptor; decryptor.SetKeyWithIV( reinterpret_cast<const CryptoPP::byte*>(key.data()), key.size(), reinterpret_cast<const CryptoPP::byte*>(iv.data()), iv.size() ); // 解密流程 std::string decrypted; CryptoPP::StringSource ss( ciphertext, true, new CryptoPP::StreamTransformationFilter( decryptor, new CryptoPP::StringSink(decrypted), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING ) ); return decrypted; } catch (const CryptoPP::Exception& e) { std::throw_with_nested(std::runtime_error("Crypto++ error: " + std::string(e.what()))); } catch (const std::exception&) { throw; } } }
主函数
int main(int argc, char* argv[]) { if (argc != 4) { std::cerr << "Usage: " << argv[0] << " <ciphertext_hex> <hex_key> <hex_iv>\n" << "Example: " << argv[0] << " A1B2C3D4E5F6 0123456789ABCDEF FEDCBA9876543210\n" << "Note:\n" << " - Key and IV must be 16-character hexadecimal strings (8 bytes)\n" << " - Ciphertext must be hexadecimal format" << std::endl; return 1; } const std::string ciphertextHex = argv[1]; const std::string keyHex = argv[2]; const std::string ivHex = argv[3]; try { // 输入验证 if (keyHex.length() != 16 || !SymCryptoUtilities::isValidHex(keyHex)) { throw std::invalid_argument("Key must be 16-character hex string (8 bytes)"); } if (ivHex.length() != 16 || !SymCryptoUtilities::isValidHex(ivHex)) { throw std::invalid_argument("IV must be 16-character hex string (8 bytes)"); } if (ciphertextHex.empty()) { throw std::invalid_argument("Ciphertext cannot be empty"); } // 十六进制解码 const std::string key = SymCryptoUtilities::hexDecode(keyHex); const std::string iv = SymCryptoUtilities::hexDecode(ivHex); // 执行解密 const std::string plaintext = SymCryptoUtilities::desCBCDecrypt(ciphertextHex, key, iv); std::cout << "Decrypted plaintext: " << plaintext << 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; }
WIN平台主函数
int main(int argc, char* argv[]) { // 设置控制台编码为UTF-8 #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif if (argc != 4) { ... ... ... }
运行
g++ DES64-CBC-encrypt.cpp -o encrypt -lcryptopp g++ DES64-CBC-decrypt.cpp -o decrypt -lcryptopp