Шифрование XOR работает * большую часть времени - PullRequest
2 голосов
/ 07 июня 2011

Мне было поручено защищать паролем приложение Java с минимальной заботой о реальной безопасности.Поэтому представляется целесообразным сохранить пары имя пользователя / пароль в текстовом файле, а затем зашифровать их.Для шифрования казалось целесообразным использовать шифры XOR, потому что они просты и быстры (помните - это просто должно обескураживать случайного пользователя, а не быть пуленепробиваемым).

Я написал все соответствующие Java, ипотом понял, что мне нужен способ шифрования файла конфигурации.Я написал дополнительный метод, но было неудобно использовать более одного или двух раз (и казалось, что он работал только для некоторых входных данных), поэтому я решил, что лучше написать что-то на Python, чтобы поиграть на REPL.

Вот что я закончил:

from itertools import izip, cycle

KEY = "stackoverflow"

def encrypt(text):
    return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(text,cycle(KEY)))

def decrypt(text):
    return encrypt(text)

def export(users, file):
    with open(file, "w") as f:
        for user, password in users.items():
            f.write(encrypt('"%s" "%s"'%(user, password)) + "\n")

def import_data(file):
    with open(file) as f:
        return [decrypt(i) for i in f.readlines()]

На поверхности это работает:

>>> x = encrypt("Hello world!")
>>> x
';\x11\r\x0f\x04O\x01\n\x00\n\x08N'
>>> decrypt(x)
'Hello world!'

Но потом все начинает разваливаться:

>>> export({"foo" : "bar", "baz" : "quux", "spam" : "eggs"}, "users.dat")
>>> import_data("users.dat")
['"foo" "bar"e', '"baz" "quux"}', '"spam" "eggs"y']

А вот как Vim читает это -

Vim rendition

А затем:

>>> export({"what" : "not", "this" : "that", "admin_istrator" : "quux"}, "users2.dat")
>>> import_data("users2.dat")
['"thi', "k97$ma{~'l", '"what" "not"}', '"admin_istrator" "quux', '7~']

Vim:

Vim rendition of the second set

Мне пришло в голову, что у меня могут быть проблемы с зашифрованной формой символа, являющейся символом новой строки, но, насколько я понимаю, это не объясняет дурацкое поведение в первом примере или all о дурацком поведении во втором.

Что касается новых строк, мой План Б состоит в том, чтобы зашифровать весь файл - новые строки и все - и затем взломать его обратно, расшифровать, разделить на "\ n ", и продолжите мой анализ на основе строки.

Заранее спасибо.


Обновление: вот мой имПлементация Плана B (описана два параграфа назад).

def import2(file):
    with open(file) as f:
        return decrypt(f.read())

, а затем:

>>> export({"foo" : "bar", "this" : "that", "admin_istrator" : "letmein"}, "users2.dat")
>>> import2("users2.dat")
'"this" "that"y%smg&91uux!}"admin_istrator" "letmein"y'

Обновление два: Двоичный код.

[Код - этоТо же, что и выше, за исключением того, что все open являются open(file, "rb") или open(file, "wb").]

>>> export({"foo" : "bar", "this" : "that", "admin_istrator" : "letmein"}, "users2.dat")
>>> import2("users2.dat")
'"this" "that"y%smg&91uux!}"admin_istrator" "letmein"y'
>>> import_data("users2.dat")
['"t', "k97$ma{~'", '"foo" "bar"', '"admin_istrator" "letmein"']

Окончательное обновление: Base 64, другие махинации.

def import2(file):
    with open(file, "rb") as f:
        return filter(str.strip, [decrypt(i) for i in f.readlines()])

где encrypt и decrypt encode in / decode base 64.

Ответы [ 3 ]

1 голос
/ 07 июня 2011

Вы пытаетесь сохранить бинарный файл в текстовом режиме.Используйте open(file, "wb") для записи и open(file, "rb") для чтения, чтобы открыть файл в двоичном режиме и исправить проблему.

В текстовом режиме все последовательности "\r", "\n" и "\r\n" обрабатываются как символы новой строки, поэтомуони преобразуются в соглашение об окончании строки вашей локальной ОС ("\r\n" для Windows, "\n" для Unix, "\r" для старых Mac).Если вы читаете их из текстового файла, вы всегда получите "\n", а если вы напишите их, я не запомню фактическое поведение, но вы наверняка также получите беспорядок вместо ваших данных:)

А с XOR-шифрованием очень вероятно, что вы столкнетесь с такими вещами:)

Если вы вынуждены , а не использовать двоичные файлы, попробуйте кодировку base64 (например, "some\0te\n\nxt with bi\x01naries".encode('base64')),Для декодирования используйте .decode (спасибо, Капитан Очевидность!).

0 голосов
/ 07 июня 2011

Вы можете исправить это, зашифровав символы новой строки и не сбрасывая ключ между строками

from itertools import izip, cycle

KEY = "stackoverflow"

def encrypt(text):
    return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(text,key))

def decrypt(text):
    return encrypt(text)

def export(users, file):
    with open(file, "w") as f:
        for user, password in users.items():
            f.write(encrypt('"%s" "%s"\n'%(user, password)))

def import_data(file):
    with open(file) as f:
        return [decrypt(i) for i in f]


key = cycle(KEY)
export({"foo" : "bar", "baz" : "quux", "spam" : "eggs"}, "users.dat")

key = cycle(KEY)
for row in import_data("users.dat"):
    print row

Это должно быть превращено в класс, и key будет переменной экземпляра вместо глобальной, так какздесь

0 голосов
/ 07 июня 2011

Проблема в том, что вы не читаете те же данные, которые вы кодифицировали (вы добавляете '\ n' после шифрования), просто выполните rstrip () из прочитанных вами данных:

  def import_data(file):
    with open(file) as f:
       return [decrypt(i.rstrip()) for i in f.readlines()]
...