Switch Editions?
Cancel
Sharing:
Title:
URL:
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles

# The Cryptopals Crypto Challenges 解题报告（1）

0
0

the cryptopals crypto challenges 中包含8组练习，共48个挑战。我们可以通过完成挑战，来学习密码学的相关知识。

Set 0: Start

Set 0 包括：十六进制、字节数组、字符串两两之间的相互转化，字节数组的异或XOR运算，AES-ECB加密算法，分块方法。

related method：

python def hex_to_bytelist(hexString): return [ord(c) for c in hexString.decode("hex")]

python def bytelist_to_hex(byteList): return "".join(hex(x)[2:] if x > 15 else '0' + hex(x)[2:] for x in byteList)

python def str_to_hex(string): return string.encode("hex")

python def hex_to_str(hexString): return hexString.decode("hex")

（ps：还有其他的方法，这里只说明一种）

python def bytelist_to_str(byteList): return hex_to_str(bytelist_to_hex(byteList))

python def str_to_bytelist(string): return hex_to_bytelist(str_to_hex(string))

XOR

“`python

AES ECB

“`python def aes_ecb_encrypt(key, plaintext): crypto = AES.new(key, AES.MODE_ECB) ciphertext = crypto.encrypt(plaintext) return ciphertext

def aes_ecb_decrypt(key, ciphertext): crypto = AES.new(key, AES.MODE_ECB) plaintext = crypto.decrypt(ciphertext) return plaintext “`

python def chunks(string, n): for i in xrange(0, len(string), n): yield s[i:i+n] Set 1: Basics

Challenge 1: Convert hex to base64 Challenge 2: Fixed XOR Challenge 3: Single-byte XOR cipher Challenge 4: Detect single-character XOR Challenge 5: Implement repeating-key XOR Challenge 6: Break repeating-key XOR Challenge 7: AES in ECB mode Challenge 8: Detect AES in ECB mode

Challenge 1 : Convert hex to base64

string = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"

def hex_to_base64(hexString): return base64.b64encode(hexString.decode('hex')) string="49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d" print hex_to_base64(string)

Challenge 2: Fixed XOR

s1 = “1c0111001f010100061a024b53535009181c”

s2 = “686974207468652062756c6c277320657965”

res = “746865206b696420646f6e277420706c6179”

Set 0 中的xor方法是实现两个字节数组的异或。

def fixed_xor(s1, s2): return bytelist_to_hex(xor(hex_to_bytelist(s1), hex_to_bytelist(s2))) s1 = "1c0111001f010100061a024b53535009181c" s2 = "686974207468652062756c6c277320657965" print fixed_xor(s1, s2)

Challenge 3: Single-byte XOR cipher

hexString=“1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736”

get_score方法：输入参数为待评估的字符串，输出为该字符的频率得分。通过找到字符串中的每一个字符在字符频率表中对应的频率，相加之和，即为该字符串的频率得分。

singlebyte_xor方法：该方法实现单字符异或加密。输入为单字符密钥key和待加密的字符串，输出为加密后的字符串。通过将待加密的字符串中的每一个字符与单字符密钥key进行异或，从而进行加密，返回加密结果（ps：加密解密相同）。

traversal_singlebyte方法：输入为解密的字符串hexString，输出为解密结果。在该方法中，遍历0-255的字符key，调用singlebyte_xor方法对输入字符串进行解密，调用get_score方法对解密后的字符串进行评估。使用列表的方式存储每个密钥key及其对应的信息，列表中的元素是字典类型，包括key、解密结果plaintext以及字符频率得分score。使用sorted方法对列表进行排序，取得字符频率得分最高的解密结果返回。

CHARACTER_FREQ = { #字符频率表 'a': 0.0651738, 'b': 0.0124248, 'c': 0.0217339, 'd': 0.0349835, 'e': 0.1041442, 'f': 0.0197881, 'g': 0.0158610, 'h': 0.0492888, 'i': 0.0558094, 'j': 0.0009033, 'k': 0.0050529, 'l': 0.0331490, 'm': 0.0202124, 'n': 0.0564513, 'o': 0.0596302, 'p': 0.0137645, 'q': 0.0008606, 'r': 0.0497563, 's': 0.0515760, 't': 0.0729357, 'u': 0.0225134, 'v': 0.0082903, 'w': 0.0171272, 'x': 0.0013692, 'y': 0.0145984, 'z': 0.0007836, ' ': 0.1918182} def get_score(string): #计算字符串的频率得分 score = 0 for ch in string: ch = ch.lower() if ch in CHARACTER_FREQ: score += CHARACTER_FREQ[ch] return score def singlebyte_xor(key, string): #单字符异或加密 res = "" for i in string: ch = chr(key ^ ord(i)) res += ch return res def traversal_singlebyte(string): #遍历单个字符解密，评估 candidate = [] for key in range(256): plaintext = singlebyte_xor(key, string) score = get_score(plaintext) res={'key': key, 'plaintext': plaintext, 'score': score} candidate.append(res) #取得分最高的返回 return sorted(candidate, key = lambda c:c['score'])[-1] hexString="1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736" print traversal_singlebyte(hexString.decode('hex'))

Challenge 4: Detect single-character XOR

Challenge 5: Implement repeating-key XOR

res = "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"

def repeatingkey_xor(string, key): res="" #字符串连接，存放每一次加密后的结果 #xrange方法使得每次处理len(key)长度的字符串 for i in xrange(0, len(string), len(key)): res += bytelist_to_hex(xor(str_to_bytelist(string[i:i+len(key)]), str_to_bytelist(key))) return res string = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal" key = "ICE" print repeatingkey_xor(string, key)

Challenge 6: Break repeating-key XOR

（1）猜测密钥长度KEYSIZE，尝试2到40

（2）汉明距离hamming_distance，即为两个字符串异或之后，二进制格式1的个数

（3）对于每个KEYSIZE，求得每个解密块两两之间的汉明距离，对KEYSIZE取平均值（大概选取四个KEYSIZE块就够了）

（4）选取2-3个最小汉明距离的KEYSIZE（如果选取了正确的密钥长度，密文块与密文块两两之间的汉明距离等于对应的明文块与明文块两两之间的汉明距离，两两块之间的汉明距离的值应该趋于小）

（5）获得KEYSIZE之后，对每一块的对应字节组合后的字符串与单字符异或，从而可以破解密钥。（例如，每一块的第一字节组合后的字符串，如果分组正确，那么他们所对应的密钥字节是相同的，这是可以使用破解单字符异或的方法，来逐字符的破解密钥）

（6）对不同KEYSIZE解密后的明文进行评估，选取得分最高的一组。

def hamming_distance(s1, s2): dis = 0 for i in range(min(len(s1), len(s2))): b = bin(ord(s1[i]) ^ ord(s2[i])) dis += b.count('1') return dis def guess_keysize(string): keys = [] for keysize in range(2, 40): blocks = [] count = 0 dis = 0 for i in range(0, len(string), keysize): count += 1 blocks.append(string[i:i+keysize]) if count == 4: break #选取四个块，两两组合求汉明距离 pairs = itertools.combinations(blocks, 2) for (x, y) in pairs: dis += hamming_distance(x, y) ndis = dis / keysize key = {'keysize': keysize, 'distance': ndis} keys.append(key) return sorted(keys, key=lambda c:c['distance'])[0:3] def guess_key(keysize, string): key = '' for i in range(keysize): now_str = '' #获取每个块相同位置的字符 for index, ch in enumerate(string): if index % keysize == i: now_str += ch key += chr(traversal_singlebyte(now_str)['key']) return key def break_repeatingkey_xor(string): keysizes = guess_keysize(string) candidate = [] plains = [] for keysize in keysizes: key = guess_key(keysize['keysize'], string) #二元组：重复密钥异或解密明文，对应密钥key plains.append((hex_to_str(repeatingkey_xor(string, key)), key)) return sorted(plains, key=lambda c:get_score(c[0]))[-1] f = open('challenge6.txt', 'r') s = f.read() string=base64.b64decode(s) res=break_repeatingkey_xor(string) print 'plaintext: \n'+res[0] print 'key: \n'+res[1]

Challenge 7: AES in ECB mode

key = “YELLOW SUBMARINE”

def aes_ecb_encrypt(key, plaintext): crypto = AES.new(key, AES.MODE_ECB) ciphertext = crypto.encrypt(plaintext) return ciphertext def aes_ecb_decrypt(key, ciphertext): crypto = AES.new(key, AES.MODE_ECB) plaintext = crypto.decrypt(ciphertext) return plaintext f = open('challenge7.txt', 'r') s = f.read() ciphertext = base64.b64deocde(s) key = "YELLOW SUBMARINE" plaintext = aes_ecb_decrypt(key, ciphertext) #这一步解密后的明文包含填充部分 plaintext = removePKCS7padding(plaintext) #去掉明文末尾的填充 print plaintext

（1）未去掉填充的末尾结果

（2）去掉填充后的完整结果

Challenge 8: Detect AES in ECB mode

def detect_ecb(ciphertext): blocks = [b for b in chunks(ciphertext, 16)] detects = [] for b in blocks: if blocks.count(b) > 1: detects.append(b) if detects: return "ECB MODE detected!" else: return "" f = open('challenge8.txt', 'r') i = 1 for line in f: print i, ': ', detect_ecb(line) i = i + 1

Viewing all articles

### 開箱 S60 T5R 2020

More Pages to Explore .....