linux

C++如何在Linux实现文件加密

小樊
36
2025-07-22 05:13:02
栏目: 编程语言

在Linux下使用C++实现文件加密,可以采用多种方法。以下介绍两种常用的方法:

  1. 使用OpenSSL库进行加密
  2. 使用AES-NI指令集进行硬件加速加密

方法一:使用OpenSSL库进行加密

OpenSSL是一个强大的加密库,支持多种加密算法和协议。通过C++调用OpenSSL库,可以方便地实现文件的加密和解密。

步骤:

  1. 安装OpenSSL开发库

    在大多数Linux发行版中,可以使用包管理器安装OpenSSL的开发库。例如,在Ubuntu上:

    sudo apt-get update
    sudo apt-get install libssl-dev
    
  2. 编写C++代码

    下面是一个使用OpenSSL的AES-256-CBC算法对文件进行加密和解密的示例代码:

    #include <iostream>
    #include <fstream>
    #include <openssl/aes.h>
    #include <openssl/rand.h>
    #include <cstring>
    
    // 加密函数
    bool encryptFile(const std::string& inputFile, const std::string& outputFile, const std::string& password) {
        // 读取输入文件
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "无法打开输入文件。" << std::endl;
            return false;
        }
    
        // 写入输出文件
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "无法打开输出文件。" << std::endl;
            return false;
        }
    
        // 生成随机的盐
        unsigned char salt[8];
        if (!RAND_bytes(salt, sizeof(salt))) {
            std::cerr << "生成盐失败。" << std::endl;
            return false;
        }
        outFile.write(reinterpret_cast<const char*>(salt), sizeof(salt));
    
        // 使用PBKDF2从密码派生密钥
        AES_KEY enc_key;
        unsigned char key[32]; // AES-256
        if (!PKCS5_PBKDF2_HMAC(password.c_str(), password.size(),
                               salt, sizeof(salt),
                               10000, AES_KEYLEN_256, EVP_sha256(), sizeof(key), key)) {
            std::cerr << "密钥派生失败。" << std::endl;
            return false;
        }
    
        // 初始化加密上下文
        if (!AES_set_encrypt_key(key, 256, &enc_key)) {
            std::cerr << "设置加密密钥失败。" << std::endl;
            return false;
        }
    
        // 写入IV(初始化向量)
        unsigned char iv[AES_BLOCK_SIZE];
        if (!RAND_bytes(iv, sizeof(iv))) {
            std::cerr << "生成IV失败。" << std::endl;
            return false;
        }
        outFile.write(reinterpret_cast<const char*>(iv), sizeof(iv));
    
        // 加密数据
        char inbuf[AES_BLOCK_SIZE];
        char outbuf[AES_BLOCK_SIZE + AES_BLOCK_SIZE];
        while (inFile.good()) {
            inFile.read(inbuf, sizeof(inbuf));
            size_t bytesRead = inFile.gcount();
            if (bytesRead > 0) {
                AES_cbc_encrypt(inbuf, outbuf, bytesRead, &enc_key, iv, AES_ENCRYPT);
                outFile.write(outbuf, sizeof(outbuf));
            }
        }
    
        inFile.close();
        outFile.close();
        return true;
    }
    
    // 解密函数
    bool decryptFile(const std::string& inputFile, const std::string& outputFile, const std::string& password) {
        // 打开输入文件
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "无法打开输入文件。" << std::endl;
            return false;
        }
    
        // 打开输出文件
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "无法打开输出文件。" << std::endl;
            return false;
        }
    
        // 读取盐
        unsigned char salt[8];
        inFile.read(reinterpret_cast<char*>(salt), sizeof(salt));
        if (!inFile) {
            std::cerr << "读取盐失败。" << std::endl;
            return false;
        }
    
        // 读取IV
        unsigned char iv[AES_BLOCK_SIZE];
        inFile.read(reinterpret_cast<char*>(iv), sizeof(iv));
        if (!inFile) {
            std::cerr << "读取IV失败。" << std::endl;
            return false;
        }
    
        // 使用PBKDF2从密码派生密钥
        AES_KEY dec_key;
        unsigned char key[32]; // AES-256
        if (!PKCS5_PBKDF2_HMAC(password.c_str(), password.size(),
                               salt, sizeof(salt),
                               10000, AES_KEYLEN_256, EVP_sha256(), sizeof(key), key)) {
            std::cerr << "密钥派生失败。" << std::endl;
            return false;
        }
    
        // 初始化解密上下文
        if (!AES_set_decrypt_key(key, 256, &dec_key)) {
            std::cerr << "设置解密密钥失败。" << std::endl;
            return false;
        }
    
        // 解密数据
        char inbuf[AES_BLOCK_SIZE + AES_BLOCK_SIZE];
        char outbuf[AES_BLOCK_SIZE];
        while (inFile.good()) {
            inFile.read(inbuf, sizeof(inbuf));
            size_t bytesRead = inFile.gcount();
            if (bytesRead > 0) {
                AES_cbc_encrypt(inbuf, outbuf, bytesRead, &dec_key, iv, AES_DECRYPT);
                outFile.write(outbuf, bytesRead);
            }
        }
    
        inFile.close();
        outFile.close();
        return true;
    }
    
    int main(int argc, char* argv[]) {
        if (argc != 4) {
            std::cerr << "用法: " << argv[0] << " encrypt|decrypt 输入文件 输出文件 密码" << std::endl;
            return 1;
        }
    
        std::string mode = argv[1];
        std::string inputFile = argv[2];
        std::string outputFile = argv[3];
        std::string password = argv[4];
    
        if (mode == "encrypt") {
            if (encryptFile(inputFile, outputFile, password)) {
                std::cout << "加密成功。" << std::endl;
            } else {
                std::cerr << "加密失败。" << std::endl;
            }
        }
        else if (mode == "decrypt") {
            if (decryptFile(inputFile, outputFile, password)) {
                std::cout << "解密成功。" << std::endl;
            } else {
                std::cerr << "解密失败。" << std::endl;
            }
        }
        else {
            std::cerr << "未知模式。使用encrypt或decrypt。" << std::endl;
            return 1;
        }
    
        return 0;
    }
    
  3. 编译代码

    使用g++编译时,需要链接OpenSSL的加密库:

    g++ -o file_encrypt file_encrypt.cpp -lcrypto
    
  4. 使用示例

    # 加密文件
    ./file_encrypt encrypt plaintext.txt encrypted.bin mypassword
    
    # 解密文件
    ./file_encrypt decrypt encrypted.bin decrypted.txt mypassword
    

说明:

方法二:使用AES-NI指令集进行硬件加速加密

如果您的CPU支持AES-NI指令集,可以利用硬件加速来提高加密和解密的性能。下面介绍如何使用C++和Intel的Intel Intrinsics来实现AES加密。

步骤:

  1. 安装必要的开发工具

    确保已安装GCC和相关的开发工具。大多数Linux发行版默认已安装。

  2. 编写C++代码

    下面是一个使用AES-NI指令集进行AES-256-CBC加密和解密的示例代码:

    #include <iostream>
    #include <fstream>
    #include <cstring>
    #include <emmintrin.h> // 包含AES-NI指令集头文件
    
    // 加密函数
    bool aesni_encrypt_file(const std::string& inputFile, const std::string& outputFile, const unsigned char* key, const unsigned char* iv) {
        // 打开输入文件
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "无法打开输入文件。" << std::endl;
            return false;
        }
    
        // 打开输出文件
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "无法打开输出文件。" << std::endl;
            return false;
        }
    
        // 写入IV
        outFile.write(reinterpret_cast<const char*>(iv), AES_BLOCK_SIZE);
    
        // 加密缓冲区
        const int bufferSize = 4096; // 4KB缓冲区
        unsigned char inbuf[bufferSize];
        unsigned char outbuf[bufferSize + AES_BLOCK_SIZE];
    
        while (inFile.good()) {
            inFile.read(reinterpret_cast<char*>(inbuf), sizeof(inbuf));
            size_t bytesRead = inFile.gcount();
    
            if (bytesRead > 0) {
                // AES-NI加密
                for (size_t i = 0; i < bytesRead; i += AES_BLOCK_SIZE) {
                    __m128i aes_key = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key));
                    __m128i aes_iv = _mm_loadu_si128(reinterpret_cast<const __m128i*>(iv));
    
                    __m128i in = _mm_loadu_si128(reinterpret_cast<const __m128i*>(inbuf + i));
                    __m128i out = _mm_aesenc_si128(in, aes_key);
                    out = _mm_aesenc_si128(out, aes_key);
                    out = _mm_aesenc_si128(out, aes_key);
                    out = _mm_aesenclast_si128(out, aes_key);
    
                    _mm_storeu_si128(reinterpret_cast<__m128i*>(outbuf + i), out);
                }
    
                outFile.write(reinterpret_cast<const char*>(outbuf), sizeof(outbuf));
            }
        }
    
        inFile.close();
        outFile.close();
        return true;
    }
    
    // 解密函数
    bool aesni_decrypt_file(const std::string& inputFile, const std::string& outputFile, const unsigned char* key, const unsigned char* iv) {
        // 打开输入文件
        std::ifstream inFile(inputFile, std::ios::binary);
        if (!inFile) {
            std::cerr << "无法打开输入文件。" << std::endl;
            return false;
        }
    
        // 打开输出文件
        std::ofstream outFile(outputFile, std::ios::binary);
        if (!outFile) {
            std::cerr << "无法打开输出文件。" << std::endl;
            return false;
        }
    
        // 读取IV
        unsigned char read_iv[AES_BLOCK_SIZE];
        inFile.read(reinterpret_cast<char*>(read_iv), sizeof(read_iv));
        if (!inFile) {
            std::cerr << "读取IV失败。" << std::endl;
            return false;
        }
    
        // 检查IV是否匹配
        if (memcmp(read_iv, iv, AES_BLOCK_SIZE) != 0) {
            std::cerr << "IV不匹配。" << std::endl;
            return false;
        }
    
        // 解密缓冲区
        const int bufferSize = 4096; // 4KB缓冲区
        unsigned char inbuf[bufferSize + AES_BLOCK_SIZE];
        unsigned char outbuf[bufferSize];
    
        while (inFile.good()) {
            inFile.read(reinterpret_cast<char*>(inbuf), sizeof(inbuf));
            size_t bytesRead = inFile.gcount();
    
            if (bytesRead > 0) {
                // AES-NI解密
                for (size_t i = 0; i < bytesRead; i += AES_BLOCK_SIZE) {
                    __m128i aes_key = _mm_loadu_si128(reinterpret_cast<const __m128i*>(key));
                    __m128i in = _mm_loadu_si128(reinterpret_cast<const __m128i*>(inbuf + i));
                    __m128i out = _mm_aesdec_si128(in, aes_key);
                    out = _mm_aesdec_si128(out, aes_key);
                    out = _mm_aesdec_si128(out, aes_key);
                    out = _mm_aesdeclast_si128(out, aes_key);
    
                    _mm_storeu_si128(reinterpret_cast<__m128i*>(outbuf + i), out);
                }
    
                outFile.write(reinterpret_cast<const char*>(outbuf), sizeof(outbuf));
            }
        }
    
        inFile.close();
        outFile.close();
        return true;
    }
    
    int main(int argc, char* argv[]) {
        if (argc != 5) {
            std::cerr << "用法: " << argv[0] << " encrypt|decrypt 输入文件 输出文件 密钥 密码" << std::endl;
            return 1;
        }
    
        std::string mode = argv[1];
        std::string inputFile = argv[2];
        std::string outputFile = argv[3];
        std::string password = argv[4];
    
        // 密钥派生(简单示例,使用PBKDF2需要额外实现)
        // 这里假设已经有一个256位的密钥
        unsigned char key[32] = { /* 256位密钥 */ };
        unsigned char iv[AES_BLOCK_SIZE] = { /* 128位IV */ };
    
        if (mode == "encrypt") {
            if (aesni_encrypt_file(inputFile, outputFile, key, iv)) {
                std::cout << "加密成功。" << std::endl;
            } else {
                std::cerr << "加密失败。" << std::endl;
            }
        }
        else if (mode == "decrypt") {
            if (aesni_decrypt_file(inputFile, outputFile, key, iv)) {
                std::cout << "解密成功。" << std::endl;
            } else {
                std::cerr << "解密失败。" << std::endl;
            }
        }
        else {
            std::cerr << "未知模式。使用encrypt或decrypt。" << std::endl;
            return 1;
        }
    
        return 0;
    }
    

    注意

    • 密钥管理:示例中硬编码了密钥和IV,实际应用中应安全地生成和存储密钥。可以使用OpenSSL或其他库生成密钥,并通过安全的方式传递给程序。
    • IV管理:每次加密应使用不同的IV,确保相同的明文加密后结果不同。IV不需要保密,但必须唯一。
    • 填充方式:AES-CBC模式要求数据长度为块大小的倍数,因此需要对数据进行填充(如PKCS#7)。上述示例代码未处理填充,实际应用中需要添加。
  3. 编译代码

    使用g++编译时,可以启用AES-NI指令集优化:

    g++ -o aesni_encrypt aesni_encrypt.cpp -mavx2
    

    -mavx2选项启用了AVX2指令集,包括AES-NI。如果您的CPU支持AES-NI但不支持AVX2,可以省略该选项或使用其他相关选项。

  4. 使用示例

    # 加密文件
    ./aesni_encrypt encrypt plaintext.txt encrypted.bin
    
    # 解密文件
    ./aesni_encrypt decrypt encrypted.bin decrypted.txt
    

说明:

总结

以上介绍了两种在Linux下使用C++实现文件加密的方法:

  1. OpenSSL库:适用于需要跨平台支持、灵活选择加密算法和模式的场景。通过调用OpenSSL库,可以方便地实现复杂的加密需求。
  2. AES-NI指令集:适用于对性能有较高要求,并且运行在支持AES-NI硬件的服务器上的应用。利用硬件加速,可以大幅提升加密和解密的效率。

根据具体需求选择合适的方法,并注意密钥管理和数据安全。

0
看了该问题的人还看了