Статья Создаём уникальный шифр на Python

Сегодня речь пойдёт о шифровании. Если есть необходимость сохранить конфиденциальность информации в текстовых документах даже при их утечке в лапы кулцхакеров, то лучшим выходом будет шифровка.

SHifrovanie.jpg



В сети есть множество программ для этого дела, да вот беда – всё что шифруется, так же замечательно и дешифруется, ведь инструменты то в паблике. Конечно понадобятся какие-то усилия на поиск подходящей тулзы, но это не займёт слишком долго по времени.

Самый верный выход – это написать свой собственный encoder с уникальным кодом, не похожим на другие.
Приступим:

Сначала накидаем обычного Цезаря, но мы ведь русские, а значит нам понадобятся как латиница, так и кириллица. Буквы большие и маленькие -


Python:
# -*- coding:utf -8 -*-
# !/usr/bin/python3

# encoder
list_encoder = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЬЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщыьъэюяABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
n = int(input('Введите число: '+'\n'))
s = input('Введите текст: '+'\n')
encoder = ''
for c in s:
    encoder += list_encoder[(list_encoder.index(c) + n) % len(list_encoder)]
print(encoder)

Но это слишком просто, ничего уникального. А теперь мы «посолим» наш алфавит, разбавив его спецсимволами и знаками препинания, включая пробел.

Python:
list_encoder = 'А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№ШЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'


Вот так-то по-нашенски, по БРОзильски! )
К энкодеру конечно понадобится и декодер, иначе шифровка не имеет смысла


Python:
# decoder
list_decoder = 'А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№ШЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'
e = int(input('Введите число: '+'\n'))
x = input('Введите текст: '+'\n')
decoder = ''
for c in x:
    decoder += list_decoder[(list_decoder.index(c) - e) % len(list_decoder)]
print(decoder)

Запускаем, и вот что получилось:

cry.png



Уже мне нравится, взрыв мозга в расшифровке обеспечен. Но не будем на этом останавливаться, запутаем врага ещё больше – сделаем вывод задом наперёд. Для этого переделаем принт таким образом:

print(encoder[: :-1])

Результат:

cry1.png



И тут Остапа понесло… ))) А ещё круче??? Сказано – сделано.

Сначала напишем небольшую тулзу с рандомным перемешиванием символов, и забабахаем туда наш список.


Python:
import random
s='А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№ШЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'
x =''.join(random.sample(s,len(s)))
print(x)

Запустим несколько раз…. Я-ху!!!

cry2.png


Выберем вариант более приятный глазу и … прогоним наши входные данные по второму кругу )))

cry3.png



Как можно заметить кроме того, что мы использовали солёно-миксованный алфавит и 2 раза к тому же зазеркалили вывод, во второй заход использовался другой сдвиг. Соответственно при расшифровке нужно вводить сдвиг в обратном порядке.
А теперь, зная идею, вы можете модифицировать данный код, делая рандомные списки, и прогоняя хоть кучу раз через прогу.
Ну вот и всё, горе тому ЦРУ-шнику, которому пришлось бы возиться с такой рашифровкой, проще застрелиться! )))

А впрочем в ЦРУ и другая работа есть )

pindos.jpeg


Итоговый исходный код
Python:
# -*- coding:utf -8 -*-
# !/usr/bin/python3

# encoder
list_encoder = 'А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№ШЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'
n = int(input('Введите число: '+'\n'))
s = input('Введите текст: '+'\n')
encoder = ''
for c in s:
    encoder += list_encoder[(list_encoder.index(c) + n) % len(list_encoder)]
print(encoder[: :-1])

# encoder2
list_encoder2 = '%Ёеуъ? 2v#;<\9}иЧRЯfA№e4УАЖn|=ёюя`ИLBНМ_ЪC0~ZwIHбпrcbdqдgзВ"$Dэlхй,С-XF{Os(:БTжГ6zшЬJьkрpKEШЮХ]uGнЩ[YДQРт)W5N8U.7фxФ/ЛV!чiS1tЕТ3мjоЗmг^aвЭщPцскКПО&hMыа@yлЙoЦ+>*Ы'
n = int(input('Введите число: '+'\n'))
s = input('Введите текст: '+'\n')
encoder2 = ''
for c in s:
    encoder2 += list_encoder2[(list_encoder2.index(c) + n) % len(list_encoder2)]
print(encoder2[: :-1])

# decoder
list_decoder = '%Ёеуъ? 2v#;<\9}иЧRЯfA№e4УАЖn|=ёюя`ИLBНМ_ЪC0~ZwIHбпrcbdqдgзВ"$Dэlхй,С-XF{Os(:БTжГ6zшЬJьkрpKEШЮХ]uGнЩ[YДQРт)W5N8U.7фxФ/ЛV!чiS1tЕТ3мjоЗmг^aвЭщPцскКПО&hMыа@yлЙoЦ+>*Ы'
e = int(input('Введите число: '+'\n'))
x = input('Введите текст: '+'\n')
decoder = ''
for c in x:
    decoder += list_decoder[(list_decoder.index(c) - e) % len(list_decoder)]
print(decoder[: :-1])

# decoder2
list_decoder2 = 'А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№ШЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'
e = int(input('Введите число: '+'\n'))
x = input('Введите текст: '+'\n')
decoder2 = ''
for c in x:
    decoder2 += list_decoder2[(list_decoder2.index(c) - e) % len(list_decoder2)]
print(decoder2[: :-1])
 
пожалуй криптостойкость повыше будет чем у вшивого RSA-2048 :)

для тех кто пересел с велосипеда на автомобиль:
линк:
 
Последнее редактирование:
пожалуй криптостойкость повыше будет чем у вшивого RSA-2048 :)

для тех кто пересел с велосипеда на автомобиль:
линк:
Да, взломостойкость получается мощная. Правда статья подана как идея, как учебный материал. В таком виде неудобно декодировать, ведь сначала в программе идёт кодирование (можно конечно тупо на 2 проги разбить кодер и декодер), и к тому же при большом размере текста неудобно, ведь нужно хранить 2 варианта - и кодированный и промежуточный.

У меня уже в голове полностью готова Pro версия. Там не придётся для раскодировки хранить промежуточные данные и 2 раза вводить - прога сама это всё сделает и на выходе получится зашифрованный текст + ключи всегда одной длины. Причём ключи будет генерить пользователь, и таким образом даже создатель программы, то бишь я, не смогу их расшифровать.

Ну и ещё нужно добавить исключения, чтобы со всякой китайской клавиатуры ничего не вводили. Ещё - в этом варианте одиночная кавычка при вводе даст краш, потому как её нет в списке. А нет, так как весь список идёт как str и заключён в одиночные кавычки. Чтобы была возможность писать и одиночные кавычки, нужно переделать код, используя другие методы, типа словари/кортежи...
 
Да, взломостойкость получается мощная. Правда статья подана как идея, как учебный материал. В таком виде неудобно декодировать, ведь сначала в программе идёт кодирование (можно конечно тупо на 2 проги разбить кодер и декодер), и к тому же при большом размере текста неудобно, ведь нужно хранить 2 варианта - и кодированный и промежуточный.

У меня уже в голове полностью готова Pro версия. Там не придётся для раскодировки хранить промежуточные данные и 2 раза вводить - прога сама это всё сделает и на выходе получится зашифрованный текст + ключи всегда одной длины. Причём ключи будет генерить пользователь, и таким образом даже создатель программы, то бишь я, не смогу их расшифровать.

Ну и ещё нужно добавить исключения, чтобы со всякой китайской клавиатуры ничего не вводили. Ещё - в этом варианте одиночная кавычка при вводе даст краш, потому как её нет в списке. А нет, так как весь список идёт как str и заключён в одиночные кавычки. Чтобы была возможность писать и одиночные кавычки, нужно переделать код, используя другие методы, типа словари/кортежи...

Ну вот я сделал практически то что задумал - одиночные кавычки работают, ввод требуется только 1 раз, а не 2.
Для параноиков сделана функция генерации новых ключей. Нажмите цифру 3 и полученный ключ вставьте в строку 13 в тройных кавычках, сохраните код и запускайте с уникальными ключами )

А вот так это теперь выглядит:

3.png



Python:
# -*- coding:utf -8 -*-
# !/usr/bin/python3
import random

print(' 1] - кодировать')
print(' 2] - декодировать')
print(' 3] - создать новый ключ'+'\n')
text = input('Выберите действие:'+'\n')
  
# encoder
list_encoder = '''А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№Ш'ЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'''
# encoder2
list_encoder2 = '''%Ёеуъ? 2v#;<\9}иЧRЯfA№e4УАЖn|=ёюя`ИLBНМ_ЪC0~ZwIHбпr'cbdqдgзВ"$Dэlхй,С-XF{Os(:БTжГ6zшЬJьkрpKEШЮХ]uGнЩ[YДQРт)W5N8U.7фxФ/ЛV!чiS1tЕТ3мjоЗmг^aвЭщPцскКПО&hMыа@yлЙoЦ+>*Ы'''

# decoder
list_decoder = list_encoder2
# decoder2
list_decoder2 = list_encoder

# new key
def key():
    w=list_decoder
    q =''.join(random.sample(w,len(w)))
    print(q)

def enc():
    a = int(input('Введите число 1 для encoder: '+'\n'))
    n = int(input('Введите число 2 для encoder: '+'\n'))
    b = input('Введите текст для encoder: '+'\n')
    for c in b:
        encoder = ''
        encoder += list_encoder[(list_encoder.index(c) + a) % len(list_encoder)]
        s = encoder[: :-1]
  
        for c in s:
            encoder2 = ''
            encoder2 += list_encoder2[(list_encoder2.index(c) + n) % len(list_encoder2)]
            print(encoder2[: :-1],end = "")


def dec():
    e = int(input('Введите число 1 для decoder: '+'\n'))
    z = int(input('Введите число 2 для decoder: '+'\n'))
    x = input('Введите текст для decoder: '+'\n')
    for c in x:
        decoder = ''
        decoder += list_decoder[(list_decoder.index(c) - e) % len(list_decoder)]
        y = decoder[: :-1] 
  
        for c in y:
            decoder2 = ''
            decoder2 += list_decoder2[(list_decoder2.index(c) - z) % len(list_decoder2)]
            print(decoder2[: :-1],end = "")


if text == "1":
    enc()
elif text == "2":
    dec()
elif text == "3":
    key()
else:
    print("Введите 1,2 или 3!")

Осталось навести красоту - "обработать напильником" и добавить исключения на ввод текста.

P.S. Ключи 162 - значные, но можно сделать и больше, разбавив строку 13 алфавитом отличным от русско-английского (актуально, если пользуетесь разными клавиатурами), потом нужно сгенерить новый ключ и заменить строку 11.
 
Последнее редактирование:
Малость обновил программу. Добавил исключения на ввод выбора действия, ввода обоих сдвигов и для кодирования и для раскодирования. Для сдвига можно вводить как положительные числа так и отрицательные.
Пока не сделал ещё исключения для символов, которых нет на клавиатуре. Я включил параноика ) буду ещё усложнять шифрование, алгоритм уже готов, будет позже ещё обнова :)

Попробуем запутать программу вводя заведомо неправильные команды:

proga.png


Обработка ошибок работает, правильные команды принимаются. Следующая обнова будет с неожиданным поворотом )

Исходник:


Python:
# -*- coding:utf -8 -*-
# !/usr/bin/python3
import random

print(' 1] - кодировать')
print(' 2] - декодировать')
print(' 3] - создать новый ключ'+'\n')


# encoder
list_encoder = '''А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№Ш'ЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'''
# encoder2
list_encoder2 = '''%Ёеуъ? 2v#;<\9}иЧRЯfA№e4УАЖn|=ёюя`ИLBНМ_ЪC0~ZwIHбпr'cbdqдgзВ"$Dэlхй,С-XF{Os(:БTжГ6zшЬJьkрpKEШЮХ]uGнЩ[YДQРт)W5N8U.7фxФ/ЛV!чiS1tЕТ3мjоЗmг^aвЭщPцскКПО&hMыа@yлЙoЦ+>*Ы'''
# decoder
list_decoder = list_encoder2
# decoder2
list_decoder2 = list_encoder

# new key
def key():
    w = list_decoder
    q = ''.join(random.sample(w, len(w)))
    print(q)


def enc():
    while True:
        try:
            a = int(input('Введите целое число 1 для encoder: '+'\n'))
            break
        except ValueError:
            print("Это не целое число!")

    while True:
        try:
            n = int(input('Введите целое число 2 для encoder: '+'\n'))
            break
        except ValueError:
            print("Это не целое число!")

    b = input('Введите текст для encoder: '+'\n')
    for c in reversed(b):
        encoder = ''
        encoder += list_encoder[(list_encoder.index(c) + a) % len(list_encoder)]

        for j in encoder:
            encoder2 = ''
            encoder2 += list_encoder2[(list_encoder2.index(j) + n) % len(list_encoder2)]
            print(encoder2, end="")


def dec():
    while True:
        try:
            e = int(input('Введите целое число 1 для decoder: '+'\n'))
            break
        except ValueError:
            print("Это не целое число!")

    while True:
        try:
            z = int(input('Введите целое число 2 для decoder: '+'\n'))
            break
        except ValueError:
            print("Это не целое число!")

    x = input('Введите текст для decoder: '+'\n')
    for c in reversed(x):
        decoder = ''
        decoder += list_decoder[(list_decoder.index(c) - e) % len(list_decoder)]

        for f in decoder:
            decoder2 = ''
            decoder2 += list_decoder2[(list_decoder2.index(f) - z) % len(list_decoder2)]
            print(decoder2, end="")


while True:
    text_vybor = input('Выберите действие:'+'\n')
    if text_vybor == "1":
        enc()
        break
    elif text_vybor == "2":
        dec()
        break
    elif text_vybor == "3":
        key()
        break
    else:
        print("Введите 1,2 или 3!")
 
Последнее редактирование:
  • Нравится
Реакции: makatun
Пока не сделал ещё исключения для символов, которых нет на клавиатуре.

Защиту "от китайцев" запилил ) Из всего кода это для меня оказалось самым сложным (нужно было сравнить ключ с входными данными, причём со всеми), в итоге вышло лишь 5 строчек кода.

china.png
 
Очень быстро я понял что в моём коде есть большая дыра. Суть в том, что количество знаков в зашифрованном сообщении = количеству знаков шифровки. Вторая дыра это повторяющиеся синхронно символы. Соответственно код можно проанализировать, составить шифрокарту с повторяющимися символами. А это даёт возможность сделать частичную дешифровку.
Чтобы было понятно пример:

milk.png


Поэтому я поставил себе задачу изменить длину в шифровке и сделать её отличной от оригинала + чтобы частота повторяющихся символов была другая.
В новом коде это выглядит так:

milk2.png


Как мы видим вместо 6 символов стало 12 и теперь повторяющихся символов стало куда больше, что будет запутывать )

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

base.png

И так у нас было молоко а стало ExHfExHеEСNL

Рассмотрим как на самом деле у нас отработала программа:

1) молоко / ввод
2) околом / реверс
3) $н$о$4 / сдвиг по ключу на 5 символов
4) b'JNC9JNC+JDQ=' / кодирование в BASE64
5) JNC9JNC+JDQ= / обрезка мусора
6) ExHfExHеEСNL / сдвиг по второму ключу на 6 символов

Вот такая многоходовочка :)

Ещё в предыдущих версиях было неудобство - нужно при расшифровке было вводить цифры для сдвига наоборот. В данном примере при шифровке 5 и 6, а при расшифровке 6 и 5. Это логично, но так можно запутаться, просто забыв этот момент. Теперь ввод цифр при шифровке/расшифровке идентичен.

Код переписал заново, правда извиняйте, не стал уже навешивать функции с выборами и обработку ошибок, всё это можно слямзить с предыдущего кода. Главной задачей было исправить недостатки прошлой версии.

В порыве творчества я придумал другой криптошифр, сегодня выложу в паблике. До встречи!

Исходник:


Python:
# -*- coding:utf -8 -*-
# !/usr/bin/python3
import base64

# encoder
list_encoder = '''А.БВ,ГД:ЕЁ;ЖЗ[ИЙ]КЛ{МН}ОП"РС<ТУ>ФХ?ЦЧ№Ш'ЩЫЬЪЭЮЯа`бв~гд1её!жз2ий@к л3мн#оп4рс$ту5фх%цч6шщ^ыьъ7эю&яABCDEFGHIJKLMNOPQRSTUVWXYZa8bc*de9fg(hi0jk)lm-no_pq=rs+tuv\w|xy/z'''
# encoder2
list_encoder2 = '''%Ёеуъ? 2v#;<\9}иЧRЯfA№e4УАЖn|=ёюя`ИLBНМ_ЪC0~ZwIHбпr'cbdqдgзВ"$Dэlхй,С-XF{Os(:БTжГ6zшЬJьkрpKEШЮХ]uGнЩ[YДQРт)W5N8U.7фxФ/ЛV!чiS1tЕТ3мjоЗmг^aвЭщPцскКПО&hMыа@yлЙoЦ+>*Ы'''
list_decoder = list_encoder2
list_decoder2 = list_encoder

n = int(input('Введите целое число 1 для encoder: '+'\n'))
nn = int(input('Введите целое число 2 для encoder: '+'\n'))
s = input('Введите текст: '+'\n')
encoder = ''
for c in reversed(s):
    encoder += list_encoder[(list_encoder.index(c) + n) % len(list_encoder)]

bb = ((str(base64.b64encode(encoder.encode('utf-8')))[2:])[:-1])
encoder2 = ''
for c in bb:
    encoder2 += list_encoder2[(list_encoder2.index(c) + nn) % len(list_encoder2)]
print('\n' + 'Зашифрованный текст:' + '\n' + encoder2)

# decoder
ee = int(input('Введите целое число 1 для decoder: '+'\n'))
e = int(input('Введите целое число 2 для decoder: '+'\n'))
y = input('Введите текст: '+'\n')
decoder = ''
for c in y:
    decoder += list_decoder[(list_decoder.index(c) - e) % len(list_decoder)]

# decoder2
r = str(base64.b64decode(decoder).decode('utf-8'))
decoder2 = ''
for c in r:
    decoder2 += list_decoder2[(list_decoder2.index(c) - ee) % len(list_decoder2)]


print('\n' + 'Расшифрованный текст:' + '\n' + decoder2[::-1])
 
  • Нравится
Реакции: makatun, pp11 и Vertigo
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!