Всем хаброчитатилям привет, для начала расскажу что из себя представляет алгоритм "маской" (название придумал я).
И да, как можно прочитать в названии нам нужно сгенерировать маску чтобы потом её на что-то наложить. Вот так легко она генерируется:
# code n1
from random import shuffle
password = 'пароль'
data = ['какие-небудь данные']
mask = list(range(len(data)))
seed(password)
shuffle(mask)
Мой код может быть не идеален
Теперь давайте определимся что мы в принципе и будем шифровать
Мой выбор пал на байты, так как в них легко превратить почти всё в Python
А теперь давайте напишем сам алгоритм наложения маски!
Алгоритм кодирования:
#code n2
result = [0] * len(data)
for d in range(len(data)):
result[mask[d]] = data[d]
print(result)
А вот и алгоритм расшифровки:
#code n3
for d in mask:
result.append(data[d])
print(result)
Да, всё так просто
НО! Теперь давайте представим что мы просто зашифровали b'hello' и у нас получилось b'oelhl', даже человек простым подбором может прочитать это.
Поэтому нужно во что-то превратить эти байты чтобы они после шифровки небыли читабельными
Я выбрал превращать байты в биты и эти биты уже и шифровать
Вот код превращения из байтов в биты:
#code n4
result = []
for b in _bytes:
result.extend(map(int, f'{b:08b}'))
print(result)
А вот код обратного превращения:
#code n5
result = bytes(int(''.join(str(bit) for bit in bits), 2) for bits in [self.data[i:i + 8] for i in range(0, len(self.data), 8)])
print(result)
# Извините, если всё написал в одной строке и это не читабельно
А вот теперь и можно использовать этот алгоритм на практике. Давайте что-нибудь зашифруем!
password = 'привет'
data = b'hello'
mask = createMask(password) # создаём маску (code n1)
bits_data = toBits(data) # превращаем байты в биты (code n4)
enc_data = encode(data, mask) # кодируем алгиритмом "маски" (code n2)
bytes_enc_data = toBytes(enc_data) # расшифровывем биты в байты (code n5)
print(bytes_enc_data)
b'\xdb6T,^'
Круто, да! Мы получили полностью не читабельный рузультат, зашифрованный паролем!
Ну и также этот результат можно расшифровать:
bits_enc_data = toBits(bytes_enc_data) # превращаем шифрованый результат обратно в биты (code n4)
dec_bits = decode(bits_enc_data, mask) # расшифровывем биты (code n3)
bytes_dec_data = toBytes(dec_bits) # превращаем биты в байты (code n5)
print(dec_result)
b'hello'
И да, я сделал модуль на python
Исходный код модуля можно найти на
[https://github.com/michazaxm/shifrator]
И проект на pypi:
[https://pypi/project/enc-shifrator]
Комментарии (8)
andreymal
00.00.0000 00:00+9Если заранее известно, что зашифрована валидная utf-8 строка, то простейший брутфорсер пишется на коленке минут за двадцать, и это я ещё даже не пытался анализировать алгоритм
Скрытый текстdef to_bits(data: bytes) -> list[int]: data_bits: list[int] = [] for b in data: data_bits.extend(map(int, f'{b:08b}')) return data_bits def to_bytes(data_bits: list[int]) -> bytes: return bytes(int(''.join(str(bit) for bit in bits), 2) for bits in [data_bits[i:i + 8] for i in range(0, len(data_bits), 8)]) def shifrator_bruteforce(data: bytes, start_seed: int = 0): from random import Random data_bits: list[int] = to_bits(data) # [0, 1, 0, ...] rnd = Random() seed = start_seed while True: seed += 1 rnd.seed(seed) mask = list(range(len(data_bits))) # [0, 1, 2, ...] rnd.shuffle(mask) result_bits = [data_bits[i] for i in mask] try: yield seed, to_bytes(result_bits).decode("utf-8") except UnicodeDecodeError: pass seed += 1
encoded = b"r\x10~\xd8\xfd\xcc\xa3\x9bm\xba\"\xfd\xcc\ry\xcc\x17\xdb\x86D\xc0\x96\x97V\xf0\xe1\xb8\x1e\xa1\xa5w|" for seed, decoded in shifrator_bruteforce(encoded): print(seed, repr(decoded))
michazaxm Автор
00.00.0000 00:00Ok я это исправил и теперь на вход шифратора подаётся чистая строка с паролем
dprotopopov
00.00.0000 00:00+7Чукча не читатель, чукча писатель?
Это знакомо https://ru.wikipedia.org/wiki/Перестановочный_шифр ?
А то что вы назвали "маской" во всём мире называется перестановкой https://ru.wikipedia.org/wiki/Перестановка
deus
00.00.0000 00:00+2Сделал тебе не ломаемый! Не благодари!
import random import operator from binascii import hexlify def shifrator(text): mask = random.randbytes(len(text)) return bytes([operator.xor(ord(s), mask[i]) for (i, s) in enumerate(text)]), mask def deshifrator(ct, mask): return "".join([chr(operator.xor(s, mask[i])) for (i, s) in enumerate(ct)]) text = "Hello world" print(f'text: {hexlify(text.encode())}') ct, key = shifrator(text) pt = deshifrator(ct, key) print(f'CT: {hexlify(ct)}') print(f'Key: {hexlify(key)}') print(f'PT: {hexlify(pt.encode())}')
y@sweet ~/work $ python 1.py text: b'48656c6c6f20776f726c64' CT: b'd1b472f41906fb69d72cd0' Key: b'99d11e9876268c06a540b4' PT: b'48656c6c6f20776f726c64'
udik_chudik
00.00.0000 00:00+1Рекомендовал бы автору пересмотреть процедуру генерации "ключа" из строки-пароля. Судя по исходному коду, энтропия вызванная порядком букв в пароле вообще не принимается во внимание (пароли "привет" и "твиреп" дают одинаковый seed). Стоит изучить базовые принципы KDF.
Т.к. seed в итоге принимает на вход int, реально размер "ключа" составляет 32 бита, что в сочитании с атакой на основе открытого текста позволяет "взломать" "шифр" без особого труда
michazaxm Автор
00.00.0000 00:00P.S. Строка в utf-8 тут взята только для примера
Впринципе можно шифровать любые байты
sunnyfox
00.00.0000 00:00Ну, лиха беда начало, главное человек думает и пытается. Если не окажется подвержен эффекту Даннинга-Крюгера, то может что-то вырасти )
KillJ0y
00.00.0000 00:00Только один вопрос зачем?!
Gpg может шифровать и паролем и открытым ключом, это раз.
Второе с точки зрения безопасности - ну тут её нет.
Третье, если нужно шифровать файлы то тут проще если все очень конфиденциально то только fde и криптоконтейнеры, если же нет дешевле (в ресурсах) использовать не полное шифрование файлов (так шифровальщики делают). Мог бы больше рассказать с примерами с работы, но это затянется на целую статью.
michazaxm Автор
P.S. Строка в utf-8 тут взята только для примера
Впринципе можно шифровать любые байты