2016-09-02 7 views
2

Я реализовал довольно простой способ для шифрования и дешифрования строки в файл, а затем обратно. Методы им с помощью внешнего вида следующим образом:XOR encryption with C++

string encrypt(string msg, string key) { 
    string tmp(key); 
    while (key.size() < msg.size()) key += tmp; 
    for (std::string::size_type i = 0; i < msg.size(); ++i) msg[i] ^= key[i]; 
    return msg; 
} 

string decrypt(string msg, string key) { 
    return encrypt(msg, key); 
} 

Однако некоторые из ключей я использую не очень полезны. Строка правильно зашифровывается и записывается в файл. Но когда я пытаюсь расшифровать все (загрузка файла в строку, дешифрование, запись вернется к другому файлу), новый файл значительно меньше и не содержит всю информацию, хранящуюся в нем.

Ключи я пытался до сих пор являются:

string crypt = "abc";       //works kinda well 
string crypt = "_H84M!-juJHFXGT01X1*G6a$gEv"; //doesnt work 
string crypt = "H84MjuJHFXGT01X1G6agEv";  //doesnt work either 

Я надеюсь, что вы можете помочь мне и дать мне советы о том, как выбрать полезный ключ.

Код для обработки файла:

ofstream temp; 
temp.open("temp", ios::in | ios::trunc); 
temp << encrypt(buffer, crypt); 
temp.close(); 


ifstream in(file); 
string content((std::istreambuf_iterator<char>(in))    (std::istreambuf_iterator<char>())); 
ofstream plain; 
plain.open(newfile, ios::in | ios::trunc); 
plain << decrypt(content, crypt); 
plain.close(); 
+3

Я ожидаю, что вы получите двоичный код 0 в вашей зашифрованной строке, а затем используйте строковую функцию 'C', которая ожидает, что строка завершена двоичным 0 char. Это приведет к усечению ваших зашифрованных данных. –

+1

Показать код для чтения и записи в файл. – Nelfeal

+8

Просто используйте 'msg [i]^= key [i% key.size()];' вместо бессмыслицы с увеличением ключа. – Slava

ответ

1

Хорошо, все ваши ответы и комментарии указали мне в правильном направлении, но не работали непосредственно в моей программе.

Во-первых, я изменил алгоритм шифрования так, как предложил Слава. Во-вторых, я переключил обработку файлов. Новый способ получает всю длину зашифрованного файла и заставляет каждого символа через массив char вводить новую строку. Я знаю, что это не очень, но я могу сохранить весь код в строковом типе.

Так что я придумал следующее:

ifstream in(file, ios::binary); 
in.seekg(0, ios::end);    // go to the end 
int length = in.tellg();   // report location (this is the length) 
in.seekg(0, ios::beg);    // go back to the beginning 
char* content = new char[length]; // allocate memory for a buffer of appropriate dimension 
in.read(content, length);   // read the whole file into the buffer 
string content2 = ""; 
for (int i = 0; i < length; i++) con31 += con3[i]; //append to string character by character 
ofstream plain; 
plain.open(newfile, ios::in | ios::trunc); 
plain << decrypt(content2, crypt); 
plain.close(); 

Это работает очень хорошо для меня. Надеюсь, у меня не было серьезных ошибок.

2

Как у вас есть двоичные данные в зашифрованной строки, вы должны использовать неформатированный write метод вместо operator<<:

ofstream os(...); 
std::string encrypted = ...; 
os.write(encrypted.data(), encrypted.size()); 

Примечание вы можете захотеть написать размер данных до фактических данных, если вам требуется более одной зашифрованной строки в файле. Затем вы читаете размер данных и данных с istream::read():

void write(std::ostream &out, const std::string &encrypted) 
{ 
    size_t length = encrypted.size(); 
    of.write(&length, sizeof(length)); 
    of.write(encryped.data(), length); 
} 

std::string read(std::istream &in) 
{ 
    size_t length = 0; 
    in.read(&length, sizeof(length)); 
    std::string str(length); 
    in.read(&str[0], length); 
    return str; 
} 

Примечание 2: это может быть хорошей идеей, чтобы хранить зашифрованные данные в std::vector<char> вместо std::string, что позволит избежать многих проблем - вы не сможете использовать многие функции, которые неявно предполагают, что строка заканчивается нулем.

+0

........... Почему? –

+0

@ArtjomB. Потому что оператор '<<' останавливается на '\ 0'. Попробуйте 'std :: cout <<" a \ 0b ";'. – Nelfeal

+0

@Nelxiost Это может быть, но это должно быть включено в ответ. В противном случае это не очень полезно. –

2

Я только что написал полный, минимальный рабочий пример.

#include <fstream> 
#include <iostream> 
#include <string> 

static std::string str_xor(const std::string &data, const std::string &key) { 
    std::string result(data.size(), '\0'); 

    for (std::size_t i = 0, i < data.size(); i++) { 
    result[i] = data[i]^key[i % key.size()]; 
    } 
    return result; 
} 

int main(int argc, char **argv) { 
    if (argc != 3) { 
    std::cerr << "usage: xor <datafile> <keyfile>\n"; 
    return 1; 
    } 

    std::ifstream data_in(argv[1]); 
    std::string data(
    (std::istreambuf_iterator<char>(data_in)), 
    (std::istreambuf_iterator<char>())); 
    data_in.close(); 

    std::ifstream key_in(argv[2]); 
    std::string key(
    (std::istreambuf_iterator<char>(key_in)), 
    (std::istreambuf_iterator<char>())); 
    key_in.close(); 

    std::string result = str_xor(data, key); 

    std::ofstream data_out(argv[1]); 
    data_out << result; 
    data_out.close(); 

    return 0; 
} 

По-прежнему отсутствует проверка ошибок для файлов, на случай, если они не найдены. Но если вы передаете ему имена двух существующих файлов, он работает как шарм, зашифровывая первый файл, используя второй файл в качестве ключа.

Предостережение: не используйте эту программу на практике, за отличные причины, указанные в https://codereview.stackexchange.com/a/140366.

+0

Возможно, используйте 'std :: string result (a); ... result [i]^= b [i% b.size()]; ' – chux

+0

Почему? Копирование 'a' означает больший доступ к памяти. Конечно, он сохраняет несколько байтов в исходном коде, но во время выполнения я думаю, что он медленнее. –