文章目录
- CTR(Counter mode,CTR)计数器模式
- 题目一
- 题目描述:
- 题目分析:
- 浅记一下
CTR(Counter mode,CTR)计数器模式
原理: CTR将块密码变为流密码。它通过递增一个加密计数器以产生连续的密钥流,其中,计数器可以是任意保证长时间不产生重复输出的函数。AES是一种分组加密模式,其中CTR(计数模式)是其中一种工作模式。
加密原理:用密钥对输入的计数器加密,然后同明文异或得到密文。
解密原理:用密钥对输入计数器加密,然后同密文异或得到明文。
⋆ ⋆ ⋆ 从图中可以看出对计数器的加密 ( 即从 C o u n t e r ⇒ K 1 的过程 ) 采用的是 A E S − E C B 加密模式 \star\star\star 从图中可以看出对计数器的加密(即从Counter\Rightarrow K1的过程)采用的是AES-ECB加密模式 ⋆⋆⋆从图中可以看出对计数器的加密(即从Counter⇒K1的过程)采用的是AES−ECB加密模式
♠
C
T
R
模式不需要
p
a
d
d
i
n
g
,故其加密后的密文长度是可知的
\spadesuit CTR模式不需要padding,故其加密后的密文长度是可知的
♠CTR模式不需要padding,故其加密后的密文长度是可知的
♠
从图中可以看出对计数器的加密
(
即从
C
o
u
n
t
e
r
⇒
K
1
的过程
)
采用的是
A
E
S
−
E
C
B
加密模式
\spadesuit 从图中可以看出对计数器的加密(即从Counter\Rightarrow K1的过程)采用的是AES-ECB加密模式
♠从图中可以看出对计数器的加密(即从Counter⇒K1的过程)采用的是AES−ECB加密模式
举个生成的例子来理解
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)
- AES.block_size 用于表示 AES 算法的分组大小(以字节为单位)的常量值。
- AES 算法支持三种分组大小:16 字节(128 bits)、24 字节(192 bits)和 32 字节(bits 位)。分组大小的选择取决于所使用的 AES 密钥长度
- 无指定情况下AES.block_size 的值为 16,表示使用 128 bits的分组大小
- initial_value用于表示计数器的初始值,每使用一次,计数器值加1,确保每次不一样,从而不易被攻击,例如:
initial_value:b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08’
Counter value1: b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08’
Counter value2: b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\t’
Counter value3: b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\n’
Counter value4: b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x0b’
Counter value5: b’\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x0c’
…
以此类推,每次加1(转为long型加1,再转为bytes型)
题目一
题目描述:
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
'''
题目分析:
由流程可知,明文msg和密文enc_flag已知,那么两者异或就能得到K3(分三组:16 16 14,不需填充)
但此K3非彼K3,此K3是14字节,实际上K3是16字节,所以要得到真正的K3得进行填充
注意这里是往后填充,不是往前填充
(从流程图确实很容易想到是往前填充。但此处是CRT库里面的自己实现的,类似于规定一样,测试出来的数据确实也表明是往后填充,我想这应该也就是所说的
C
T
R
模式不需要
p
a
d
d
i
n
g
CTR模式不需要padding
CTR模式不需要padding的原因吧)
在末尾爆破两字节得到真正的K3,然后-2即可得到初始Counter,即initial_value
initial_value出来了,那么flag差不多也就出来了
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util import Counter
from hashlib import sha256
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'
a = msg[32:]
b = enc[2:]
enc_Counter1 = bytes(a[i] ^ b[i] for i in range(14))
for i in range(256):
for j in range(256):
enc_Counter2 = enc_Counter1 + bytes([i]) + bytes([j])
aes = AES.new(key,AES.MODE_ECB)
Counter = aes.decrypt(enc_Counter2)
initial_value = bytes_to_long(Counter) - 2
if hash == sha256(str(initial_value).encode()).hexdigest():
enc_key = long_to_bytes(initial_value)
aes = AES.new(enc_key,AES.MODE_ECB)
flag = aes.decrypt(enc_flag)
print(flag)
break
# flag{9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d}
浅记一下
学到了AES-CTR加密模式,往后填充哪里确实需要我们记住
还有,当时看了很多资料,发现大家都是这样说的(引用一下):
计数器的生成方法
每次加密时都会生成一个不同的值(nonce)来作为计数器的初始值。当分组长度为128比特(16字节)时,计数器的初始值可能是像下面这样的形式
其中前8个字节为nonce(随机数),这个值在每次加密时必须都是不同的,后8个字节为分组序号,这个部分是会逐次累加的。在加密的过程中,计数器的值会产生如下变化:
这应该是初始值只有8字节的时候吧
如果初始值就是16字节,那Counter value1的值就是初始值,之后的Counter value便是每次在初始值后加1,也就没有所谓的后8字节为分组序号组这一说法,就像上面讲原理是所介绍的那个例子。我理解的大致是这样,因为遇到的题目确实是按这个想法才能解。
学艺不精,还有待提升,继续加油!