ctf密碼學常用python庫


1. pyCryptodome庫

pip3 install pyCryptodome -i https://pypi.douban.com/simple

這個庫是實現各種算法和協議的密碼模塊的集合,包含Cipher,Hash,Protocol,PublicKey,Signature,Util這些子包;

1.1. Cipher子包

實現了分組加密(AES,DES,DES3,CAST,Blowfish,RC2),流加密(RC4,XOR)與公鑰加密(RSA PKCS#1與PKCS#1 OAEP,這兩個區別在於加密前對數據的填充不同);如下是文檔給出的例子:

from Crypto.Cipher import AES
from Crypto import Random
key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')
print msg.encode('hex')

有時在解RSA的題時,已經知道了密鑰,解出來的flag卻是亂碼,也許是加了一些填充如OAEP,PKCS#1導致的;這時就需要使用對應的秘鑰解密;如下是一個PKCS#1填充的例子,加密的明文(字節)長度必須嚴格小於密鑰(字節)長度-11

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from gmpy2 import invert
from base64 import b64decode

cip='bT633yPu4dOHEL66eKCHjg6cZb09CElt2mSSQZkRDHk='

n=87924348264132406875276140514499937145050893665602592992418171647042491658461L
e=65537L
#http://factordb.com/
p=275127860351348928173285174381581152299L
q=319576316814478949870590164193048041239L
phi=(p-1)*(q-1)
d=invert(e,phi)

privkey=RSA.construct((n,e,long(d),p,q))

#原生RSA
print privkey.decrypt(b64decode(cip))

#PKCS#1填充
key= PKCS1_v1_5.new(privkey)
print key.decrypt(b64decode(cip),'')

再舉個OAEP填充的例子,加密的明文(字節)長度必須嚴格小於密鑰(字節)長度減去41;你可以試一下在下面代碼中的明文中多加一個字符運行就會報錯。

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from base64 import b64encode,b64decode

rsa_key=RSA.generate(1024)
key=PKCS1_OAEP.new(rsa_key)
cip=b64encode(key.encrypt('PCTF{256b_i5_m3dium}PCTF{256b_i5_m3dium}PCTF{256b_i5_m3dium}PCTF{256b_i5_m3dium}abcdef'))
print cip

msg=key.decrypt(b64decode(cip))
print msg

1.2. Hash子包

實現了哈希算法(MD2,MD4,MD5,RIPEMD,SHA,SHA224,SHA256,SHA384,SHA512,HMAC,hashalgo);如下是文檔給出的例子:

from Crypto.Hash import MD2
h = MD2.new()
h.update(b'Hello')
print h.hexdigest()

但是沒有實現SHA1,要使用SHA1,需要導入hashlib庫,正好驗證一下Google之前給出的求得兩個 sha1 值一樣的pdf對:https://shattered.io/

from hashlib import sha1

with open('shattered-1.pdf','rb') as f1:
    da1=f1.read()
with open('shattered-2.pdf','rb') as f2:
    da2=f2.read()

print sha1(da1).hexdigest()
print sha1(da2).hexdigest()

1.3. PublicKey子包

實現了公鑰加密和簽名算法(RSA,DSA,ElGamal);文檔給出的例子:

from Crypto.PublicKey import RSA
key0 = RSA.generate(2048)
with open('mykey.pem','w') as f:
    f.write(key0.exportKey('PEM'))

with open('mykey.pem','r') as g:
    key = RSA.importKey(g.read())

1.4. Util子包

實現了各種有用的模塊和功能(Util.number:數論函數,Util.randpool:隨機數生成,Util.RFC1751:在128位鍵和可讀的字串之間進行轉換,Util.asn1:對ASN.1 DER編碼的最小支持);自己寫個例子如下:

from Crypto.Util import number
s='this is a demo'
#字節轉換為long型整數
ls=number.bytes_to_long(s)

bits=8*len(s)
#生成長度為bits的素數
gp=number.getPrime(bits)

#生成長度小於bits的隨機數
gri=number.getRandomInteger(bits)
 
#生成長度為bits的隨機數
grnbi=number.getRandomNBitInteger(bits)
 
#生成長度不超過bits的隨機數
grn=number.getRandomNumber(bits)
 
#生成grn與2*grn之間的隨機數
grr=number.getRandomRange(grn,2*grn)

#生成強的素數(gsp-1,gsp+1均至少具有一個大的素因子)
gsp=number.getStrongPrime(1024)

#計算gri在模grn下的逆
iin=number.inverse(gri,grn)

#判斷iin是否為素數
ip=number.isPrime(iin)

#long型整數轉換為字節
tb=number.long_to_bytes(ls)

由於這個庫很多函數都很有用,因此我們直接使用

from Crypto.Util.number import *

來導入這個包的所有函數。

2. pwntools庫

pip3 install pwntools -i https://pypi.douban.com/simple

這個庫內容很多,只介紹比賽中用到的。

2.1. mbruteforce函數

多線程窮舉函數,詳細定義如下:mbruteforce(func, alphabet, length, method='upto', start=None, threads=None),其中,

  • func輸入參數為字符串,輸出布爾值,mbruteforce窮舉直到func輸出True;
  • alphabet為組成輸入參數字符串的字符集合;
  • length指定輸入參數字符串的長度上界;
  • method默認為'upto',指定窮舉的字符串長度從1增大到length;另外兩個選項為'fixed'、'downfrom',fixed'指定窮舉的字符串長度僅為ength,'downfrom'指定窮舉的字符串長度從length減小到1;
  • start=(N,i),就是把搜索空間分成N塊從第i塊開始窮舉;默認為(1,1)
  • threads指定窮舉時的線程數,默認值是內核的數量;

舉個例子:

from pwn import pwnlib
from pwnlib.util.iters import mbruteforce
mbruteforce(lambda x: x == 'hello','helo',5,method='fixed')

2.2. remote類

用來與服務器交互;常用函數的用法注釋到如下腳本中。

from pwn import pwnlib
from pwnlib.tubes.remote import remote

#創建到遠程主機的TCP或udp連接,主機為cn.bing.com,連接主機的端口為443
#ssl=True代表用SSL包裝套接字
r=remote('cn.bing.com',443,ssl=True)

#向主機發送數據,只不過數據只能是一行
r.sendline('GET /')

#向主機發送數據,數據可以是多行
r.send(b'\r\n\r\n')

##上面兩行代碼等價於r.send(b'GET /\r\n\r\n')

#從主機接收4個字節的數據
re=r.recvn(4)
print re

#從主機一直接收數據直到'Please'出現
re=r.recvuntil('Please')
print re

#從主機一直接收數據,最多接收4096字節
re=r.recv()
print re

#關閉連接
r.close()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM