Криптография/Блочные шифры. Атаки на блочные шифры: различия между версиями

Материал из SecSem Wiki
Перейти к навигации Перейти к поиску
м (Задание 2)
 
(не показаны 2 промежуточные версии этого же участника)
Строка 5: Строка 5:
 
====Ciphertexts====
 
====Ciphertexts====
  
<pre>
+
<syntaxhighlight lang="python">
xored_with_onebyte_key = b'%\r\r\x06B\x0e\x17\x01\tNB\n\x03\x14\x07B\x04\x17\x0c'
+
xored_with_onebyte_key = b"'\x1c\x1cS\x14\x1c\x1c\x17S\x07\x1cS\x11\x16S\x07\x01\x06\x16"
  
xored_with_multibyte_key = b"\x07\x0b\r\x1c\x00I\x04\x006C\x1c\x19\nI\x0e\x1b=\x07\x1bN\n\x0fE\x11!\x1a" \
+
xored_with_multibyte_key = b'\x08T\x1f\x10\x1a\x10E\x1d.\x00R\x03\x0c\x05\x17]a2\x17\x04\x1bD\x0c\x00a\x00\x1a\x00I\t\x0c\x1d%Y\x19\x0c\x05'\
                          b"\x18\x1a\n\x0e\x17\x13#\x0b\x11N\x0c\x07E\x06;\n\x1bN\x12\x06\x17\x1e7YH\r\x17" \
+
b'\x08\x00\x01oT4\x00\x08\x16E\x1a2T\x06\r\x0cD\t\x1a5\x00\x1e\x00D\x00\x00\x125\x1cR\x11\x01\x05\x11S#\x06\x1b\x0b\x0e'\
                          b"\x10\x15\x06<\x04\x1a\x0f\x15\x01\x1cR'\x0b\t\x1aE\x1e\x0c\x1e?C\x1b\x1a\n\x19E" \
+
b'\x17E\x07.\x00\x13\tI\x0b\x07\x1f(\x00\x17\x17\x08\x10\x0c\x1c/ZR,I\x13\x0c\x1f-T\x14\x04\n\x01E\x1e8T\x14\x00\x08\x16K'\
                          b"\x0b<\x16\x1aN\x0e\x00\x01R \n\x1b\x1a\x00\x1bE\x14!\x0c\x05N\x17\x0c\x04\x16:\r\x0fN" \
+
b'S\x08T\x05\x0c\x05\x08E\x03$\x06\x1f\x0c\x1dD\x0c\x07a\x00\x1dE\x19\x05\x16\x00a\x1b\x04\x00\x1bD\x08\x16a\x15\x1c\x01I'\
                          b"\x1c\x06\x10\x00s\x05\x01\x02\x00\x1aIR2\r\x0cN\x06\x1b\x1c\x02'\x0c\x0f\x1c\x04\x19\r" \
+
b'\x10\r\x01.\x01\x15\rI\t\x00]a5\x1c\x01I\x13\r\x16/T\x1b\x11I\x0c\x04\x00a\x13\x1d\x0b\x0cD\x15\x122\x00^E D\x12\x1a-\x18R'\
                          b"\x0bs\x17\x00\x0f\x11I\x12\x1b?\x0fH\x1d\x11\x06\x15R>\x02\x02\x01\x17I\x02\x1d%\x06\x1a\x00" \
+
b'\x11\x1c\x16\x0bS5\x1c\x17E\x00\n\x0b\x163T\x17\x1c\x0cD\x11\x1ca\x07\x17\x00I\r\x11\x00a\x04\x13\x11\x01JE$)\x11\x00\x00I'\
                          b"\x08\x0c\x0b\x06 C\x0e\x1c\n\x04E\x006\x02\x0c\x07\x0b\x0eE\x0b<\x16\x1aN\x03\x00\t\x17 M"
+
b'\x10\r\x16a\x12\x17\x04\x1bD\r\x122T\x15\n\x07\x01E\x07)\x11\x00\x00I\x13\x0c\x1f-T\x10\x00I\n\n\x07)\x1d\x1c\x02GD*\x1d-\rR,I\x13'\
 
+
b'\x0c\x1f-T\x00\x00\x04\x05\x0c\x1do'
</pre>
 
  
 +
</syntaxhighlight >
  
 
=== Задание 1===
 
=== Задание 1===
 
====Скрипт:====
 
====Скрипт:====
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
one = b'%\r\r\x06B\x0e\x17\x01\tNB\n\x03\x14\x07B\x04\x17\x0c'
+
symbl = "qwertyuiopasdfghjklzxcvbnm,./;'[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
all_symbols = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ, !?.()[]{}*-'
+
 
for key in range(1, 256):
+
def xor_srting(str, key):
    output = ''
+
result = ''
    for i in range(len(one)):
+
for i in range(len(str)):
        output = output + chr(one[i]^key)
+
s = chr(str[i] ^ key)
        if chr(one[i]^key) not in all_symbols:
+
if s not in symbl:
            output = ''
+
return False
            break
+
else:
    if len(output) > 0:
+
result += s
        print('key = ', chr(key), ' output = ', output)
+
return result
 +
 
 +
 
 +
for k in range(256):
 +
p = xor_srting(xored_with_onebyte_key , k)
 +
if p:
 +
print('key ', k, 'str ', p)
 
</syntaxhighlight >
 
</syntaxhighlight >
  
 
Вывод:
 
Вывод:
 
<pre>
 
<pre>
key = b output =  Good luck, have fun
+
key  114 str Unn!fnne!un!cd!ustd
key = o output =  Jbbi-axnf!-el{h-kxc
+
key  115 str Too good to be true
 
</pre>
 
</pre>
 
  
 
=== Задание 2===
 
=== Задание 2===
Строка 47: Строка 52:
 
Определяет длину ключа.
 
Определяет длину ключа.
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
xored_with_multibyte_key = b"\x07\x0b\r\x1c\x00I\x04\x006C\x1c\x19\nI\x0e\x1b=\x07\x1bN\n\x0fE\x11!\x1a" \
+
symbl = "qwertyuiopasdfghjklzxcvbnm,./;'[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
                          b"\x18\x1a\n\x0e\x17\x13#\x0b\x11N\x0c\x07E\x06;\n\x1bN\x12\x06\x17\x1e7YH\r\x17" \
+
 
                          b"\x10\x15\x06<\x04\x1a\x0f\x15\x01\x1cR'\x0b\t\x1aE\x1e\x0c\x1e?C\x1b\x1a\n\x19E" \
+
def count_weight(num):
                          b"\x0b<\x16\x1aN\x0e\x00\x01R \n\x1b\x1a\x00\x1bE\x14!\x0c\x05N\x17\x0c\x04\x16:\r\x0fN" \
+
return bin(num).count('1')
                          b"\x1c\x06\x10\x00s\x05\x01\x02\x00\x1aIR2\r\x0cN\x06\x1b\x1c\x02'\x0c\x0f\x1c\x04\x19\r" \
+
 
                          b"\x0bs\x17\x00\x0f\x11I\x12\x1b?\x0fH\x1d\x11\x06\x15R>\x02\x02\x01\x17I\x02\x1d%\x06\x1a\x00" \
+
def foo(str, key_len):
                          b"\x08\x0c\x0b\x06 C\x0e\x1c\n\x04E\x006\x02\x0c\x07\x0b\x0eE\x0b<\x16\x1aN\x03\x00\t\x17 M"
+
weight = 0
def weight(val):
+
tmp_str = str[key_len:] + str[:key_len]
    res = 0
+
for i in range(len(str)):
    while val > 0:
+
weight += count_weight(str[i] ^ tmp_str[i])
        res = res + val % 2;
+
return weight/len(str)
        val = val // 2
 
    return res
 
  
print('Calculating Hamming distance')
 
  
for i in range(1, len(xored_with_multibyte_key)//2):
+
for i in range(2, len(c)//2):
    s  = 0
+
#tmp_w = xor_srting(c, i)
    xored_with_multibyte_key_mov = xored_with_multibyte_key[i:]+xored_with_multibyte_key[:i]
+
tmp_w  = foo(c, i)
    for j in range(len(xored_with_multibyte_key)):
+
if tmp_w < 2.7:
        p = xored_with_multibyte_key[j] ^ xored_with_multibyte_key_mov[j]
+
print(i, ' ', tmp_w)
        s = s + weight(p)
+
 
    if s/len(xored_with_multibyte_key) < 2.7:
 
        print(i, ' ', s/len(xored_with_multibyte_key))
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Строка 76: Строка 76:
 
<pre>
 
<pre>
 
Calculating Hamming distance
 
Calculating Hamming distance
8  2.536082474226804
+
8  2.498360655737705
16  2.6597938144329896
+
16  2.5311475409836066
24  2.670103092783505
+
24  2.6950819672131145
64   2.6597938144329896
+
32   2.675409836065574
72  2.6804123711340204
 
 
</pre>
 
</pre>
  
Строка 88: Строка 87:
 
Принимает на вход длину блока (разбивает строку на сеты и ломает каждый как однобайтовый xor-шифр):  
 
Принимает на вход длину блока (разбивает строку на сеты и ломает каждый как однобайтовый xor-шифр):  
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
import sys
 
xored_with_multibyte_key = b"\x07\x0b\r\x1c\x00I\x04\x006C\x1c\x19\nI\x0e\x1b=\x07\x1bN\n\x0fE\x11!\x1a" \
 
                          b"\x18\x1a\n\x0e\x17\x13#\x0b\x11N\x0c\x07E\x06;\n\x1bN\x12\x06\x17\x1e7YH\r\x17" \
 
                          b"\x10\x15\x06<\x04\x1a\x0f\x15\x01\x1cR'\x0b\t\x1aE\x1e\x0c\x1e?C\x1b\x1a\n\x19E" \
 
                          b"\x0b<\x16\x1aN\x0e\x00\x01R \n\x1b\x1a\x00\x1bE\x14!\x0c\x05N\x17\x0c\x04\x16:\r\x0fN" \
 
                          b"\x1c\x06\x10\x00s\x05\x01\x02\x00\x1aIR2\r\x0cN\x06\x1b\x1c\x02'\x0c\x0f\x1c\x04\x19\r" \
 
                          b"\x0bs\x17\x00\x0f\x11I\x12\x1b?\x0fH\x1d\x11\x06\x15R>\x02\x02\x01\x17I\x02\x1d%\x06\x1a\x00" \
 
                          b"\x08\x0c\x0b\x06 C\x0e\x1c\n\x04E\x006\x02\x0c\x07\x0b\x0eE\x0b<\x16\x1aN\x03\x00\t\x17 M"
 
  
sym = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ, !?.'
+
symbl = "qwertyuiopasdfghjklzxcvbnm,./;[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
 +
key_len = 8
  
key_len = int(sys.argv[1])
+
def xor_srting(str, key):
 +
    result = ''
 +
    for i in range(len(str)):
 +
        s = chr(str[i] ^ key)
 +
        if s in symbl:
 +
            result += s
 +
        else:
 +
            return False
 +
        #result += s
 +
    return result
 +
 
 +
def find_key(c):
 +
    for k in range(256):
 +
        p = xor_srting(c, k)
 +
        if p:
 +
            print('key:', chr(k), '| text:', p)
  
def break_message(mes, k):
 
    res = b""
 
    for i in range(len(mes)//key_len):
 
        res = res + mes[i*key_len+k:i*key_len+1+k]
 
    return res
 
  
 
print('Finding possible keys\n')
 
print('Finding possible keys\n')
for t in range(key_len):
+
 
     short_mes = break_message(xored_with_multibyte_key, t)
+
for j in range(key_len):
 +
     short_c = b''
 +
    for q in range(len(c)//key_len):
 +
        short_c += c[j + key_len*q].to_bytes(1, 'big')
 +
    find_key(short_c)
 
     print('-'*25)
 
     print('-'*25)
    flag = 1
 
    for i in range(1, 256):
 
        output = ''
 
        flag = 1
 
        for j in range(len(short_mes)):
 
            output = output + chr(i ^ short_mes[j])
 
            if chr(i ^ short_mes[j]) not in sym and j < len(short_mes)-1:
 
                flag = 0
 
        if flag:
 
            print(t+1, 'mini_key =', i, '->', chr(i), ' ', output)
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Строка 127: Строка 123:
 
Finding possible keys
 
Finding possible keys
  
 +
key: @ | text: Hn!!e/ruucnhomxHd!!!n!o!rmus!!i!rimimm
 +
key: A | text: Io  d.sttboinlyIe  o n sltr  h shlhll
 
-------------------------
 
-------------------------
1 mini_key = 83 -> S  Tenrphdotlosri at lmvseo
 
 
-------------------------
 
-------------------------
 +
key: r | text: m ehkFtl iae ffwmovngnio, eeearegrbn r
 
-------------------------
 
-------------------------
3 mini_key = 104 -> h  etspys rasrsmgidgh jrfdr
+
key: e | text: ufaeiehetnlrIaeii edhdtn t yeteaoeegIe
 
-------------------------
 
-------------------------
4 mini_key = 110 -> n  rw t  catt t  l rasonri
 
 
-------------------------
 
-------------------------
5 mini_key = 101 -> e  eoooiwrp okeryecattrmonf
+
key: d | text: ta mlr dasotwerl a tmwh  rn i.t ewn wa
 
-------------------------
 
-------------------------
6 mini_key = 104 -> h  !!gfonxivqhsdnrsq!n!dlfh
+
key: e | text:  riie let bii . ismhehapwnntt hh ioOii
6 mini_key = 105 -> i    fgnoyhwpireosrp o emgi
 
6 mini_key = 118 -> v  ??yxqpfwhovmzplmo?p?zrxv
 
 
-------------------------
 
-------------------------
7 mini_key = 101 -> e  ak r rpyi d au,yhwpgn  l
+
key: s | text: n.snriia tlolm ptser.esai eosWeatltnln
 
-------------------------
 
-------------------------
8 mini_key = 114 -> r  ricatlt ly fdr pyi otrye
 
 
</pre>
 
</pre>
  
Строка 149: Строка 143:
 
Принимает на вход ключ (если символ ключа - '*', то не преобразует соответствующий символ шифр-текста).
 
Принимает на вход ключ (если символ ключа - '*', то не преобразует соответствующий символ шифр-текста).
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
import sys
+
symbl = "qwertyuiopasdfghjklzxcvbnm,./;[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
xored_with_multibyte_key = b"\x07\x0b\r\x1c\x00I\x04\x006C\x1c\x19\nI\x0e\x1b=\x07\x1bN\n\x0fE\x11!\x1a" \
+
key_len = 8
                          b"\x18\x1a\n\x0e\x17\x13#\x0b\x11N\x0c\x07E\x06;\n\x1bN\x12\x06\x17\x1e7YH\r\x17" \
+
key = b'**re*des'
                          b"\x10\x15\x06<\x04\x1a\x0f\x15\x01\x1cR'\x0b\t\x1aE\x1e\x0c\x1e?C\x1b\x1a\n\x19E" \
 
                          b"\x0b<\x16\x1aN\x0e\x00\x01R \n\x1b\x1a\x00\x1bE\x14!\x0c\x05N\x17\x0c\x04\x16:\r\x0fN" \
 
                          b"\x1c\x06\x10\x00s\x05\x01\x02\x00\x1aIR2\r\x0cN\x06\x1b\x1c\x02'\x0c\x0f\x1c\x04\x19\r" \
 
                          b"\x0bs\x17\x00\x0f\x11I\x12\x1b?\x0fH\x1d\x11\x06\x15R>\x02\x02\x01\x17I\x02\x1d%\x06\x1a\x00" \
 
                          b"\x08\x0c\x0b\x06 C\x0e\x1c\n\x04E\x006\x02\x0c\x07\x0b\x0eE\x0b<\x16\x1aN\x03\x00\t\x17 M"
 
 
 
key = sys.argv[1]
 
key_len = len(key)
 
  
output = ''
+
res = ''
for i in range(len(xored_with_multibyte_key)):
+
for i in range(len(c)):
     if key[i%key_len] == '*':
+
     if key[i % key_len] != b'*'[0]:
         output = output + chr(xored_with_multibyte_key[i])
+
         key_symbol = key[i % key_len]
 
     else:
 
     else:
         output = output + chr(xored_with_multibyte_key[i] ^ ord(key[i%key_len]))
+
         key_symbol = 0
 +
    res += chr(c[i] ^ key_symbol)
  
print(output)
+
print(res)
 
</syntaxhighlight >
 
</syntaxhighlight >
  
Вывод для аргумента 'S*hneier'
+
Вывод для аргумента '**re*des'
 
<pre>
 
<pre>
T
+
Tmu�t n. f
ere areCtwo kins of cr�ptograp
+
          ar.a2easaheImin%YkileroTFr i2Tth
                              y in th
+
                                          li5leDdea5 tat #ins t.alIobl(etio/Z IIwil-Tfa
s worldY cryptoraphy t
+
e m8Tfr.Twil p$mi itao assaeeandIthr.ghIme.a5ndIwhe/TitIhasaon
                      at willCstop yor kid s
+
                                                              pa2,   wi- trn 5e nne3Tey
ster fr
+
                                                                                        toaeeIitsaat. W IIwil-Treainooe t)reIwil-TbeInot)ngG On-
d cryptiles, a
 
      graphy hat wil stop mjor govrnmentsCfrom reding yor filesM
 
 
</pre>
 
</pre>
  
Второй символ ключа угадываем из идеи, что строка <code>willCstop</code> должно отобразиться в <code>will stop</code>, тогда он определяется как <code>chr(ord('C')^ord(' '))</code> и равен <code>c</code>. В итоге ключ равен <code>Schneier</code> а текст расшифровывается в
+
Первый символ ключа выбирается из <code>A</code> и <code>@</code> по более осмысленному тексту при соответствующей подстановке.
 +
 
 +
Вывод для аргумента 'A*re*des'
 +
<pre>
 +
ITmu�t no f
 +
          ar. 2eas heImindYkiler.TFr isTth
 +
                                            litleDdeat tat bins toalIoblietionZ IIwillTfa
 +
e myTfr. ITwil pemi it o ass ee ndIthroghIme. 5ndIwhenTitIhas on
 +
                                                                pas,  wil trn te nnerTey
 +
                                                                                          to eeIits at. IIwillTreain.Tgoe threIwillTbeInothngG Onl
 +
</pre>
 +
 
 +
Второй символ ключа угадываем из идеи, что строка <code>whenTit</code> должно отобразиться в <code>when it</code>, тогда он определяется как <code>chr(ord('T')^ord(' '))</code> и равен <code>t</code>.
 +
Пятый символ ключа угадываем из идеи, что строка <code>itIhas</code> должно отобразиться в <code>itIhas</code>, тогда он определяется как <code>chr(ord('I')^ord(' '))</code> и равен <code>i</code>.  
 +
 
 +
В итоге ключ равен <code>Atreides</code>а текст расшифровывается в
  
 
<pre>
 
<pre>
There are two kinds of cryptography in this world: cryptography that will stop your kid sister from reading your files, and cryptography that will stop major governments from reading your files.
+
I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past, I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.
 
</pre>
 
</pre>

Текущая версия на 11:23, 29 февраля 2024

Ссылки

Ciphertexts

xored_with_onebyte_key = b"'\x1c\x1cS\x14\x1c\x1c\x17S\x07\x1cS\x11\x16S\x07\x01\x06\x16"

xored_with_multibyte_key = b'\x08T\x1f\x10\x1a\x10E\x1d.\x00R\x03\x0c\x05\x17]a2\x17\x04\x1bD\x0c\x00a\x00\x1a\x00I\t\x0c\x1d%Y\x19\x0c\x05'\
b'\x08\x00\x01oT4\x00\x08\x16E\x1a2T\x06\r\x0cD\t\x1a5\x00\x1e\x00D\x00\x00\x125\x1cR\x11\x01\x05\x11S#\x06\x1b\x0b\x0e'\
b'\x17E\x07.\x00\x13\tI\x0b\x07\x1f(\x00\x17\x17\x08\x10\x0c\x1c/ZR,I\x13\x0c\x1f-T\x14\x04\n\x01E\x1e8T\x14\x00\x08\x16K'\
b'S\x08T\x05\x0c\x05\x08E\x03$\x06\x1f\x0c\x1dD\x0c\x07a\x00\x1dE\x19\x05\x16\x00a\x1b\x04\x00\x1bD\x08\x16a\x15\x1c\x01I'\
b'\x10\r\x01.\x01\x15\rI\t\x00]a5\x1c\x01I\x13\r\x16/T\x1b\x11I\x0c\x04\x00a\x13\x1d\x0b\x0cD\x15\x122\x00^E D\x12\x1a-\x18R'\
b'\x11\x1c\x16\x0bS5\x1c\x17E\x00\n\x0b\x163T\x17\x1c\x0cD\x11\x1ca\x07\x17\x00I\r\x11\x00a\x04\x13\x11\x01JE$)\x11\x00\x00I'\
b'\x10\r\x16a\x12\x17\x04\x1bD\r\x122T\x15\n\x07\x01E\x07)\x11\x00\x00I\x13\x0c\x1f-T\x10\x00I\n\n\x07)\x1d\x1c\x02GD*\x1d-\rR,I\x13'\
b'\x0c\x1f-T\x00\x00\x04\x05\x0c\x1do'

Задание 1

Скрипт:

symbl = "qwertyuiopasdfghjklzxcvbnm,./;'[]!? QWERTYUIOPASDFGHJKLZXCVBNM"

def xor_srting(str, key):
	result = ''
	for i in range(len(str)):
		s = chr(str[i] ^ key)
		if s not in symbl:
			return False
		else:
			result +=  s
	return result


for k in range(256):
	p = xor_srting(xored_with_onebyte_key , k)
	if p:
		print('key ', k, 'str ', p)

Вывод:

key  114 str  Unn!fnne!un!cd!ustd
key  115 str  Too good to be true

Задание 2

Скрипт 1

Определяет длину ключа.

symbl = "qwertyuiopasdfghjklzxcvbnm,./;'[]!? QWERTYUIOPASDFGHJKLZXCVBNM"

def count_weight(num):
	return bin(num).count('1')

def foo(str, key_len):
	weight = 0
	tmp_str = str[key_len:] + str[:key_len]
	for i in range(len(str)):
		weight += count_weight(str[i] ^ tmp_str[i])
	return weight/len(str)		


for i in range(2, len(c)//2):
	#tmp_w = xor_srting(c, i)
	tmp_w  = foo(c, i)
	if tmp_w < 2.7:
		print(i, ' ', tmp_w)

Вывод:

Calculating Hamming distance
8   2.498360655737705
16   2.5311475409836066
24   2.6950819672131145
32   2.675409836065574

Выбираем длину ключа 8.

Скрипт 2

Принимает на вход длину блока (разбивает строку на сеты и ломает каждый как однобайтовый xor-шифр):

symbl = "qwertyuiopasdfghjklzxcvbnm,./;[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
key_len = 8

def xor_srting(str, key):
    result = ''
    for i in range(len(str)):
        s = chr(str[i] ^ key)
        if s in symbl:
            result += s
        else:
            return False
        #result += s
    return result

def find_key(c):
    for k in range(256):
        p = xor_srting(c, k)
        if p:
            print('key:', chr(k), '| text:', p)


print('Finding possible keys\n')

for j in range(key_len):
    short_c = b''
    for q in range(len(c)//key_len):
        short_c += c[j + key_len*q].to_bytes(1, 'big')
    find_key(short_c)
    print('-'*25)

Вывод:

Finding possible keys

key: @ | text: Hn!!e/ruucnhomxHd!!!n!o!rmus!!i!rimimm
key: A | text: Io  d.sttboinlyIe   o n sltr  h shlhll
-------------------------
-------------------------
key: r | text: m ehkFtl iae ffwmovngnio, eeearegrbn r
-------------------------
key: e | text: ufaeiehetnlrIaeii edhdtn t yeteaoeegIe
-------------------------
-------------------------
key: d | text: ta mlr dasotwerl a tmwh  rn i.t ewn wa
-------------------------
key: e | text:  riie let bii . ismhehapwnntt hh ioOii
-------------------------
key: s | text: n.snriia tlolm ptser.esai eosWeatltnln
-------------------------

Скрипт 3

Принимает на вход ключ (если символ ключа - '*', то не преобразует соответствующий символ шифр-текста).

symbl = "qwertyuiopasdfghjklzxcvbnm,./;[]!? QWERTYUIOPASDFGHJKLZXCVBNM"
key_len = 8
key = b'**re*des'

res = ''
for i in range(len(c)):
    if key[i % key_len] != b'*'[0]:
        key_symbol = key[i % key_len]
    else:
        key_symbol = 0
    res += chr(c[i] ^ key_symbol)

print(res)

Вывод для аргумента '**re*des'

Tmu�t n. f
          ar.a2easaheImin%YkileroTFr i2Tth
                                           li5leDdea5 tat #ins t.alIobl(etio/Z IIwil-Tfa
e m8Tfr.Twil p$mi itao assaeeandIthr.ghIme.a5ndIwhe/TitIhasaon
                                                               pa2,   wi- trn 5e nne3Tey
                                                                                         toaeeIitsaat. W IIwil-Treainooe t)reIwil-TbeInot)ngG On-

Первый символ ключа выбирается из A и @ по более осмысленному тексту при соответствующей подстановке.

Вывод для аргумента 'A*re*des'

ITmu�t no f
           ar. 2eas heImindYkiler.TFr isTth
                                            litleDdeat tat bins toalIoblietionZ IIwillTfa
e myTfr. ITwil pemi it o ass ee ndIthroghIme. 5ndIwhenTitIhas on
                                                                 pas,   wil trn te nnerTey
                                                                                           to eeIits at. IIwillTreain.Tgoe threIwillTbeInothngG Onl

Второй символ ключа угадываем из идеи, что строка whenTit должно отобразиться в when it, тогда он определяется как chr(ord('T')^ord(' ')) и равен t. Пятый символ ключа угадываем из идеи, что строка itIhas должно отобразиться в itIhas, тогда он определяется как chr(ord('I')^ord(' ')) и равен i.

В итоге ключ равен Atreidesа текст расшифровывается в

I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past, I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.