日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【入门建议收藏】密码学学习笔记之线性分析入门篇——EzSPN

發布時間:2025/3/21 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【入门建议收藏】密码学学习笔记之线性分析入门篇——EzSPN 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

上一篇了解了一下差分分析,這次我們結合一道CTF題目聊一聊線性分析

同屬于選擇明文的差分分析不同,線性分析屬于已知明文攻擊方法,它通過尋找明文和密文之間的一個“有效”的線性逼近表達式,將分組密碼與隨機置換區分開來,并再此基礎上進行密鑰恢復攻擊。

在正式介紹線性分析之前,我們還是要介紹一下相關的基礎概念,參考《分組密碼的攻擊方法與實例分析》一書

基礎概念

首先還是給出和差分分析一樣的一個迭代分組密碼的加密流程

迭代分組密碼的加密流程

內積

線性掩碼

線性逼近表達式

線性殼

迭代分組密碼的一條 i 輪線性殼是指一對掩碼(β0,βi),其中β0 是輸入掩碼,βi 是輸出掩碼。

線性特征

線性殼的線性概率

線性特征的線性概率

線性區分器

先給出一個命題,對{0,1}^n 上的隨機置換R,任意給定掩碼α,β,α ≠ 0,β ≠ 0, 則 LP(α,β ) = 0,? 即 偏差 ε?(α,β) = 0

如果我們找到了一條 r-1 輪線性逼近表達式 (α,β),其線性概率 LP(α,β) ≠ 0,即偏差 ε(α,β) ≠ 0。則利用該線性逼近表達式可以將 r-1 輪的加密算法與隨即置換區分開來,利用該線性區分器就可以對分組密碼進行密鑰恢復攻擊。假設攻擊 r 輪加密算法,為獲得第 r 輪的輪密鑰的攻擊步驟如下。
步驟1

尋找一個 r – 1輪的線性逼近表達式 (α,β) ,設其偏差為ε(α,β),使得 |ε(α,β)|較大。

步驟2

根據區分器的輸出,攻擊者確定要恢復的第 r 輪輪密鑰 k_r(或者其部分比特):設攻擊的密鑰比特長度為 l,對每個可能的候選密鑰gk_i, 0 ≤ i ≤ 2^l -1,設置相應的 2^l 個計數器λ_i,并初始化。

步驟3

均勻隨機地選取明文 X,在同一個未知密鑰 k 下加密,(一般是讓擁有密鑰地服務端幫你加密)獲得相應地密文 Z, 這里選擇明文地數目為 m ≈ c ·(1/ε ^2),c 為某個常數。

步驟4

對一個密文Z,我們用自己猜測地第 r 輪輪密鑰 gk_i(或其部分比特)對其進行第 r 輪解密得到Y_{r-1},然后我們計算線性逼近表達式 α x · X ⊕ β · Y_{r-1} 是否為0,若成立,則給相應計數器λ_i 加 1

步驟5

將 2^l 個計數器中|λ/m – 1/2| 最大地指所對應地密鑰 gk_i(或其部分比特)作為攻擊獲得地正確密鑰值。

Remark 針對步驟1中,我們如何去尋找一個高概率地 r -1 輪線性逼近表達式呢?例如針對一個S盒,我們可以選擇窮舉所有的輸入、并獲得相應的輸出,然后窮舉輸入掩碼、輸出掩碼,去獲取這個S盒的相關線性特性。

下面就根據一道CTF中出現的賽題來解釋分析上述過程。

實例-[NPUCTF2020]EzSPN

task.py

import os from binascii import hexlify, unhexlify import Crypto.Random.random as random from secret import flagSZ = 8 coef = [239, 163, 147, 71, 163, 75, 219, 73] sbox = list(range(256)) random.shuffle(sbox) sboxi = [] for i in range(256):sboxi.append(sbox.index(i))def doxor(l1,l2):return [x[0]^x[1] for x in zip(l1,l2)]def trans(blk):res = []for k in range(0, SZ, 8):bits = [bin(x)[2:].rjust(8,'0') for x in blk[k:k+8]]for i in range(8):res.append(int(''.join([x[(i+1) % 8] for x in bits]),2))res[k:k+8] = [(coef[i] * res[k+i]) % 256 for i in range(8)]return resdef encrypt_block(pt, ks):cur = doxor(pt, ks[:SZ])cur = [sbox[x] for x in cur]cur = trans(cur)cur = [sboxi[x] for x in cur]cur = doxor(cur, ks[SZ:])return curdef encrypt(pt, k):x = 0 if len(pt)%SZ==0 else (SZ-len(pt)%SZ)pt += [x]*xct = ''for i in range(0, len(pt), SZ):res = encrypt_block([x for x in pt[i:i+SZ]], k)ct += ''.join(["{:02x}".format(xx) for xx in res])return ctdef doout(x):if len(x) % 16:x = (16 - len(x) % 16) * "0" + xreturn xdef doin(x):return list(unhexlify(x))def genkeys():return list(os.urandom(2*SZ))if __name__ == "__main__":print(sbox)key = genkeys()ct = encrypt(flag, key)print(ct)while True:pt = doin(input())print(doout(encrypt(pt, key)))

題目提供一個交互,能夠加密你的輸入并返回密文。所以這里是否可以采用差分分析的攻擊方法呢,但這里我們討論的線性分析,所以我們就用線性分析來做這道題目里。

那么看到這里所用加密系統的流程。

關鍵函數是encrypt_block(pt, ks),

首先是一個明文和一半的密鑰異或,然后是進入S盒(題目每次隨機生成并提供S盒具體內容),然后trans一下,再進入一個逆S盒,最后再和另一半的密鑰異或。

看到這個trans函數,這里有一個int(‘’.join([x[(i+1) % 8] for x in bits]),2),這個(i+1%8)有點類似位移的效果,然后是乘以了一個系數,但這個系數已經定死了,所以沒有什么關系。

首先測一個這個trans函數的一個位移效果,大概類似這樣


然后整個流程圖(畫的丑了點)

那么針對這道題,我們利用線性分析攻擊手法,

**步驟1,**我們去分析S盒的線性特性以找到使得線性表達式偏差大的掩碼對(α,β)。我們窮舉所有的S盒的可能的輸入并計算出相應的輸出,然后窮舉所有的輸入、輸出掩碼的組合,然后根據其是否符合滿足線性逼近表達式 α · X ⊕ β · F(X,K) = 0 來更新計數器,最后我們計算相應的偏差表offset

def linearSbox():global linearInput for i in range(256):si = sbox[i]for j in range(256):for k in range(256):a = bitxor(i, j) # 線性估計輸入b = bitxor(si, k) # 線性估計輸出 if a == b:offset[j][k] += 1for i in range(256):offset[i] = [abs(x - 128) / 256 for x in offset[i]]for linearOutput in range(256):cur = [x[linearOutput] for x in offset]linearInput.append(cur.index(max(cur)))

其中j是輸入掩碼,k是輸出掩碼。

這里的offset以輸入掩碼為行,輸出掩碼為列,所以這里的cur是獲取同一輸出掩碼下不同輸入掩碼的偏差

并且在linearInput中記錄下同一輸入掩碼下使得線性表達式偏差最大的輸出掩碼。

這里我們簡單看一下輸出的offset表

可以看到列表的第一行很特殊,除了第一個是0.5這個極大的值以外,其他都是0。因為在輸入掩碼為0、輸出掩碼也為0的話,肯定是能夠滿足的情況下,針對所有的輸入、輸出肯定是都能滿足線性逼近表達式的,所以偏差達到了最大,0.5。但是換做其他輸出掩碼的話,針對所有的輸出,其最后的表達式的結果分布得很均勻,所以偏差為0。

再舉第二行第一列的0.03131…這個值的含義:就是針對所有的256個輸入,當輸入掩碼為1,輸出掩碼為1時的線性逼近表達式的偏差。即有 256 * (0.03+0.5) ≈ 135 個輸入滿足(或者不滿足)這個線性逼近表達式。

有了S盒的線性特性之后,步驟2是設置一個計數器counter,然后我們開始進入步驟3搜集明文密文對。就隨機選擇明文,發送給服務端,然后接收服務端返回的密文即可。

接著開始步驟4,由于這里有兩輪加密,然后我們在步驟1已經生成了關于單個S盒的一個offset表,這個就相當于是 1 輪線性特征了,那么我們接下來就按照線性分析的攻擊思路,

這里我們按字節猜測密鑰,首先拿一個密文的第一個字節,異或第一個字節的密鑰(枚舉)后從S逆盒出去,然后把系數coef除掉,再根據P盒,把這個值換到相應的位置,然后這里我們根據S盒的線性特征選取合適的輸出、輸入掩碼對我們的這對輸入進行測試。若滿足線性逼近表達式,則True計數加一,否則False計數加一。

最后步驟5,針對每個字節我們都測一萬對,取結果偏差最大的key值。這樣就完成了密鑰每個字節的猜測。

結合代碼再細細講一遍

def calcOffset(pt, ct, j, guessed_key): # 猜測第j段子密鑰pt = list(unhexlify(pt))ct = list(unhexlify(ct))ct[j] ^= guessed_keyct[j] = sbox[ct[j]] # sbox即為sboxi的逆ct[j] = (ct[j] * coef[j]) % 256u1 = bitxor(pt[0], linearInput[1 << ((6 - j) % 8)])u2 = bitxor(ct[j], 0b10000000)if u1 == u2:return Trueelse:return Falsedef linearAttack():key2 = []for i in range(8): # 第二輪子密鑰的第i段count = [0 for _ in range(256)]for guessed_key in range(256):print("[+] Cracking key...({}-{})".format(i, guessed_key))for j in range(10000):if calcOffset(plain[j], cipher[j], i, guessed_key) == True:count[guessed_key] += 1bias = [abs(x - 5000) / 10000 for x in count]key2.append(bias.index(max(bias)))return key2

linearAttack()中我們主要關注那個循環。這里調用了calcOffset函數,傳入了一對明文密文對(plain[j], cipher[j])、索引(i)、以及猜測的密鑰(guessed_key)。

在calcOffset中,首先用密文異或了guessed_key,然后根據值獲取從Sbox的輸入,然后乘以了coef(這里已經是原來coef的逆了),接著是u2 = bitxor(ct[j], 0b10000000),用了0b10000000作為掩碼,即選取了密文的第一個bit。然后選取 linearInput[1 << ((6 – j) % 8)] 做為明文第一個字節的掩碼。

為什么只選明文的第一個字節,以及其掩碼的選取這里可能看的不是很直觀,因為這里其實包含了兩部分。

我們需要回去注意到P盒。當這里j=0,即爆破第一個字節的密鑰時,我們選取的是密文的第1個字節,掩碼選的是第1個bit,那么這是從P盒輸入的哪個bit傳來的呢,從P盒我們可以看到這是P盒輸入的第一個字節的第2bit傳來的,那么P盒輸入的第2bit,實際上就是S盒輸出的第2bit,也就是S盒的輸出掩碼為0b01000000,也就是1 << 6。而這個 linearInput 存的就是輸出掩碼為某個值的使得線性逼近表達式偏差最大的輸入掩碼。
linearAttack()中我們主要關注那個循環。這里調用了calcOffset函數,傳入了一對明文密文對(plain[j], cipher[j])、索引(i)、以及猜測的密鑰(guessed_key)。

在calcOffset中,首先用密文異或了guessed_key,然后根據值獲取從Sbox的輸入,然后乘以了coef(這里已經是原來coef的逆了),接著是u2 = bitxor(ct[j], 0b10000000),用了0b10000000作為掩碼,即選取了密文的第一個bit。然后選取 linearInput[1 << ((6 – j) % 8)] 做為明文第一個字節的掩碼。

為什么只選明文的第一個字節,以及其掩碼的選取這里可能看的不是很直觀,因為這里其實包含了兩部分。

我們需要回去注意到P盒。當這里j=0,即爆破第一個字節的密鑰時,我們選取的是密文的第1個字節,掩碼選的是第1個bit,那么這是從P盒輸入的哪個bit傳來的呢,從P盒我們可以看到這是P盒輸入的第一個字節的第2bit傳來的,那么P盒輸入的第2bit,實際上就是S盒輸出的第2bit,也就是S盒的輸出掩碼為0b01000000,也就是1 << 6。而這個 linearInput 存的就是輸出掩碼為某個值的使得線性逼近表達式偏差最大的輸入掩碼。

當我們選取密文第二個字節的時候,根據P盒,第二個字節第1個bit來自于明文第一個字節第3個bit,也就是0b00100000,也就是1 << 5,同理可推

所以這里只用選明文的第一個字節,密文不同字節的第一個比特,且輸入掩碼為 linearInput[1 << ((6 – j) % 8)]。

另外可能還有一個問題,S盒的輸入不是明文啊,應該是明文異或了第一個段密鑰。確實,但是試想一下,在線性逼近表達式的這個式子中,密鑰部分相互異或后,最后無非就是0或者1,而且由于密鑰固定,所以針對固定的輸入掩碼,這個值是固定的。對于返回結果沒有影響或者只是一個取反的效果。而我們是根據偏移來判斷的,所以正并不影響結果,key的具體的值在這里也就沒什么影響。

舉個例子,如果輸入掩碼是0b00110011,輸入掩碼是0b00001111,那么由于密鑰的存在,線性逼近表達式就是這么寫:X_2 ⊕ X_3 ⊕ X_6⊕ X_7 ⊕ K_2 ⊕ K_3⊕ K_6⊕ K_7 = Y_4⊕ Y_5 ⊕ Y_6 ⊕ Y_7

其中K_2 ⊕ K_3⊕ K_6⊕ K_7 這部分無非就是等于 0 或者 1,對于結果沒有影響或者只是一個取反的效果,對偏差則沒有影響。

爆破出第二部分key的每一個字節之后,我們就可以逆算法流程。由于S盒是雙射的,用明文、密文、第二部分key就可以去恢復第一部分的key,然后再寫一個解密函數就可以解決這道問題了,

來自出題人的exp:

import os, sys from binascii import hexlify, unhexlify from pwn import *SZ = 8 offset = [[0 for i in range(256)] for i in range(256)] #Sbox線性估計offset linearInput = [] sbox, sboxi, plain, cipher = [], [], [], [] enc_flag = None coef = [15, 11, 155, 119, 11, 99, 83, 249]def getData(ip, port):global enc_flag, sbox, sboxiio = remote(ip, port)sbox_str = io.recvline()sbox = eval(sbox_str)for i in range(256):sboxi.append(sbox.index(i))enc_flag = io.recvline().strip().decode("utf8")for i in range(10000):print("[+] Getting data...({}/10000)".format(i))pt = hexlify(os.urandom(8)).decode("utf8")plain.append(pt)io.sendline(pt)ct = io.recvline().strip().decode("utf8")print(ct,pt)cipher.append(ct)io.close()def doxor(l1, l2):return [x[0] ^ x[1] for x in zip(l1, l2)]# 線性層 def trans(blk):res = []for k in range(0, SZ, 8):cur = blk[k:k+8]cur = [(cur[i] * coef[i]) % 256 for i in range(8)]bits = [bin(x)[2:].rjust(8, '0') for x in cur]bits = bits[-1:] + bits[:-1]for i in range(8):res.append(int(''.join([x[i] for x in bits]), 2))return resdef bitxor(n, mask):bitlist = [int(x) for x in bin(n & mask)[2:]]return bitlist.count(1) % 2# Sbox線性估計 def linearSbox():global linearInput for i in range(256):si = sbox[i]for j in range(256):for k in range(256):a = bitxor(i, j) # 線性估計輸入b = bitxor(si, k) # 線性估計輸出 if a == b:offset[j][k] += 1for i in range(256):offset[i] = [abs(x - 128) / 256 for x in offset[i]]for linearOutput in range(256):cur = [x[linearOutput] for x in offset]linearInput.append(cur.index(max(cur)))def calcOffset(pt, ct, j, guessed_key): # 猜測第j段子密鑰pt = list(unhexlify(pt))ct = list(unhexlify(ct))ct[j] ^= guessed_keyct[j] = sbox[ct[j]] # sbox即為sboxi的逆ct[j] = (ct[j] * coef[j]) % 256u1 = bitxor(pt[0], linearInput[1 << ((6 - j) % 8)])u2 = bitxor(ct[j], 0b10000000)if u1 == u2:return Trueelse:return Falsedef linearAttack():key2 = []for i in range(8): # 第二輪子密鑰的第i段count = [0 for _ in range(256)]for guessed_key in range(256):print("[+] Cracking key...({}-{})".format(i, guessed_key))for j in range(10000):if calcOffset(plain[j], cipher[j], i, guessed_key) == True:count[guessed_key] += 1bias = [abs(x - 5000) / 10000 for x in count]key2.append(bias.index(max(bias)))return key2def getkey(key2):ct = list(unhexlify(cipher[0]))pt = list(unhexlify(plain[0]))cur = doxor(ct, key2)cur = [sbox[x] for x in cur]cur = trans(cur)cur = [sboxi[x] for x in cur]key = doxor(cur, pt) + key2return keydef decrypt_block(ct, key):cur = doxor(ct, key[SZ:])cur = [sbox[x] for x in cur]cur = trans(cur)cur = [sboxi[x] for x in cur]cur = doxor(cur, key[:SZ])return curdef decrypt(ct, key):pt = b''for i in range(0, len(ct), SZ * 2):block_ct = list(unhexlify(ct[i : i + SZ * 2]))block_pt = decrypt_block(block_ct, key)pt += bytes(block_pt)return ptif __name__ == "__main__":getData('node4.buuoj.cn', 27125)linearSbox()key2 = linearAttack()key = getkey(key2)print(key)flag = decrypt(enc_flag, key)print(flag)

那么對于這道簡單的兩輪分組密碼的線性分析就到此告一段落了,但對于分組密碼的學習不會到此為止,因為,還有高階差分、截斷差分、不可能差分……

最后

我有收集整理了一些學習的資料與工具,有想要得朋友,可以給個關注私我,發給你

【資料了解】

總結

以上是生活随笔為你收集整理的【入门建议收藏】密码学学习笔记之线性分析入门篇——EzSPN的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 免费大片黄在线观看 | aa视频网站 | 国产精品178页 | 成人精品视频99在线观看免费 | 射综合网 | 国产美女91呻吟求 | 龚玥菲三级露全乳视频 | 成人一区视频 | 超碰碰碰碰 | 四虎成人av| 亚洲一区二区日韩欧美 | 国产三区在线视频 | 在线观看高清av | 欧美日韩国产麻豆 | 天天草视频| 中文字幕五区 | 篠田优在线观看 | www.欧美成人 | av在线你懂的 | 日本一级大毛片a一 | 波多野结衣二区三区 | 国产在线激情 | 窝窝视频在线观看 | 思思久久精品 | 国产91欧美 | 中文字幕乱码一二三区 | 日韩视频一二三 | 成人手机在线视频 | 教练含着她的乳奶揉搓揉捏动态图 | 99在线视频免费观看 | 一区二区三区视频免费看 | 亚洲黄色免费网站 | 91看片网站 | 在线观看av国产一区二区 | 99精品国产一区 | 一二三四精品 | 国产一区一区 | 爽爽影院免费观看 | ass亚洲尤物裸体pics | www.好了av| 操人视频网站 | 欧美超碰在线 | 亚洲综合99 | 色网站免费观看 | 淫五月| 97超碰国产精品无码蜜芽 | 在线看成人av | 成人性做爰aaa片免费看不忠 | 99精品热| 中文字幕人妻熟女在线 | 福利视频不卡 | 天天天操操操 | 国产伦精品一区二区三区照片91 | 久久极品 | 色校园 | 日本不卡视频一区二区三区 | 777米奇影视第四色 五月丁香久久婷婷 | 久久首页 | 亚洲狠狠丁香婷婷综合久久久 | 女女h百合无遮涩涩漫画软件 | 天天激情站 | 少妇荡乳情欲办公室456视频 | 久久免费视频网站 | 色哟哟入口国产精品 | 日本高清久久 | 日韩成人高清在线 | 女18毛片| 91桃色在线观看 | 91干视频 | 日本精品二区 | 黄网www | 一区二区三区人妻 | 亚洲网站视频 | 黄色av电影网站 | 亚洲成人观看 | 久久久久久久极品内射 | 欧美高清性xxxxhd | 久久久不卡国产精品一区二区 | 最新av免费观看 | 久久七| 清冷学长被爆c躁到高潮失禁 | 午夜免费福利网站 | 男人操女人的网站 | 国产高清不卡一区 | 亚洲天堂男人天堂 | 无码人妻熟妇av又粗又大 | 久久理论 | 日日碰 | 黄色香蕉视频 | 国产成人精品一区二区三 | 精品国产乱码一区二 | 久久久久久久性 | 免费看毛片的网站 | 少妇av导航 | 欧州一区二区 | 一级黄色大片视频 | 天天在线免费视频 | 放几个免费的毛片出来看 | 久久精品免费观看 |