學習筆記——cryptopals解密(一)


前言

第一次接觸加密算法,通過Crytopals來學習。

參考文章:

  1. cryptopals解密之旅 (一)
  2. 淺談常見的七種加密算法及實現

Set 1:Basics

1.第一題

在這裏插入圖片描述
在這裏插入圖片描述
從題中可以瞭解,需要將文章中16進制轉換爲base64編碼,那麼首先了解一下base64。
Base64:是網絡上最常見的用於傳輸8Bit字節碼的編碼方式之一,是一種基於64個可打印字符來表示二進制數據的方法。


(1) Base64是網絡上最常見的用於傳輸8Bit字節碼的可讀性編碼算法之一。
(2) 可讀性編碼算法不是爲了保護數據的安全性,而是爲了可讀性。
(3) 可讀性編碼不改變信息內容,只改變信息內容的表現形式

在一些網絡傳送渠道,有時候有些的字節字符不能被支持.比如圖片的二進制流的每個字節不可能全部是可見字符,這種情況下傳送不了.而Base64的機制就能很好解決這種問題,它不改變原來的協議,在原來的基礎做一種擴展,基於64個可打印字符來表示二進制.這樣不會改變原來的圖片,同理還有郵件等需要加密的文件。

首先,瞭解下base64是如何編碼的:
首先我們規定一個字符:abc
1.將字符通過ASCII碼編碼。
2.將編好的ASCII碼變爲二進制(8位),並以6位爲一組,分成四組。
3.將這四組的高位各補兩個0,轉爲十進制數。
4.查表,得到對應的字符,就是對應的Base64轉化的字符。
在這裏插入圖片描述





如果最後剩下兩個輸入數據,在編碼結果後加1個“=”;如果最後剩下一個輸入數據,編碼結果後加2個“=”;如果沒有剩下任何數據,就什麼都不要加。或分成6位一組後,最後一組沒有到6位時需要填充一個=或者兩個=。

在這裏插入圖片描述

代碼實現(python):

from enum import Enum
b64_encoding_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijk" \
                     "lmnopqrstuvwxyz0123456789+/"
class Status(Enum):
    START_NEX = 0
    TAKE_2 = 1
    TAKE_4 = 2
def hex_to_base64(hexdata):
    b64data = ""
    sixbits = 0
    status = Status.START_NEX
    for hexchar in hexdata:
        dec = int(hexchar, 16)
        if status == Status.START_NEX:
            sixbits = dec
            status = Status.TAKE_2
        elif status == Status.TAKE_2:
            sixbits = (sixbits << 2) | (dec >> 2)
            b64data += b64_encoding_table[sixbits]
            sixbits = (dec & 0x3)
            status = Status.TAKE_4
        elif status == Status.TAKE_4:
            sixbits = (sixbits << 4) | dec
            b64data += b64_encoding_table[sixbits]
            status = Status.START_NEX
    if status == Status.TAKE_2:
        sixbits <<= 2
        b64data += b64_encoding_table[sixbits]
        b64data += "="
    elif status == Status.TAKE_4:
        sixbits <<= 4
        b64data +=  b64_encoding_table[sixbits]
        b64data += "=="
    return b64data
def main():
    print(hex_to_base64("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"))
if __name__ == '__main__':
    main()

結果爲
在這裏插入圖片描述

2.第二題

在這裏插入圖片描述
由題可知,這題是考察XOR異或。
需要對兩個16進制代碼異或,生成下面的代碼。
使用python實現:


def hex_xor (hex1, hex2):
    dec1 = int(hex1, 16)
    dec2 = int(hex2, 16)
    xor = dec1 ^ dec2
    return hex(xor)
def main():
    a = hex_xor("1c0111001f010100061a024b53535009181c",
     "686974207468652062756c6c277320657965")
    print(a)
if __name__ == '__main__':
    main()

結果爲
在這裏插入圖片描述
但是,結果中含有[0x]這個前綴,查閱資料發現,只要在return處後面加[2:] 就可以解決。

 return hex(xor)[2:]

結果與題目中所要結果相同。

異或:異或運算符”∧”,它的規則是若參加運算的兩個二進位同號,則結果爲0(假);異號則爲1(真)。即 0∧0=0,0∧1=1, 1^0=1,1∧1=0。

運算 說明
0^1=1, 0^0=0 0異或任何數,其結果=任何數
1^0=1, 1^1=0 1異或任何數,其結果=任何數取反
x^x=0 任何數異或自己,等於把自己置0

異或的運算:先轉化爲二進制,再對照位來進行運算,相同爲0,不同爲1。
通過按位異或運算,可以實現兩個值的交換,而不必使用臨時變量。例如交換兩個整數a=3,b=4的值,可通過下列語句實現:

a=a∧b;
b=b∧a;
a=a∧b;

3.第三題

在這裏插入圖片描述
在第三題裏,只給了一個經過異或的密文,而我們知道是由單個字符所異或,這裏起初想用暴力破解。
字符頻率是一個很好的指標,我沒有考慮到字符頻率的問題(不在目前知識範圍內)而忽略了這個提示,查閱百度發現,字符頻率就是日常生活該字符的使用頻率。如果爲正常的英文文本,那麼它的字符頻率應該儘可能的大。所以,只要能計算出哪個字符異或後字符頻率打,這就是這道題的答案。
比如這裏有兩個解密後的字符串:
I am a student.
sd evbgac rgbq.
通過計算
第一個:0.04+0.19+0.08+0.02+0.19+0.08+0.19+0.06+0.09+0.02+0.04+0.12+0.06+0.09=1.27
同理第二個:
0.82
由此可知。第一個爲正確結果









首先準備一個字符頻率表:
在這裏插入圖片描述
然後再計算分值

def get_score(input_bytes):
    score = 0

    for byte in input_bytes:
        score += CHARACTER_FREQ.get(chr(byte).lower(), 0)

        return score

對字符串中每個字符與key進行異或

def singlechar_xor(input_bytes, key_value):
    output = b''
    for char in input_bytes:
        output += bytes([char ^ key_value])
        
    return output

用每個可能的字節對密碼異或解密,計算得出的明文分數。所用的key就是題目要找出來的key

def singlechar_xor_brute_force(ciphertext):

    candidates = []
    for key_candidate in range(256):
        plaintext_candidate = singlechar_xor(ciphertext, key_candidate)
        candidates_score = get_score(plaintext_candidate)
        result = {
   
    
            'key': key_candidate,
            'score': candidates_score,
            'plaintext': plaintext_candidate,
        }


        candidates.append(result)
    return  sorted(candidates, key=lambda c: c['score'], reverse=True)[0]

打印明文和key

def pretty_print_result(result):
    print(result['plaintext'].decode().rstrip(),
          "\tKey:", chr(result['key']))

最後的結果爲
在這裏插入圖片描述
由此可知加密前的明文和key。

參考文章:

  1. 什麼是Base64?
  2. 異或
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章