Cypher: أكواد Python لحل الألغاز المتقدمة (3-4 ، 4-3 ، 5- * ، 6-5)

كيف حللت بعض الألغاز المتقدمة (3-4 ، 4-3 ، 5-1 ، 5-2 ، 5-3 ، 6-5) باستخدام بايثون

 

المُقدّمة

يوضح هذا الدليل كيف تمكنت من حل بعض الألغاز المتقدمة بمساعدة Python. في الأصل كنت أقوم بحل الألغاز بقلم رصاص ولقطات مطبوعة (مثل الصورة أدناه لـ 3-3 ؛ لا تنقر للتكبير إذا كنت لا تريد أن تكون مدللًا) ، ولكن بالنسبة للمشكلات اللاحقة ، سئمت من التجارب والأخطاء. لذا حصلت على بايثون للقيام بذلك.

ملاحظة: لنشر أكوادي على Steam Community ، كان علي إعادة تسمية المتغيرات لفهارس القائمة من i إلى x من أجل منعها من التحليل كعلامات ترميز (في رأيي ، يجب تجاهل العلامات داخل عنصر الكود).

3-4: تحليل التردد

يحسب الكود أدناه تكرار كل حرف. بمجرد الانتهاء من ذلك ، قم بتعيين كل حرف وفقًا للإخراج و ETAOIN SHRDLU ، وسوف تحدد الحروف. ثم يتم حل المشكلة بسهولة باستخدام قلم رصاص وورقة.
from collections import Counter

text = """
AJLPNYRJZJFLZYASGSKQGSMME
JKEJPFSVLPJLKKEJELNNSPZKY
NNYGNSGASGYZJGAKEYZYGASVW
NJKSWSKECNLUJZKEJZEYCYZWS
VOEKLGAHYKKJAZEJNYJZLKLGU
ESPPJLAFHSPZJLFSVGJRJPYTL
OYGJALZMJJKJPZUESSGJPLUEY
NATYOEKZLYNEJPKMSEVGAPJAK
SGZGLTJEYZCLGYSNL
""".replace("\n", "")

print(Counter(text))


النتيجة (لا تقم بالتكبير إذا كنت لا تريد أن تفسد):

4-3: تحليل التردد

لحل تشفير الاستبدال متعدد الأبجدية (Vigenère cipher) ، فإن أول شيء يجب فعله هو معرفة طول المفتاح. وفقًا للتلميح داخل اللعبة ، يوجد (على الأقل) تسلسلين متكرر من 3 أحرف: DUF و LUE. بحساب امتدادات المظهر لكل منهم ، ثم أخذ القاسم المشترك الأكبر ، نحصل على الطول الأرجح للمفتاح: 3.

بمجرد تحديد طول المفتاح ، يمكننا استخدام تقنية تحليل التردد كما هو الحال في الأصفار البديلة أحادية الأبجدية. يقسم الكود أدناه النص ciphetext إلى "مراحل" اعتمادًا على حرف المفتاح الذي يتم تطبيقه ، ويحسب تواتر الأحرف داخل المرحلة.

from collections import Counter

text = """\
LAFLUIWOYWPADUFHSNBVSWVNDZQDUF
RBPLUYQPLWLPHZRLUEDUBSYMIPRDIJ
HTYQUCUZYLKFRSKHZBUHULUEKPQFOY
LYSSAMWOCWHZOLGDTDDPPOFDDTGOPY
UDGWOYOSDRYKVVDVLAULRZYGWPLJZY
QKYPTWVLJIAFHHSWOMUVDDAPLMJLUE
PVLRNPDWFXWMQAFHZSEQCFAGQDFLJF
LHLDSWCLMQLFXUBULBDUBVPVWFQHWY
UHRHJGSOCUZZXAGFVLILQVAFDARKPQ
LZCQAGULJBUCZAMPL\
""".replace("\n", "")

phase1 = "".join(text[x] for x in range(len(text)) if x % 3 == 0)
phase2 = "".join(text[x] for x in range(len(text)) if x % 3 == 1)
phase3 = "".join(text[x] for x in range(len(text)) if x % 3 == 2)

triplets = (text[x - 2] + text[x - 1] + text[x] for x in range(2, len(text), 3))

print(Counter(phase1))
print(Counter(phase2))
print(Counter(phase3))
print(Counter(triplets))


يحاول الرمز أيضًا العثور على تسلسلات مكررة من 3 أحرف مثل DUF و LUE. اعتقدت أنه ليس من الضروري العثور على التسلسلات في المراحل بخلاف 1-2-3. لسوء الحظ ، لم يكن ذلك كافيًا للعثور على ما هو "THE" في النص الصريح.

4-3: هجوم القوة الغاشمة

بعد تجربة بعض التحولات وفقًا لتحليل التردد ، قررت أن أجرب جهاز الكمبيوتر الخاص بي.

يخرج الكود عدة مرشحين للحل ، لذلك يتعين علينا اختيار الحل الصحيح يدويًا.

from string import ascii_uppercase as alphabets
from itertools import product

text = """\
LAFLUIWOYWPADUFHSNBVSWVNDZQDUF
RBPLUYQPLWLPHZRLUEDUBSYMIPRDIJ
HTYQUCUZYLKFRSKHZBUHULUEKPQFOY
LYSSAMWOCWHZOLGDTDDPPOFDDTGOPY
UDGWOYOSDRYKVVDVLAULRZYGWPLJZY
QKYPTWVLJIAFHHSWOMUVDDAPLMJLUE
PVLRNPDWFXWMQAFHZSEQCFAGQDFLJF
LHLDSWCLMQLFXUBULBDUBVPVWFQHWY
UHRHJGSOCUZZXAGFVLILQVAFDARKPQ
LZCQAGULJBUCZAMPL\
""".replace("\n", "")

def char_to_num(char):
    return alphabets.index(char) + 1

def vigenere_sub(char1, char2):
    return alphabets[(char_to_num(char1) - char_to_num(char2) - 1) % 26]

for key_chars in product(alphabets, repeat=3):
    decryption = ""
    for x in range(len(text)):
        decryption += vigenere_sub(text[x], key_chars[x % 3])
    if "THE" in decryption and "AND" in decryption:
        print(key_chars)
        print(decryption)
        print()


كما قد يوحي الجزء العلوي الأيمن من الصورة ، كنتيجة لهجوم القوة الغاشمة ، علمت أنني قد أوشكت على حل اللغز عن طريق تحليل التردد ولكني تخليت عن عدم الثقة الكافية للمضي قدمًا. (لا تقم بتكبير الصورة إذا كنت لا تريد أن تفسد.)

5-1, 5-2, 5-3

بالنسبة لألغاز التشفير الآلية ، يمكننا كتابة رمز لمحاكاة وظائف Enigma. يمكننا استخدام نفس الكود لحلها جميعًا باستثناء:

  • بالنسبة للغز الثاني ، نحتاج إلى بعض التجربة والخطأ ، أو القليل من القوة الغاشمة ، لتحديد الدوران الأولي للقرص.
  • بالنسبة إلى اللغز الأخير ، نحتاج إلى وظيفة تبديل بعض أزواج الأحرف.
from string import ascii_uppercase as keyboard

scrambler1 = (keyboard, "UWYGADFPVZBECKMTHXSLRINQOJ")
scrambler2 = (keyboard, "AJPCZWRLFBDKOTYUQGENHXMIVS")
scrambler3 = (keyboard, "TAGBPCSDQEUFVNZHYIXJWLRKOM")
reflector = (keyboard, "YRUHQSLDPXNGOKMIEBFZCWVJAT")

def scramble(position, disk, backwards=False):
    row1, row2 = disk[::-1] if backwards else disk
    char = row1[position]
    return row2.index(char)

def rotate(disk, n):
    return (disk[0][n:] + disk[0][:n], disk[1][n:] + disk[1][:n])

def decrypt(char, *disks):
    x = keyboard.index(char)
    for disk in disks:
        x = scramble(x, disk)
    for disk in disks[-2::-1]:
        x = scramble(x, disk, True)
    return keyboard[x]

def decrypt_text(text, *disks):
    decryption = ""
    disk1 = disks[0]
    for char in text:
        disk1 = rotate(disk1, 1)
        decryption += decrypt(char, disk1, *disks[1:])
    return decryption

def swap(text, key):
    result = ""
    for char in text:
        result += key.replace(char, "") if char in key else char
    return result

def swap_keys(text, keys):
    for key in keys:
        text = swap(text, key)
    return text

def puzzle_5_1():
    print(decrypt_text("ZYDNI", scrambler1, reflector))

def puzzle_5_2():
    for i in range(26):
        scrambler = rotate(scrambler1, i)
        text = decrypt_text("QHSGUWIG", scrambler, reflector)
        if text[:2] == "XV":
            print(text)

def puzzle_5_3():
    text = "GYHRVFLRXY"
    keys = ("AB", "SZ", "UY", "GH", "LQ", "EN")
    text = swap_keys(text, keys)
    d1 = rotate(scrambler2, scrambler2[0].index("A"))
    d2 = rotate(scrambler1, scrambler1[0].index("E"))
    d3 = rotate(scrambler3, scrambler3[0].index("B"))
    text = decrypt_text(text, d1, d2, d3, reflector)
    text = swap_keys(text, keys)
    print(text)

puzzle_5_1()
puzzle_5_2()
puzzle_5_3()


6-5

اللغز بسيط - فقط تنفيذ الخوارزمية إلى الوراء. ومع ذلك ، فإن حل هذا يدويًا ، قد يؤدي خطأ صغير واحد إلى إفساد كل شيء. هذا هو السبب في أنني استخدمت (أو اضطررت إلى استخدام) Python لحل هذه المشكلة.

لاحظ أنني قمت بإعادة تفسير الخوارزمية: بدلاً من تطبيق تبديل الصفوف على كل من النص والمفتاح ثم XOR-ing لهم ، فسرت التعليمات على أنها XOR-ing أولاً ثم تبديل الصفوف - النتائج هي نفس الشيء.

def block(bitstr):
    return (bitstr[:4], bitstr[4:8], bitstr[8:12], bitstr[12:])

def swap(rows):
    return tuple(row[1] + row[0] + row[3] + row[2] for row in rows)

def xor(rows, key):
    keybits = "".join(bin(ord(char))[2:].zfill(8) for char in key)
    if len(keybits) != 16: raise AssertionError
    textbits = "".join(rows)
    val = "".join("0" if keybits[x] == textbits[x] else "1" for x in range(16))
    return block(val)

def shift(rows):
    result = []
    for n in range(len(rows)):
        row = rows[n]
        result.append(row[n:] + row[:n])
    return tuple(result)

def decrypt(cipher, key):
    return xor(swap(shift(cipher)), key)

ciphertext = block("1001011110110101")
first = decrypt(ciphertext, "BX")
second = decrypt(first, "YS")
print(chr(int(second[0] + second[1], 2)))
print(chr(int(second[2] + second[3], 2)))

By unvollstaendigkeitssatz

اترك تعليق

ArabicEnglishFrenchGermanItalianJapaneseKoreanPortugueseSpanish