目錄
- 前言
- Set 1:Basics
- 1.第一題
- 2.第二題
- 3.第三題
前言
第一次接觸加密演算法,通過Crytopals來學習,
參考文章:
- cryptopals解密之旅 (一)
- 淺談常見的七種加密演算法及實作
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,
參考文章:
- 什么是Base64?
- 異或
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/246509.html
標籤:其他
上一篇:淺談Linux信號那些事
下一篇:Apache網頁優化實用技巧
