DES-CBC加密和解密模式

问题

加密       

    输入:<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

测试 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值