南郵ctf-密碼學(前五題)
寫writeup之前先來介紹一下Base編碼系列:base16,base32與base64。
1.
Base16編碼使用16個ASCII可列印字元(數字0-9和字母A-F)對任意位元組資料進行編碼。Base16先獲取輸入字串每個位元組的二進位制值(不足8位元在高位補0),然後將其串聯進來,再按照4位元一組進行切分,將每組二進位制數分別轉換成十進位制,在下述表格中找到對應的編碼串接起來就是Base16編碼。可以看到8位元資料按照4位元切分剛好是兩組,所以Base16不可能用到填充符號“=”。
Base16編碼後的資料量是原資料的兩倍:1000位元資料需要250個字元(即 250*8=2000 位元)。換句話說:Base16使用兩個ASCII字元去編碼原資料中的一個位元組資料。
Base16編碼是一個標準的十六進位制字串(注意是字串而不是數值),更易被人類和計算機使用,因為它並不包含任何控制字元,以及Base64和Base32中的“=”符號。
值 | 編碼 | 值 | 編碼 |
---|---|---|---|
0 | 0 | 8 | 8 |
1 | 1 | 9 | 9 |
2 | 2 | 10 | A |
3 | 3 | 11 | B |
4 | 4 | 12 | C |
5 | 5 | 13 | D |
6 | 6 | 14 | E |
7 | 7 | 15 | F |
2.Base32編碼是使用32個可列印字元(字母A-Z和數字2-7)對任意位元組資料進行編碼的方案,編碼後的字串不用區分大小寫並排除了容易混淆的字元,可以方便地由人類使用並由計算機處理。
值 | 符號 | 值 | 符號 | 值 | 符號 | ||
---|---|---|---|---|---|---|---|
0 | A | 8 | I | 16 | Q | 24 | Y |
1 | B | 9 | J | 17 | R | 25 | Z |
2 | C | 10 | K | 18 | S | 26 | 2 |
3 | D | 11 | L | 19 | T | 27 | 3 |
4 | E | 12 | M | 20 | U | 28 | 4 |
5 | F | 13 | N | 21 | V | 29 | 5 |
6 | G | 14 | O | 22 | W | 30 | 6 |
7 | H | 15 | P | 23 | X | 31 | 7 |
填充 | = |
Base32將任意字串按照位元組進行切分,並將每個位元組對應的二進位制值(不足8位元高位補0)串聯起來,按照5位元一組進行切分,並將每組二進位制值轉換成十進位制來對應32個可列印字元中的一個。
由於資料的二進位制傳輸是按照8位元一組進行(即一個位元組),因此Base32按5位元切分的二進位制資料必須是40位元的倍數(5和8的最小公倍數)。例如輸入單位元組字元“%”,它對應的二進位制值是“100101”,前面補兩個0變成“00100101”(二進位制值不足8位元的都要在高位加0直到8位元),從左側開始按照5位元切分成兩組:“00100”和“101”,後一組不足5位元,則在末尾填充0直到5位元,變成“00100”和“10100”,這兩組二進位制數分別轉換成十進位制數,通過上述表格即可找到其對應的可列印字元“E”和“U”,但是這裡只用到兩組共10位元,還差30位元達到40位元,按照5位元一組還需6組,則在末尾填充6個“=”。填充“=”符號的作用是方便一些程式的標準化執行,大多數情況下不新增也無關緊要,而且,在URL中使用時必須去掉“=”符號。
與Base64相比,Base32具有許多優點:
- 適合不區分大小寫的檔案系統,更利於人類口語交流或記憶。
- 結果可以用作檔名,因為它不包含路徑分隔符 “/”等符號。
- 排除了視覺上容易混淆的字元,因此可以準確的人工錄入。(例如,RFC4648符號集忽略了數字“1”、“8”和“0”,因為它們可能與字母“I”,“B”和“O”混淆)。
- 排除填充符號“=”的結果可以包含在URL中,而不編碼任何字元。
Base32也比Base16有優勢:
- Base32比Base16佔用的空間更小。(1000位元資料Base32需要200個字元,而Base16則為250個字元)
Base32的缺點:
- Base32比Base64多佔用大約20%的空間。因為Base32使用8個ASCII字元去編碼原資料中的5個位元組資料,而Base64是使用4個ASCII字元去編碼原資料中的3個位元組資料。
3.
Base64編碼是使用64個可列印ASCII字元(A-Z、a-z、0-9、+、/)將任意位元組序列資料編碼成ASCII字串,另有“=”符號用作字尾用途。
數值 | 字元 | 數值 | 字元 | 數值 | 字元 | 數值 | 字元 |
---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w |
1 | B | 17 | R | 33 | h | 49 | x |
2 | C | 18 | S | 34 | i | 50 | y |
3 | D | 19 | T | 35 | j | 51 | z |
4 | E | 20 | U | 36 | k | 52 | 0 |
5 | F | 21 | V | 37 | l | 53 | 1 |
6 | G | 22 | W | 38 | m | 54 | 2 |
7 | H | 23 | X | 39 | n | 55 | 3 |
8 | I | 24 | Y | 40 | o | 56 | 4 |
9 | J | 25 | Z | 41 | p | 57 | 5 |
10 | K | 26 | a | 42 | q | 58 | 6 |
11 | L | 27 | b | 43 | r | 59 | 7 |
12 | M | 28 | c | 44 | s | 60 | 8 |
13 | N | 29 | d | 45 | t | 61 | 9 |
14 | O | 30 | e | 46 | u | 62 | + |
15 | P | 31 | f | 47 | v | 63 | / |
Base64將輸入字串按位元組切分,取得每個位元組對應的二進位制值(若不足8位元則高位補0),然後將這些二進位制數值串聯起來,再按照6位元一組進行切分(因為2^6=64),最後一組若不足6位元則末尾補0。將每組二進位制值轉換成十進位制,然後在上述表格中找到對應的符號並串聯起來就是Base64編碼結果。
由於二進位制資料是按照8位元一組進行傳輸,因此Base64按照6位元一組切分的二進位制資料必須是24位元的倍數(6和8的最小公倍數)。24位元就是3個位元組,若原位元組序列資料長度不是3的倍數時且剩下1個輸入資料,則在編碼結果後加2個=;若剩下2個輸入資料,則在編碼結果後加1個=。
完整的Base64定義可見RFC1421和RFC2045。因為Base64演算法是將3個位元組原資料編碼為4個位元組新資料,所以Base64編碼後的資料比原始資料略長,為原來的4/3。在電子郵件中,根據RFC822規定,每76個字元,還需要加上一個回車換行。可以估算編碼後資料長度大約為原長的135.1%。
Base64可用於任意資料的底層二進位制資料編碼,以應用於只能傳輸ASCII字元的場合。不過最常用於文字資料的處理傳輸,例如在MIME格式的電子郵件中,Base64可以用來編碼郵件內容,方便在不同語言計算機間傳輸而不亂碼,注意是傳輸而不是顯示,例如在西歐地區計算機上使用utf-8編碼即可正常顯示中文(安裝有對應字型檔),但是它未必能正常傳輸中文,這時轉換為Base64便無此顧慮。
1.easy!
可以看到密文中含有小寫字母,八成斷定是base64編碼。將其放入base線上編碼轉換中解碼得到flag。
2.KeyBoard
可以畫出每個字串在鍵盤上的軌跡。
nctf{areuhack}
3.base64全家桶
base線上編碼轉換按base64、base32、base16順序解碼即可。
nctf{base64_base32_and_base16}
4.n次base64
點選密文地址,看到密文很長。python解吧!!將密文複製下來,以base.txt命名,將base.txt文件和下面程式碼放到同一檔案下。
import base64
content = open("base.txt")
try:
flag = content.read()
finally:
content.close()
while 1:
try:
flag = base64.b64decode(flag)
except:
print(flag);
break;
執行可得flag。
5.騷年來一發嗎
密文:iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas
根據提示明文字串經過加密函式(先反轉明文字串得到$_o,再將$_o字串裡的每個字元(從第一個字元開始)加一,再base64編碼,再反轉再rot13,最後返回加密後的字串)後得到密文:iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas
那就寫解密函式就行了。
<?php
$c='iEJqak3pjIaZ0NzLiITLwWTqzqGAtW2oyOTq1A3pzqas';
function decode($str)
{
$re=base64_decode(strrev(str_rot13($str)));
$m='';
for($i=0;$i<strlen($re);$i++)
{
$m.=chr(ord(substr($re,$i,1))-1);
}
return strrev($m);
}
echo decode($c);
?>
解密函式先將密文rot13,再反轉,再base64,得到字串$re,再將字串$re,從第一個字元開始取對應字元的ASCII 值,然後減一,再取ASCII 值對應的字元,將得到的字串接到$m,再將$m反轉即可。