Python 基于pycryptodome,實現(xiàn)對AES、DES、3DES、RSA、blowfish、RC4等常用加密算法的使用,文末附各種加密的源碼示例
(中文名:加密圓頂)pycryptodome是一個基于c實現(xiàn)的Python庫,它在2.x中支持2.7以上版本,或3.x中支持3.5以上版本的Python。
可以使用以下命令安裝它:
pip install pycryptodome
該庫支持以下特性
- 認證加密模式 Authenticated encryption modes (GCM, CCM, EAX, SIV, OCB)
- AES加密在英特爾上的加速 Accelerated AES on Intel platforms via AES-NI
- 一種jit編譯以提高運算速度 First class support for PyPy
- 橢圓曲線加密 Elliptic curves cryptography (NIST curves P-192, P-224, P-256, P-384 and P-521)
- 更好更緊湊的接口 Better and more compact API (nonce and iv attributes for ciphers, automatic generation of random nonces and IVs, simplified CTR cipher mode, and more)
- 各種hash SHA-3 hash algorithms (FIPS 202) and derived functions (NIST SP-800 185):
- SHAKE128 and SHA256 XOFs
- cSHAKE128 and cSHAKE256 XOFs
- KMAC128 and KMAC256
- TupleHash128 and TupleHash256
- 一個兄弟提出的算法 KangarooTwelve XOF (derived from Keccak)
- SHA散列算法 Truncated hash algorithms SHA-512/224 and SHA-512/256 (FIPS 180-4)
- 一種散列算法 BLAKE2b and BLAKE2s hash algorithms
- 一種流式加密 Salsa20 and ChaCha20/XChaCha20 stream ciphers
- Google所采用的一種新式加密算法 Poly1305 MAC
- 也是Google新算法 ChaCha20-Poly1305 and XChaCha20-Poly1305 authenticated ciphers
- 兩種加密算法以及HKDF的推導(dǎo)函數(shù) scrypt, bcrypt and HKDF derivation functions
- DSA加密 Deterministic (EC)DSA
- 密鑰保護容器 Password-protected PKCS#8 key containers
- 密鑰分享方法 Shamir’s Secret Sharing scheme
- 基于硬件的隨機數(shù) Random numbers get sourced directly from the OS (and not from a CSPRNG in userspace)
- 簡化的安裝流程并且支持windows系統(tǒng) Simplified install process, including better support for Windows
- RSA和DSA的密鑰生成器 Cleaner RSA and DSA key generation (largely based on FIPS 186-4)
- 源碼很漂亮 Major clean ups and simplification of the code base
更多文檔可參考【官網(wǎng)文檔】
概述
DES、3DES、AES都是對稱加密算法,即一個密鑰既用于加密也用于解密。而RSA是不對稱加密,需要使用公鑰和私鑰分別進行加解密。
對稱加密中通常需要三個參數(shù),分別是密鑰key
,向量iv
(一種初始的數(shù)值用于變更加密的走向以得到不同的加密結(jié)果)和密文content
。
不論是DES、3DES,或者還是AES的加密,常用的主要分為MODE_CBC、MODE_CFB、MODE_ECB、MODE_OFB這四種,其他的如EAX等這里不作演示。
四種分組加密模式簡介
MODE_ECB
ECB(Electronic Codebook)電碼本
- 是一種簡單加密
- 這種模式不需要傳入
iv
- 但是可能會被明文攻擊
- 密鑰需要傳入8位的bytes
MODE_CBC
(Cipher-block chaining)密碼分組鏈接
- 需要傳入8位bytes的
iv
- 密鑰需要傳入8位的bytes
- 它不容易被主動攻擊
- 安全性好于ECB
- 而且就算密文有損壞也還能繼續(xù)解密
- 適合加密大數(shù)據(jù)
- 廣泛用于SSL、IPSec中。
MODE_CFB
CFB(Cipher FeedBack) 密鑰反饋
- 需要傳入8位bytes的
iv
- 密鑰需要傳入8位的bytes
- 密文損壞了會出問題
MODE_OFB
(Output Feedback)輸出反饋模式
- 需要傳入8位bytes的
iv
- 密鑰需要傳入8位的bytes
- 密文損壞了會出問題
對稱加密
DES加密
from Crypto.Cipher import DES
def padding_to(raw: bytes, padding: int, max_length: int = None):
'''
部分加解密是需要補齊位數(shù)到指定padding的
'''
c = len(raw)/padding
block: int = int(c)
if block != c:
block += 1
result = raw.ljust(padding*block, b'\0')
if max_length:
result = result[0:max_length]
return result
def test_des(key,iv,content):
# MODE_CBC
e = DES.new(padding_to(key,8,8), DES.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES.new(padding_to(key,8,8), DES.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_CFB
e = DES.new(padding_to(key,8,8), DES.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES.new(padding_to(key,8,8), DES.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_ECB no need for iv
e = DES.new(padding_to(key,8,8), DES.MODE_ECB).encrypt(padding_to(content,8))
d = DES.new(padding_to(key,8,8), DES.MODE_ECB).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_OFB
e = DES.new(padding_to(key,8,8), DES.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES.new(padding_to(key,8,8), DES.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
config = {
"key": "SGTSerfend2022",
"iv": "1Ssecret1Ssecret1Ssecret"
}
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_des(key,iv,content)
DES全稱為Data Encryption Standard,即數(shù)據(jù)加密標(biāo)準(zhǔn),是一種使用密鑰加密的塊算法,1977年被美國聯(lián)邦政府的國家標(biāo)準(zhǔn)局確定為聯(lián)邦資料處理標(biāo)準(zhǔn)(FIPS),并授權(quán)在非密級政府通信中使用,隨后該算法在國際上廣泛流傳開來。需要注意的是,在某些文獻中,作為算法的DES稱為數(shù)據(jù)加密算法(Data Encryption Algorithm,DEA),已與作為標(biāo)準(zhǔn)的DES區(qū)分開來。
DES算法的入口參數(shù)有三個:Key、Data、Mode。其中Key為7個字節(jié)共56位,是DES算法的工作密鑰;Data為8個字節(jié)64位,是要被加密或被解密的數(shù)據(jù);Mode為DES的工作方式,有兩種:加密或解密。
密鑰需要是56位(實際使用64位),iv需要是64位
3DES加密
from Crypto.Cipher import DES3
def padding_to(raw: bytes, padding: int, max_length: int = None):
'''
部分加解密是需要補齊位數(shù)到指定padding的
'''
c = len(raw)/padding
block: int = int(c)
if block != c:
block += 1
result = raw.ljust(padding*block, b'\0')
if max_length:
result = result[0:max_length]
return result
def test_3des(key,iv,content):
# MODE_CBC
e = DES3.new(padding_to(key,24,24), DES3.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES3.new(padding_to(key,24,24), DES3.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_CFB
e = DES3.new(padding_to(key,24,24), DES3.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES3.new(padding_to(key,24,24), DES3.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_ECB no need for iv
e = DES3.new(padding_to(key,24,24), DES3.MODE_ECB).encrypt(padding_to(content,8))
d = DES3.new(padding_to(key,24,24), DES3.MODE_ECB).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_OFB
e = DES3.new(padding_to(key,24,24), DES3.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = DES3.new(padding_to(key,24,24), DES3.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
config = {
"key": "SGTSerfend2022",
"iv": "1Ssecret1Ssecret1Ssecret"
}
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_3des(key,iv,content)
3DES(或稱為Triple DES)是三重數(shù)據(jù)加密算法(TDEA,Triple Data Encryption Algorithm)塊密碼的通稱。它相當(dāng)于是對每個數(shù)據(jù)塊應(yīng)用三次DES加密算法。
由于計算機運算能力的增強,原版DES密碼的密鑰長度變得容易被暴力破解;3DES即是設(shè)計用來提供一種相對簡單的方法,即通過增加DES的密鑰長度來避免類似的攻擊,而不是設(shè)計一種全新的塊密碼算法。
密鑰需要是3 * 56 = 168位(實際使用192位),iv需要是64位
AES加密
from Crypto.Cipher import AES
def padding_to(raw: bytes, padding: int, max_length: int = None):
'''
部分加解密是需要補齊位數(shù)到指定padding的
'''
c = len(raw)/padding
block: int = int(c)
if block != c:
block += 1
result = raw.ljust(padding*block, b'\0')
if max_length:
result = result[0:max_length]
return result
def test_aes(key,iv,content):
# MODE_CBC
e = AES.new(padding_to(key,32,32), AES.MODE_CBC, padding_to(iv,16,16)).encrypt(padding_to(content,16))
d = AES.new(padding_to(key,32,32), AES.MODE_CBC, padding_to(iv,16,16)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_CFB
e = AES.new(padding_to(key,32,32), AES.MODE_CFB, padding_to(iv,16,16)).encrypt(padding_to(content,16))
d = AES.new(padding_to(key,32,32), AES.MODE_CFB, padding_to(iv,16,16)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_ECB no need for iv
e = AES.new(padding_to(key,32,32), AES.MODE_ECB).encrypt(padding_to(content,16))
d = AES.new(padding_to(key,32,32), AES.MODE_ECB).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_OFB
e = AES.new(padding_to(key,32,32), AES.MODE_OFB, padding_to(iv,16,16)).encrypt(padding_to(content,16))
d = AES.new(padding_to(key,32,32), AES.MODE_OFB, padding_to(iv,16,16)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
config = {
"key": "SGTSerfend2022",
"iv": "1Ssecret1Ssecret1Ssecret"
}
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_aes(key,iv,content)
這個標(biāo)準(zhǔn)用來替代原先的DES(Data Encryption Standard),已經(jīng)被多方分析且廣為全世界所使用。經(jīng)過五年的甄選流程,高級加密標(biāo)準(zhǔn)由美國國家標(biāo)準(zhǔn)與技術(shù)研究院 (NIST)于2001年11月26日發(fā)布于FIPS PUB 197,并在2002年5月26日成為有效的標(biāo)準(zhǔn)。2006年,高級加密標(biāo)準(zhǔn)已然成為對稱密鑰加密中最流行的算法之一 [1] 。
該算法為比利時密碼學(xué)家Joan Daemen和Vincent Rijmen所設(shè)計,結(jié)合兩位作者的名字,以Rijdael之名命之,投稿高級加密標(biāo)準(zhǔn)的甄選流程。(Rijdael的發(fā)音近于 “Rhine doll”。)
密鑰需要是32位,iv需要是16位
blowfish加密
from Crypto.Cipher import Blowfish
def padding_to(raw: bytes, padding: int, max_length: int = None):
'''
部分加解密是需要補齊位數(shù)到指定padding的
'''
c = len(raw)/padding
block: int = int(c)
if block != c:
block += 1
result = raw.ljust(padding*block, b'\0')
if max_length:
result = result[0:max_length]
return result
def test_Blowfish(key,iv,content):
# MODE_CBC
e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CBC, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CBC, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_CFB
e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_CFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_ECB no need for iv
e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_ECB).encrypt(padding_to(content,8))
d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_ECB).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
# MODE_OFB
e = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_OFB, padding_to(iv,8,8)).encrypt(padding_to(content,8))
d = Blowfish.new(padding_to(key,32,32), Blowfish.MODE_OFB, padding_to(iv,8,8)).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
config = {
"key": "SGTSerfend2022",
"iv": "1Ssecret1Ssecret1Ssecret"
}
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
iv = str(config['iv']).encode()
key = str(config['key']).encode()
test_Blowfish(key,iv,content)
Blowfish是一個對稱加密塊算法,由Bruce Schneider于1993年設(shè)計,現(xiàn)已應(yīng)用在多種加密產(chǎn)品。Blowfish能保證很好的加密速度,并且目前為止沒有發(fā)現(xiàn)有效地破解方法。目前為止AES比Blowfish有更廣的知名度。
密鑰需要是32-448位(或1-14個字符),iv需要是8位
RC4加密
from Crypto.Cipher import ARC4
def test_rc4(key: bytes, content: bytes):
e = ARC4.new(key).encrypt(content)
d = ARC4.new(key).decrypt(e)
print(f'e = {e}\nd = {d}\n\n')
assert d == content
if __name__ == '__main__':
config = {
"key": "SGTSerfend2022",
}
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
key = str(config['key']).encode()
test_rc4(key, content)
非對稱加密
RSA加密
整體測試示例代碼
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.Hash import SHA
def test_rsa(content):
rsa = RSA.generate(2048)
public_key = rsa.public_key().export_key()
private_key = rsa.export_key()
print(f'public_key: {public_key}\n\nprivate_key: {private_key}\n')
private_key = RSA.importKey(private_key)
public_key = RSA.importKey(public_key)
# sign a message
signer = PKCS1_signature.new(private_key)
digest = SHA.new()
digest.update(content)
sign = signer.sign(digest)
print(f'sign: {sign}\n')
# check sign for a message
verifier = PKCS1_signature.new(public_key)
digest = SHA.new()
digest.update(content)
sign_result = verifier.verify(digest,sign)
print(f'the message check sign result is :{sign_result}\n')
# encrypt rsa
cipher = PKCS1_cipher.new(public_key)
encrypt_text = cipher.encrypt(content)
print(f'encrypt_text: {encrypt_text}\n')
# decrypt rsa
cipher = PKCS1_cipher.new(private_key)
decrypt_text = cipher.decrypt(encrypt_text,b'')
print(f'decrypt_text: {decrypt_text}\n')
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
test_rsa(content)
RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當(dāng)時他們?nèi)硕荚诼槭±砉W(xué)院工作。RSA就是他們?nèi)诵帐祥_頭字母拼在一起組成的 [1] 。
RSA公開密鑰密碼體制的原理是:根據(jù)數(shù)論,尋求兩個大素數(shù)比較簡單,而將它們的乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰 [4] 。
產(chǎn)生密鑰對
可以是產(chǎn)生128 224 256 512 768 1024 2048等整數(shù)位數(shù)的密鑰
from Crypto.PublicKey import RSA
rsa = RSA.generate(2048)
public_key = rsa.public_key().export_key()
private_key = rsa.export_key()
print(f'public_key: {public_key}\n\nprivate_key: {private_key}\n')
private_key = RSA.importKey(private_key)
public_key = RSA.importKey(public_key)
加解密
利用產(chǎn)生的密鑰對,調(diào)用
RSA.importKey
分別導(dǎo)入公鑰和私鑰
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
# sign a message
signer = PKCS1_signature.new(private_key)
digest = SHA.new()
digest.update(content)
sign = signer.sign(digest)
print(f'sign: {sign}\n')
# check sign for a message
verifier = PKCS1_signature.new(public_key)
digest = SHA.new()
digest.update(content)
sign_result = verifier.verify(digest,sign)
print(f'the message check sign result is :{sign_result}\n')
校驗簽名(判斷數(shù)據(jù)是否是可靠的,沒有被篡改的)
使用SHA1等散列算法生成一個hash,用于生成簽名
from Crypto.Signature import PKCS1_v1_5 as PKCS1_signature
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
content = ('0123456789abcdefAAAAAAAAAA'*5).encode()
# encrypt rsa
cipher = PKCS1_cipher.new(public_key)
encrypt_text = cipher.encrypt(content)
print(f'encrypt_text: {encrypt_text}\n')
# decrypt rsa
cipher = PKCS1_cipher.new(private_key)
decrypt_text = cipher.decrypt(encrypt_text,b'')
print(f'decrypt_text: {decrypt_text}\n')
注意事項
padding_to
方法是因為有些key、iv和待加密的數(shù)據(jù)的長度是需要是一些數(shù)值的倍數(shù),不足長度的是需要補齊的,這里使用\0
對其進行補齊
max_length
是補齊后的最大長度,超過這個長度的數(shù)據(jù)將會被截取
def padding_to(raw: bytes, padding: int, max_length: int = None):
'''
部分加解密是需要補齊位數(shù)到指定padding的
'''
c = len(raw)/padding
block: int = int(c)
if block != c:
block += 1
result = raw.ljust(padding*block, b'\0')
if max_length:
result = result[0:max_length]
return result
其他文檔
- CTF逆向-常用的逆向工具 提取碼:pnbt
- B站教程中國某省隊CTF集訓(xùn)(逆向工程部分)
- 中國某省隊CTF集訓(xùn)(逆向工程部分)(已授權(quán))(一)
- 基礎(chǔ)加密方式例如
XXTEA
、Base64
換表 - Python庫
Z3
方程式、不定式等的約束求解
- 基礎(chǔ)的假跳轉(zhuǎn)花指令(臟字節(jié))
- 非自然程序流程
- 扁平化程序控制流
- OLLVM程序流程(虛擬機殼) 很難一般不考
- ida里面按
X
鍵跟蹤,尋找所有Ty
為w
的引用(即類型是寫入的),通常就是關(guān)鍵位置
- 中國某省隊CTF集訓(xùn)(逆向工程部分)(已授權(quán))(二)
- ollydb動調(diào)去殼,upx為例子
- python的逆向和自定義虛擬指令
- 使用pycdc 提取碼:dorr 解密python編譯的exe或者pyc
- 逐條去解析用py字典手動實現(xiàn)的指令調(diào)用
- C++編譯的程序的逆向
-
中國某省隊CTF集訓(xùn)(逆向工程部分)(已授權(quán))(三)
- 簡單模運算加密
- base58 尋找一下特別大的數(shù),這種數(shù)通常是算法的標(biāo)識,或者ida7.7版本以上自帶的
find crypt
插件ctrl+alt+f
- 常見的關(guān)鍵位置是有新的內(nèi)存分配的地方通常是關(guān)鍵地方,或者函數(shù)中間突然return的地方也是
- 迷宮題 注意繪制出來就好
- 動調(diào)題
- 注意觀察會執(zhí)行的反調(diào)試分支,例如出現(xiàn)
int 3
,需要跳過去
- 注意觀察會執(zhí)行的反調(diào)試分支,例如出現(xiàn)
- 基本知識
- 大小端序
更多CTF逆向題通用性做法和常用工具下載參考該博文內(nèi)容:CTF逆向Reverse題的玩法
相關(guān)逆向CTF題
-
Python
- Python反匯編方法 Python的pyc字節(jié)碼反編譯反匯編相關(guān)知識
- [CTF逆向-羊城杯 2020]Bytecode-WP-Python字節(jié)碼反編譯
-
遠程調(diào)試匯編
- CTF逆向-[watevrCTF 2019]Timeout-WP-遠程調(diào)試和修改程序當(dāng)前運行位置RIP
-
流程控制
- CTF逆向-Dig the way Interesting Pointer-通過棧溢出方式覆蓋變量以達到修改執(zhí)行流程的目的
-
逆向思維
- [CTF逆向-NPUCTF2020]Baby Obfuscation-逆向思維編寫腳本以及函數(shù)含義的邏輯理解
- [CTF逆向-MRCTF2020]EasyCpp - C++類型的逆向通用操作方法
- [CTF逆向-SUCTF2018]babyre-WP-cpp簡單迭代并按表輸出值的爆破
-
安卓
- [CTF逆向-網(wǎng)鼎杯 2020 青龍組]bang-安卓脫殼逆向:frida-dexdump導(dǎo)出得到源碼
-
虛擬機
- [CTF逆向-GWCTF 2019]babyvm-WP-虛機模擬流程反向編碼和z3約束求解器解方程工具的使用
- [CTF逆向-WMCTF2020]easy_re-WP_虛機-perl加載器截取
-
反調(diào)試和SMC
- [CTF逆向-SCTF2019]creakme-WP-基于AES加密算法下的保護:反調(diào)試及except_handler和SMC
-
加密
- Python 基于pycryptodome,實現(xiàn)對AES、DES、3DES、RSA等常用加密算法的使用,文末附各種加密的源碼示例
- [CTF逆向-FlareOn2]very_success-WP_rol循環(huán)位移加密
- base64換表
- [CTF逆向-CISCN2018]2ex-WP_mips-32架構(gòu)以及base64換表
- [CTF逆向-De1CTF2019]Re_Sign-簡單脫殼和base64換表編碼的深度算法跟蹤
-
花指令
- [CTF逆向-SCTF2019]babyre-WP_簡單去花指令和流程識別
-
流程混淆的扁平化處理
-
[CTF逆向-RoarCTF2019]polyre-WP_控制流扁平化去混淆idcpy去指令文章來源:http://www.zghlxwxcb.cn/news/detail-406465.html
-
CTF逆向-[SUCTF2019]hardcpp-使用優(yōu)化過的deflat.py處理混淆的控制流并將cpp的lambda解析得到實際處理邏輯文章來源地址http://www.zghlxwxcb.cn/news/detail-406465.html
-
到了這里,關(guān)于Python 基于pycryptodome,實現(xiàn)對AES、DES、3DES、RSA等常用加密算法的使用,文末附各種加密的源碼示例的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!