块密码 AES

跟着blog系统地学习一遍

ECB模式

image
ECB模式首先将明文分块 然后用相同的加密方式和密钥进行加密
因此相同的明文在不同次的加密后是一样的
注意: plaintext和key都必须是16的倍数

SWPU2020 ECB

chall.py

from Crypto.Cipher import AES
import os
BLOCKSIZE = 16
flag = os.environ['FLAG']


def pad(data):
        pad_len = BLOCKSIZE - (len(data) % BLOCKSIZE) if  len(data) % BLOCKSIZE != 0 else 0
        return data + chr(pad_len) * pad_len

def unpad(data):
        num = ord(data[-1])
        return data[:-num]


def enc(data,key):
	cipher = AES.new(key,AES.MODE_ECB)
	encrypt = cipher.encrypt(pad(data))
	return encrypt


def dec(data,key):
	try:
		cipher = AES.new(key,AES.MODE_ECB)
		encrypt = cipher.decrypt(data)
		return unpad(encrypt)
	except:
		exit()


def task():
        try:
                key = os.urandom(16)
                while True:
                        plaintext = raw_input("Amazing function: ").decode('hex')
                        yusa = plaintext+flag
                        print (enc(yusa,key).encode('hex'))
        except Exception as e:
                print (str(e))
                exit()
if __name__ == "__main__":
        task()

(...

CBC模式

image
与ECB不同的是这里每个明文组与前一个密文组xor后再进行ECB的加密模式
每个明文组长度要是128bit的整数倍

简单原理练习

from Crypto.Cipher import AES
import os
iv = os.urandom(16)
key = os.urandom(16)
my_aes = AES.new(key, AES.MODE_CBC, iv)
flag = open('flag.txt', 'rb').read()
flag += (16 - len(flag) % 16) * b'\x00'
c = my_aes.encrypt(flag)
print(list(c), list(iv), list(key))

'''
[137, 163, 60, 145, 236, 127, 76, 5, 212, 171, 46, 211, 161, 172, 41, 198, 117, 247, 140, 226, 169, 248, 208, 245, 214, 44, 180, 9, 170, 59, 205, 234] 

[138, 237, 90, 59, 60, 190, 103, 179, 137, 128, 10, 206, 237, 10, 183, 174] 

[170, 90, 227, 119, 123, 155, 185, 38, 148, 37, 159, 42, 221, 36, 2, 57]
'''

这里只需要将c,iv,key转成byte即可
同时注意AES.new(key,MODE,iv)参数的顺序

from Crypto.Cipher import AES
from Crypto.Util.number import *

c = [137, 163, 60, 145, 236, 127, 76, 5, 212, 171, 46, 211, 161, 172, 41, 198, 117, 247, 140, 226, 169, 248, 208, 245, 214, 44, 180, 9, 170, 59, 205, 234] 
iv = [138, 237, 90, 59, 60, 190, 103, 179, 137, 128, 10, 206, 237, 10, 183, 174] 
key = [170, 90, 227, 119, 123, 155, 185, 38, 148, 37, 159, 42, 221, 36, 2, 57]

C = b''
for i in c:
    C += long_to_bytes(i)

IV = b''
for i in iv:
    IV += long_to_bytes(i)

KEY = b''
for i in key:
    KEY += long_to_bytes(i)

aes = AES.new(KEY,AES.MODE_CBC,IV)
print(aes.decrypt(C).decode()) 
# flag{E@SY_AAAAaaaaa33333s}

[HNCTF 2022 WEEK3]AES

chall.py

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from os import urandom
from flag import flag

def cbc_encrypt(msg: bytes):
    msg = pad(msg, 16)
    msg = [msg[i:i+16] for i in range(0, len(msg), 16)]
    key = urandom(16)
    out = []
    for block in msg:
        cipher = AES.new(key, AES.MODE_ECB)
        next = cipher.encrypt(block)
        out.append(next)
        key = next
    out = b"".join(out)
    return key, out

def main():
    key, ct = cbc_encrypt(flag*3)
    # print(f"flag = {flag}")
    # print(f"key = {key}")
    print(f"ct = {ct}")

if __name__ == "__main__":
    main()
"""
ct = b'\x179\xb8l\x97\xbew\xc2\xd5f~\x8e\xdc\xf2\x9b\xabR\xa9a\xd2\xf4\xde\xd6|\xd1\x9f\xe9q\x1d\xfcm\xfbj\xe9\x9e\xab\xf5fL\xb3\xb5_\xa5\x16\x8e\x7f\x9fV`\x8b\x16\xa1\xa6)\x08\x97\x91\xbd3\x1d\xeb\\\x86\xa2\xd6\x94>\xf3\xfdt\xd9\x14\xf3\xfc\xe2\x02\xd6\xc4\xcfq"\x1a\x14~2]4\x9f\xc9\x88\xf8\x12\xb6\xa2\xd7\xec\x0b\x7f\xd4d\xdc\xc6\xb4]\x10u\xc6f\x97m\xccA\x82\x02\xa5gh\x85\x85Wz\xd9.\xff\x9bx\x99J\x0e\x86\x16\x90\xad\x1e\x17\x86\x95\xb8S\x17\xea\x93v\xd0'
"""

重点是要看到key = next这里
那么我们从最后往前推的话 每次的key就是前一密文块 这样除了初始key不知道没办法还原第一个密文块以外 其余的都能还原

from Crypto.Cipher import AES
from Crypto.Util.number import *


ct = b'\x179\xb8l\x97\xbew\xc2\xd5f~\x8e\xdc\xf2\x9b\xabR\xa9a\xd2\xf4\xde\xd6|\xd1\x9f\xe9q\x1d\xfcm\xfbj\xe9\x9e\xab\xf5fL\xb3\xb5_\xa5\x16\x8e\x7f\x9fV`\x8b\x16\xa1\xa6)\x08\x97\x91\xbd3\x1d\xeb\\\x86\xa2\xd6\x94>\xf3\xfdt\xd9\x14\xf3\xfc\xe2\x02\xd6\xc4\xcfq"\x1a\x14~2]4\x9f\xc9\x88\xf8\x12\xb6\xa2\xd7\xec\x0b\x7f\xd4d\xdc\xc6\xb4]\x10u\xc6f\x97m\xccA\x82\x02\xa5gh\x85\x85Wz\xd9.\xff\x9bx\x99J\x0e\x86\x16\x90\xad\x1e\x17\x86\x95\xb8S\x17\xea\x93v\xd0'
ct = [ct[i:i+16] for i in range(0,len(ct),16)]
flag = ''
for i in range(len(ct)-1,0,-1):
    key = ct[i-1]
    aes = AES.new(key,AES.MODE_ECB)
    flag = aes.decrypt(ct[i]).decode()+flag
print(flag)
# 45e4-11ed-bba0-28d0eab06969}NSSCTF{07104f28-45e4-11ed-bba0-28d0eab06969}NSSCTF{07104f28-45e4-11ed-bba0-28d0eab06969}

安洵杯2020 easyaes

chall.py

#!/usr/bin/python
from Crypto.Cipher import AES
import binascii
from Crypto.Util.number import bytes_to_long
from flag import flag
from key import key

iv = flag.strip(b'd0g3{').strip(b'}')

LENGTH = len(key)
assert LENGTH == 16

hint = os.urandom(4) * 8
print(bytes_to_long(hint)^bytes_to_long(key))

msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'

def encrypto(message):
    aes = AES.new(key,AES.MODE_CBC,iv)
    return aes.encrypt(message)

print(binascii.hexlify(encrypto(msg))[-32:])

'''
56631233292325412205528754798133970783633216936302049893130220461139160682777
b'3c976c92aff4095a23e885b195077b66'
'''

思路就是先还原key 再根据已经告诉的最后密文块向前还原IV

from Crypto.Cipher import AES
import binascii
from Crypto.Util.number import *
from pwn import xor

hint = 56631233292325412205528754798133970783633216936302049893130220461139160682777
enc = b'3c976c92aff4095a23e885b195077b66'
enc = binascii.unhexlify(enc)

# 先恢复key
hint = long_to_bytes(hint)
print(hint)
key = bytes_to_long(hint[16:])^bytes_to_long(hint[:16])
print(long_to_bytes(key))
key = b'd0g3{welcomeyou}'
msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'
msg = [msg[i:i+16] for i in range(0,len(msg),16)]

def decrypt(msg):
    ebc = AES.new(key,AES.MODE_ECB)
    return ebc.decrypt(msg)

c3 = xor(decrypt(enc),msg[3])
c2 = xor(decrypt(c3),msg[2])
c1 = xor(decrypt(c2),msg[1])
c0 = xor(decrypt(c1),msg[0])
iv = c0
print(b'd0g3{'+iv+b'}')

本质是要弄清楚CBC比ECB就多了层xor(ct[i-1],pt[i])然后就跟ECB一模一样
还有关于hexify
这里不清楚到底告诉的几个密文块可以输出len(binascii.unhexlify(enc))发现长度为16 刚好128bit 所以告诉的是最后一个密文块

CTR模式

image
在CTR模式中关键是这个计数器
它是由IV经过一定规则生成的一段数据 长度与数据块相等

COUNTER通过ECB加密后得到一个COUNTER的密文,再和明文1进行异或得到密文1。在加密结束后COUNTER的值加1,然后再次用ECB加密,依次加密
其实就是在ECB模式基础上进一步复杂化xor

例题

from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util import Counter
from hashlib import sha256
from secret import flag

import os


def padding(msg):
    return msg + os.urandom(16 - len(msg) % 16)


msg = b"where is the flag? Key in my Heart/Counter!!!!"
key = b"I w0nder how????"

assert len(msg) == 46
assert len(key) == 16

enc_key = os.urandom(16)
initial_value = bytes_to_long(enc_key)
hash = sha256(str(initial_value).encode()).hexdigest()

aes = AES.new(enc_key, AES.MODE_ECB)
enc_flag = aes.encrypt(padding(flag))

ctr = Counter.new(AES.block_size * 8, initial_value=initial_value)
aes = AES.new(key, counter=ctr, mode=AES.MODE_CTR)
enc = aes.encrypt(msg)

print("enc = {}".format(enc[-16:]))
print("enc_flag = {}".format(enc_flag))
print("hash = {}".format(hash))

'''
enc = b'\xbe\x9bd\xc6\xd4=\x8c\xe4\x95bi\xbc\xe01\x0e\xb8'
enc_flag = b'\xb2\x97\x83\x1dB\x13\x9b\xc2\x97\x9a\xa6+M\x19\xd74\xd2-\xc0\xb6\xba\xe8ZE\x0b:\x14\xed\xec!\xa1\x92\xdfZ\xb0\xbd\xb4M\xb1\x14\xea\xd8\xee\xbf\x83\x16g\xfa'
hash = efb07225b3f1993113e104757210261083c79de50f577b3f0564368ee7b25eeb
'''

这里要先弄清楚CTR的工作流程
由于这里msg是46bytes 会被分成3组 : 16,16,14
由原理图 CTR->CTR+1->CTR+2 也就是说最后的CTR和初始CTR差值为2
那么我们就先想办法获得LAST_CTR
由原理图: 最后一组14bytes(pad后16bytes)与(CTR+2)xor后得到了enc
那么我们将msg[-14:]与enc[-14:] xor就能得到LAST_CTR的前14bytes
剩下的2bytes爆破一下 利用hash进行check即可
注意aes = AES.new(key, counter=ctr, mode=AES.MODE_CTR)这里生成的时候用的key 所以CTR在INITIAL_VALUE的基础上以这个key作了一次ECB

from Crypto.Cipher import AES
from tqdm import *
import binascii
from Crypto.Util.number import *
from pwn import xor
from hashlib import *

msg = b"where is the flag? Key in my Heart/Counter!!!!"
key = b"I w0nder how????"
enc = b'\xbe\x9bd\xc6\xd4=\x8c\xe4\x95bi\xbc\xe01\x0e\xb8'
enc_flag = b'\xb2\x97\x83\x1dB\x13\x9b\xc2\x97\x9a\xa6+M\x19\xd74\xd2-\xc0\xb6\xba\xe8ZE\x0b:\x14\xed\xec!\xa1\x92\xdfZ\xb0\xbd\xb4M\xb1\x14\xea\xd8\xee\xbf\x83\x16g\xfa'
hash = 'efb07225b3f1993113e104757210261083c79de50f577b3f0564368ee7b25eeb'

last_CTR = xor(msg[-14:],enc[-14:]) # 得到最后CTR的前14个字节

# 爆破剩下两个字节

for bit in trange(2**8,2**16):
    CTR = last_CTR + long_to_bytes(bit)
    ecb = AES.new(key,AES.MODE_ECB)
    CTR = ecb.decrypt(CTR)
    INIT_CTR = bytes_to_long(CTR)-2
    _hash = sha256(str(INIT_CTR).encode()).hexdigest()
    if hash == _hash:
        enc_key = long_to_bytes(INIT_CTR)
        aes = AES.new(enc_key,AES.MODE_ECB)
        print(aes.decrypt(enc_flag))

image

posted @ 2023-11-11 16:29  N0zoM1z0  阅读(138)  评论(0编辑  收藏  举报