天天看點

1024程式員解密遊戲

    人們喜歡造節。一些人就起哄把 10 月 24 日叫做程式員節。1024 是 2 的 10 次方,是計算機存儲機關的換算率,1024 位元組等于 1K,1024K 等于 1M,以此類推。是以 1024 這個數字被認為與程式員相關。

    程式設計的本質是組合創造,是思考,優秀的程式應該正确、簡單、健壯。所謂的程式員節其實毫無意義。不過在身邊有兩個活動,一是親橙裡旁邊有一個展台派送禮品,二是下班的時候(約 18:30)

Rancher 公衆号推送了一個程式員解密遊戲 。這個遊戲其實有點意思,即貼合程式員知識,又貼合大衆娛樂。注意:想要自己解題的小夥伴看完圖檔後就此打住,不要再往下看了。
1024程式員解密遊戲
    謎面主體是圖檔中間的一段密文,群裡很快有人看出這是 摩爾斯電碼(Morse code)

,并得到官方确認。

    摩爾斯電碼(Morse code,又譯為摩斯密碼)是早期用于發送電報等資訊的編碼,與計算機使用二進制編碼資料類似,摩爾斯電碼使用短聲嘀 di 和長聲嗒 dah 兩種狀态編碼資料。以短聲嘀 di 的時間為一個時間機關 t,停頓時間也為 t,長聲嗒 dah 時間為 3t 。國際摩爾斯電碼給出了 26 個英文字母和 10 個阿拉伯數字的編碼表,如下圖所示。

1024程式員解密遊戲

    摩爾斯電碼并非純二進制編碼(如果使用純二進制編碼,編碼間的停頓應該是無意義的)。一個字元的摩爾斯電碼需要使用分隔符指明邊界。摩爾斯(或者維爾?)很聰明,他想到可以使用較長時間的停頓(3t)來分隔字元,還可以使用更長時間的停頓來分割單詞、句子等。停頓時間雖然有意義,但并不能引入全功能的狀态位(停頓本身也是狀态位的邊界),是以摩爾斯電碼也不是 3 進制編碼,大概可以叫做 2.5 進制編碼。

    書寫時通常使用點(

.

)表示滴 di,橫(

-

)表示嗒 dah,分割符可以使用空格或

/

等。通常空白無意義,使用

/

更容易閱讀和排版。可見上述密文幾乎是标準的摩爾斯電碼。根據圖檔提示,還可以回複公衆号得到可複制的文本形式密文,密文如下。

-.-/..-/..---/-/--./---/-.../--../-.-/..-/..---/.--/./-.--/
.-./-/-.-/..-/..---/--./-.-/---/-.../.--/-.-/..-/...--/-../
./--/.---/.-./-.-/..-/...--/-/--/---/-.../..-/-.-/..-/...--/
-/./-./.-../-.-./-.../../-...-/-...-/-...-/-...-/-...-/-...-           

    根據編碼表,就可以完成解碼。為了友善人肉編碼解碼,還有人整理了一張字母編碼表,如下圖所示。

1024程式員解密遊戲

    為了偷懶,直接在網上找了一個

線上翻譯器

。沒想到這個翻譯器很粗糙,還有部分編碼沒翻譯過來,看了下未翻譯的部分是數字,敢情這個翻譯器隻認識英文字母。

1024程式員解密遊戲

    還好數字部分不多,而且數字編碼規則很簡單(共 5 位,點在前每點加一,橫在前大于 5,每橫加一),可以人肉翻譯補齊,如

..---

2

。這時有人在群裡貼出了解碼後的結果,這樣是不對的,透露答案。于是我直接将其複制出來,如下,簡單核對了一下,應該沒問題。

KU2TGOBZKU2WEYRTKU2GKOBWKU3DEMJRKU3TMOBUKU3TENLCBI           

    稍後,官方宣布截止到 19:40 已有超過 34 人解密成功,但決定再追加 34 個名額。

    顯然,解碼後的這段文本仍然是一段編碼。官方透露第二層加密的線索也在圖檔中,還确認 2 的 5 次方裡有秘密,這樣是不對的,透露答案。2 的 5 次方是 32,于是我打開 python3 嘗試直接用 base32 解碼試試。

$ python3
Python 3.6.8 (default, Oct  7 2019, 12:59:55) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> base64.b32decode('KU2TGOBZKU2WEYRTKU2GKOBWKU3DEMJRKU3TMOBUKU3TENLCBI')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/base64.py", line 205, in b32decode
    raise binascii.Error('Incorrect padding')
binascii.Error: Incorrect padding           

    提示編碼沒有填充對齊,難道是前面摩爾斯電碼沒有解碼完嗎?回頭看,果然在編碼結尾

CBI

後,還有

-...-

這樣的編碼,上述國際摩爾斯電碼表裡查不出這個編碼,可能是某種擴充編碼,也可能根本就毫無意義。再看了下,發現原密文結尾連續出現 6 次出現此編碼,或許就隻是用來填充對齊 base32 編碼。不管了,先嘗試補 6 個

=

上去做填充對齊,再次嘗試 base32 解碼,竟解碼成功。

>>> base64.b32decode('KU2TGOBZKU2WEYRTKU2GKOBWKU3DEMJRKU3TMOBUKU3TENLCBI======')
b'U5389U5bb3U4e86U6211U7684U725b\n'           

    解碼結果出來一些數字。本來準備好解密的某一步要用上 1024 這個數字(活動源頭 + 圖檔中有隐約出現),但同時注意到每隔 4 個字元規律的出現一個大寫的

U

,結尾還有一個換行符

\n

,熟悉 Java 或者 JSON 字元串轉義的同學應該能猜到,這難道是變體的 Unicode 編碼?注意:在 JSON 或 python3 裡,2 位元組範圍的 Unicode 字元應該使用小寫的

\u

轉義,即

\uXXXX

的形式。手動解碼一下試試,果然得到有意義的文字字元,總共沒幾個字元,全部手動解碼即可。在英文編碼間兜兜轉轉,最終通過 Unicode 回歸偉大的中文。

>>> chr(0x5389)
'厲'
>>> chr(0x5bb3)
'害'           

解碼結果為

厲害了我的牛

,這應該就是最終解密結果了,公衆号回複驗證成功,不過趕不上前 n 名了。

最後,收獲是學習了摩爾斯電碼(然而并沒有什麼用?),缺憾是準備好的 1024 這個數字竟然沒用上。