文件加解密操作

1. 前言

老板之前布置的一个任务中有一个对文件进行加解密的需求,拖了好久都没做, 今天正好想起来,做了一下, 虽然遇到了一些问题, 但是做完之后的感觉是棒棒的呢。

2. 基本思路

  1. 由于我们需要加密的目标文件是ascii文件,我们希望可以将他通过一个密钥进行加密,然后输出到一个二进制文件中。
  2. 加密算法我们这里使用的非常简单, ie, 对文件中的每个字节数据与我们的密钥进行异或操作, 得到加密后的数据, 再执行一次异或操作即可还原原始数据了
  3. 一些经典的加密算法:http://www.iplaysoft.com/encrypt-arithmetic.html,为了实现的方便起见(只是偷懒),我们采用了最简单的异或方法进行加密。
  4. 我们这里的这个异或加密算法, 是按照行来读取文件数据,以行为单位进行加解密操作, 由于需要转化为二进制文件,为了精准控制, 我们在存储每行数据之前, 先存入 4 字节大小的行内数据长度

3. 遇到的一些问题及参考资料

  1. C++ 读写二进制文件
    http://blog.csdn.net/zhyh1435589631/article/details/52181435
    http://blog.csdn.net/lightlater/article/details/6364931

  2. C++ ifstream 操作 http://en.cppreference.com/w/cpp/io/basic_ifstreami

  3. c++中char[]与string之间的相互转换问题, 可以使用 string(char [], num)的形式表示 从char [] 中截取 num 个字符数据转化成 string

4. 实现效果

这里写图片描述
其中, asInt.ini, asString.ini 都是原始数据文件
*.bin 文件是他们加密得到的数据文件
通过gtest 测试工具, 我们可以发现对加密完的数据进行解密可以重新得到原始数据的, 这表明我们的加密算法是成功的~~~

5. 代码实现

utils.h

#pragma once
#include <fstream>
#include <string>

/**
*   将ascii编码文件内容,根据key进行加密, 并输出到二进制文件中(以行为单位进行加密)
*   @param filename 输入文件名称
*   @param key 加密关键字
*   @param outfile 输出二进制文件名称
*   @return bool if ok
*/
bool encrypt_with_passwd_file(const std::string & filename, const std::string & key, const std::string & outfile);

/**
*   对输入的二进制文件中的数据利用 key 解密, 并返回
*   @param filename 输入文件名称 (二进制)
*   @param key 加密关键字
*   @return 解密后的字符串数据
*/
std::string decrypt_with_passwd_file(const std::string & filename, const std::string & key);

/**
*   对输入字符串按照 key 加密
*   @param input 输入字符串数据
*   @param key 加密关键字
*   @return 加密后的字符串数据
*/
std::string encrypt_with_passwd(const std::string & input, const std::string & key);

/**
*   对输入字符串按照 key 解密
*   @param input 输入字符串数据
*   @param key 加密关键字
*   @return 解密后的字符串数据
*/
std::string decrypt_with_passwd(const std::string & input, const std::string & key);

/**
*   加解密核心业务逻辑
*   @param input 输入字符串数据
*   @param key 加密关键字
*   @return 加解密后的字符串数据
*/
std::string crypt_with_passwd_core(const std::string & input, const std::string & key);

utils.cpp

#include "utils.h"
#include <sstream>

using namespace std;

const int fileSizeInByte = 4;
const int MAXBYTE = 1024;

bool encrypt_with_passwd_file(const std::string & filename, const std::string & key, const std::string & outfile){
    std::ifstream ifs(filename);
    std::ofstream ofs(outfile, std::ios::binary);
    if (!ifs || !ofs)
        return false;

    std::string line;
    std::string res;
    while (getline(ifs, line)){
        res = encrypt_with_passwd(line, key);
        ofs.write(to_string(res.size()).c_str(), fileSizeInByte);
        ofs.write(res.c_str(), res.size());
    }   
    ofs.flush();
    return true;
}

std::string decrypt_with_passwd_file(const std::string & filename, const std::string & key){
    std::ifstream ifs(filename, std::ios::binary);
    if (!ifs)
        return "";

    // get file size
    ifs.seekg(0, ifstream::end);
    int MyfileSize = ifs.tellg();
    ifs.seekg(0);

    std::string content;    
    int already_read = 0;   
    while (already_read < MyfileSize){
        // 读取本次需要读入的数据的字节数目
        char buf[fileSizeInByte] = { 0 };       
        ifs.read(buf, fileSizeInByte);
        already_read += ifs.gcount();

        // 读取字节数据
        char buffer[MAXBYTE] = { 0 };
        int num = stoi(buf);
        ifs.read(buffer, num);
        int readNum = ifs.gcount();
        already_read += readNum;
        content += decrypt_with_passwd(std::string(buffer, readNum), key) + "\n";
    }
    return content;
}

std::string encrypt_with_passwd(const std::string & input, const std::string & key){
    return crypt_with_passwd_core(input, key);
}

std::string decrypt_with_passwd(const std::string & input, const std::string & key){
    return crypt_with_passwd_core(input, key);
}

std::string crypt_with_passwd_core(const std::string & input, const std::string & key){
    if (key == "")
        return input;

    int iter = 0;
    std::string res;
    for (int i = 0; i < input.size(); i++){
        res += (input[i] ^ key[iter++]);
        if (iter == key.size())
            iter = 0;
    }
    return res;
}

test.cpp

#include "gtest/gtest.h"
#include "utils.h"
#include <string>
#include <fstream>

using namespace std;

TEST(ENCRYPTION, encryptString){
    std::string filename = "asString.ini";
    std::string outfile = "asString.bin";
    std::string key = "";
    bool ret = encrypt_with_passwd_file(filename, key, outfile);
    std::string res = decrypt_with_passwd_file(outfile, key);
    std::string standard = "hello world\nhi\n你好\nsafd\na 12\ndsaf\n";
    ASSERT_EQ(res, standard);
}

TEST(ENCRYPTION, encryptInt){
    std::string filename = "asInt.ini";
    std::string outfile = "asInt.bin";
    std::string key = "";
    bool ret = encrypt_with_passwd_file(filename, key, outfile);
    std::string res = decrypt_with_passwd_file(outfile, key);
    std::string standard = "1.00 2.00 3.00\n0.0 1.2 3.4\n4.6  6.5  3.4\n";
    ASSERT_EQ(res, standard);
}

TEST(ENCRYPTION, encryptIntKey){
    std::string filename = "asInt.ini";
    std::string outfile = "asInt.bin1";
    std::string key = "131xxxx8380";
    bool ret = encrypt_with_passwd_file(filename, key, outfile);
    std::string res = decrypt_with_passwd_file(outfile, key);
    std::string standard = "1.00 2.00 3.00\n0.0 1.2 3.4\n4.6  6.5  3.4\n";
    ASSERT_EQ(res, standard);
}

TEST(ENCRYPTION, encryptStringKey){
    std::string filename = "asString.ini";
    std::string outfile = "asString.bin";
    std::string key = "131xxxx8380";
    bool ret = encrypt_with_passwd_file(filename, key, outfile);
    std::string res = decrypt_with_passwd_file(outfile, key);
    std::string standard = "hello world\nhi\n你好\nsafd\na 12\ndsaf\n";
    ASSERT_EQ(res, standard);
}

TEST(STRINGCRYPT, stringcrypt){
    std::string input = "hello world";
    std::string key = "131xxxx8380";
    std::string encrypted = encrypt_with_passwd(input, key);
    std::string decrypted = decrypt_with_passwd(encrypted, key);
    ASSERT_EQ(decrypted, input);
}

int main(int argc, char ** argv){
    ::testing::InitGoogleTest(&argc, argv);
    RUN_ALL_TESTS();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值