跳轉到內容

維基少年:樹莓派/樹莓派謎機

來自華夏公益教科書
布萊切利莊園

政府通訊總部和樹莓派基金會 CC-BY-SA 4.0

基於樹莓派 OctoPi 教程:https://projects.raspberrypi.org/en/projects/octapi-brute-force-enigma

什麼是謎機?

[編輯 | 編輯原始碼]

謎機是一種用於加密和解密資訊的裝置。它是在20世紀初開發的,在第二次世界大戰期間被德國人廣泛用於編碼他們的軍事通訊。

謎機最出名的是被阿蘭·圖靈和他在布萊切利莊園的團隊破解,他們開發了破譯謎機密碼的技術。這在第二次世界大戰中盟軍的勝利中發揮了至關重要的作用,因為它使他們能夠攔截並解碼德國人傳送的重要資訊。

謎機是如何工作的?

[編輯 | 編輯原始碼]

謎機是如何工作的? 在 YouTube 上

謎機由以下部分組成

  • 一個用於輸入資訊的鍵盤
  • 一系列執行加密和解密的轉子
  • 一個反射器,將電流反射回轉子,方向相反

轉子可以設定在不同的位置,從而產生大量可能的組合,使得攻擊者很難解碼資訊。

工作表

[編輯 | 編輯原始碼]

檢視你的謎機設定表,你會發現今天的設定如下

轉子環設定插線板設定轉子起始位置
IV I V20 05 10SX KU QF UN JG TC LA WM OB ZFFNZ

解密一條資訊

[編輯 | 編輯原始碼]

解密後的資訊是什麼?

[編輯 | 編輯原始碼]

這裡有一條秘密資訊:GON XXLXYFQNZIK

  1. 開啟 Python 3,然後開啟名為 decrypt.py 的檔案
  2. chosen_rotors 旁邊的綠色引號 '' 內輸入所選轉子。
  3. 現在在 rotor_start 旁邊的綠色引號 '' 內輸入轉子起始位置的字母。
  4. message_key 旁邊的綠色引號 '' 內輸入資訊金鑰 GON
  5. 輸入明文,即秘密資訊 XXLXYFQNZIK
  6. 透過按 F5 鍵執行程式(如果提示儲存,請選擇“是”)。

你能解密這條資訊嗎?

[編輯 | 編輯原始碼]

使用相同的謎機設定,但不要忘記更改資訊金鑰:LJE OIVGWVHOVHKAU

加密一條資訊

[編輯 | 編輯原始碼]
  1. 開啟 Python 3,然後開啟名為 encrypt.py 的檔案
  2. 再次從設定表中輸入所選轉子,以及轉子起始位置。
  3. message_key 旁邊的綠色引號 ' ' 內輸入資訊金鑰 BFR
  4. 執行程式並檢查它是否有效——對於明文 RASPBERRYPI,生成的密文應該是 XXLXYFQNZIK

現在是時候加密你自己的資訊了!

  • 選擇不同的三個字母的 message_key 並輸入。
  • 選擇不同的明文資訊並輸入。確保沒有空格!
  • 執行程式,然後記下加密的金鑰和密文,並將它們交給其他人解密。

解密這條資訊:GED HYZFQOOVVBBKBWPDZLSL

暴力破解攻擊

[編輯 | 編輯原始碼]

你需要知道謎機設定才能解密資訊!

這是今天的設定。不幸的是,有人在轉子設定上灑了墨水 😟

轉子環設定插線板設定轉子起始位置
21 15 16KL IT PQ MY XC NF VZ JB SH OGPOW

字謎是你在知道明文和密文的情況下才能知道的資訊。

字謎:WEATHER
密文:VZTLMPU

如果你知道字謎和部分設定,你能使用暴力破解攻擊解密這條資訊嗎?

VZTLMPUSLKTEXYWZWKXDOTT

暴力破解攻擊

[編輯 | 編輯原始碼]
  1. 開啟 Python 3,然後開啟名為 bruteforce.py 的檔案。
  2. 輸入字謎和相應的密文。
  3. 執行暴力破解攻擊,以找到轉子和資訊金鑰。

解密資訊

[編輯 | 編輯原始碼]
  1. 現在開啟之前使用過的 decrypt.py 程式。
  2. 輸入 rotor start 設定,這次你還需要從設定表中輸入環和插線板設定。
  3. 在暴力破解攻擊中找到的chosen rotors中輸入。
  4. 這次我們已經知道解密的訊息金鑰。找到這行程式碼:decrypted_message_key = machine.process_text(message_key)

將其更改為decrypted_message_key = '???',其中???是在暴力破解攻擊中找到的三個字母的金鑰。

  • 秘密資訊是什麼?

最終挑戰

[編輯 | 編輯原始碼]

DHPCMHCQ PXE

18/05/18
ZOC EJDTLFHR BT UKW.

本教程使用Brian Neal 編寫的 py-enigma 模組來提供 Enigma 機器功能。

您可以透過在終端中執行此命令在您的 Raspberry Pi(或您的計算機)上安裝 py-enigma 的副本

sudo pip3 install py-enigma

進一步閱讀

[編輯 | 編輯原始碼]

維基少年第二次世界大戰一書中有一節介紹 Enigma 機器,其中詳細介紹了它的工作原理。

瞭解 Enigma 機器的最佳場所是參觀英國米爾頓凱恩斯附近的 布萊切利莊園

模仿遊戲(2014)是一部由本尼迪克特·康伯巴奇主演的電影,他扮演了破譯 Enigma 機器的阿蘭·圖靈。這部電影的年齡分級為 12 級(在美國為 PG-13 級),因此適合年齡較大的兒童和成年人。

樹莓派基金會推薦傳記Dilly — The Man Who Broke Enigmas(2010,ISBN 9781906447151)由 Mavis Batey 撰寫。這本書講述的是二戰期間英國首席密碼破譯員阿爾弗雷德·迪爾溫·諾克斯的故事。

本教程的原始 PDF 檔案可在維基共享資源上獲得

encrypt.py

[編輯 | 編輯原始碼]
from enigma.machine import EnigmaMachine

chosen_rotors = ''    # Type a space between each rotor e.g. V IV I
rotor_start = ''
message_key = ''
plaintext = 'RASPBERRYPI'   # The message you want to encrypt

print("You started with message key " + message_key + " and plaintext " + plaintext)

# Set up the Enigma machine
machine = EnigmaMachine.from_key_sheet(
   rotors=chosen_rotors,
   reflector='B',
   ring_settings='20 5 10',
   plugboard_settings='SX KU QP VN JG TC LA WM OB ZF')

# Set the initial position of the Enigma rotors
machine.set_display(rotor_start)

# Encrypt the message key (the three letters you chose)
encrypted_message_key = machine.process_text(message_key)
print("The encrypted message key is " + encrypted_message_key)

# Set the rotor start position to the UNENCRYPTED message key
machine.set_display(message_key)

# The result
ciphertext = machine.process_text(plaintext)

print("The cipher text is: " + ciphertext)

decrypt.py

[編輯 | 編輯原始碼]
from enigma.machine import EnigmaMachine

chosen_rotors = ''    # Type a space between each rotor e.g. V IV I
rotor_start = ''
message_key = ''
plaintext = ''   # The message you want to decrypt

print("You started with message key " + message_key + " and plaintext " + plaintext)

# Set up the Enigma machine
machine = EnigmaMachine.from_key_sheet(
   rotors=chosen_rotors,
   reflector='B',
   ring_settings='20 5 10',
   plugboard_settings='SX KU QP VN JG TC LA WM OB ZF')

# Set the initial position of the Enigma rotors
machine.set_display(rotor_start)

# Decrypt the message key
decrypted_message_key = machine.process_text(message_key)
print("The decrypted message key is " + decrypted_message_key)

# Set the rotor start position to the DECRYPTED message key
machine.set_display(decrypted_message_key)

# The result
ciphertext = machine.process_text(plaintext)

print("The cipher text is: " + ciphertext)

bruteforce.py

[編輯 | 編輯原始碼]
cribtext = ""
ciphertext = ""

# All possible combinations of rotors
rotors = [ "I II III", "I II IV", "I II V", "I III II",
"I III IV", "I III V", "I IV II", "I IV III",
"I IV V", "I V II", "I V III", "I V IV",
"II I III", "II I IV", "II I V", "II III I",
"II III IV", "II III V", "II IV I", "II IV III",
"II IV V", "II V I", "II V III", "II V IV",
"III I II", "III I IV", "III I V", "III II I",
"III II IV", "III II V", "III IV I", "III IV II",
"III IV V", "IV I II", "IV I III", "IV I V",
"IV II I", "IV II III", "IV I V", "IV II I",
"IV II III", "IV II V", "IV III I", "IV III II",
"IV III V", "IV V I", "IV V II", "IV V III",
"V I II", "V I III", "V I IV", "V II I",
"V II III", "V II IV", "V III I", "V III II",
"V III IV", "V IV I", "V IV II", "V IV III" ]

def find_rotor_start( rotor_choice, ciphertext, cribtext ):

    from enigma.machine import EnigmaMachine

    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    machine = EnigmaMachine.from_key_sheet(
       rotors=rotor_choice,
       reflector='B',
       ring_settings='21 15 16',					
       plugboard_settings='KL IT PQ MY XC NF VZ JB SH OG')	


    # Search over all possible rotor starting positions
    for i in range(len(alphabet)):            # search for rotor 1 start position
        for j in range(len(alphabet)):        # search for rotor 2 start position
            for k in range(len(alphabet)):    # search for rotor 3 start position

                # Generate a possible rotor start position
                start_pos = alphabet[i] + alphabet[j] + alphabet[k]

                # Set machine initial starting position and attempt to decrypt
                machine.set_display(start_pos)
                plaintext = machine.process_text(ciphertext)

                #print("Plain: " + plaintext + ", Crib: " + cribtext)

                # Check if decrypted text is the same as the crib text
                if (plaintext == cribtext):
                    return( rotor_choice, start_pos )

    return( rotor_choice, "null" )



print("Brute force crypt attack on Enigma message " + ciphertext)
print("Crib text " + cribtext )

# Try all rotor settings 
for rotor_setting in rotors:
    print("Trying rotors " + rotor_setting)
    rotor_choice, start_pos = find_rotor_start( rotor_setting, ciphertext, cribtext )
    if (start_pos != "null"):
        print("Machine setting found!")
        print("Rotors: " + rotor_choice)
        print("Message key: " + start_pos)
        print("Using crib " + cribtext)
        exit(0)
華夏公益教科書