Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
jvdsn
GitHub Repository: jvdsn/crypto-attacks
Path: blob/master/test/test_cbc_and_cbc_mac.py
2587 views
1
import os
2
import sys
3
from random import randbytes
4
from unittest import TestCase
5
6
from Crypto.Cipher import AES
7
from Crypto.Util.Padding import pad
8
from Crypto.Util.Padding import unpad
9
10
path = os.path.dirname(os.path.dirname(os.path.realpath(os.path.abspath(__file__))))
11
if sys.path[1] != path:
12
sys.path.insert(1, path)
13
14
from attacks.cbc_and_cbc_mac import eam_key_reuse
15
from attacks.cbc_and_cbc_mac import etm_key_reuse
16
from attacks.cbc_and_cbc_mac import mte_key_reuse
17
18
19
class TestCBCAndCBCMAC(TestCase):
20
def _encrypt_eam(self, key, p):
21
# Notice how the key is used for encryption and authentication...
22
p = pad(p, 16)
23
iv = randbytes(16)
24
c = AES.new(key, AES.MODE_CBC, iv).encrypt(p)
25
# Encrypt-and-MAC using CBC-MAC to prevent chosen-ciphertext attacks.
26
t = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(p)[-16:]
27
return iv, c, t
28
29
def _decrypt_eam(self, key, iv, c, t):
30
p = AES.new(key, AES.MODE_CBC, iv).decrypt(c)
31
t_ = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(p)[-16:]
32
# Check the MAC to be sure the message isn't forged.
33
if t != t_:
34
return None
35
36
return unpad(p, 16)
37
38
def _encrypt_etm(self, key, p):
39
# Notice how the key is used for encryption and authentication...
40
p = pad(p, 16)
41
iv = randbytes(16)
42
c = AES.new(key, AES.MODE_CBC, iv).encrypt(p)
43
# Encrypt-then-MAC using CBC-MAC to prevent chosen-ciphertext attacks.
44
t = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(iv + c)[-16:]
45
return iv, c, t
46
47
def _decrypt_etm(self, key, iv, c, t):
48
t_ = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(iv + c)[-16:]
49
# Check the MAC to be sure the message isn't forged.
50
if t != t_:
51
return None
52
53
return unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(c), 16)
54
55
def _encrypted_zeroes(self, key):
56
return AES.new(key, AES.MODE_ECB).encrypt(bytes(16))
57
58
def _encrypt_mte(self, key, p):
59
# Notice how the key is used for encryption and authentication...
60
p = pad(p, 16)
61
iv = randbytes(16)
62
# MAC-then-encrypt using CBC-MAC to prevent chosen-ciphertext attacks.
63
t = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(p)[-16:]
64
c = AES.new(key, AES.MODE_CBC, iv).encrypt(p + t)
65
return iv, c
66
67
def _decrypt_mte(self, key, iv, c):
68
d = AES.new(key, AES.MODE_CBC, iv).decrypt(c)
69
p = d[:-16]
70
t = d[-16:]
71
t_ = AES.new(key, AES.MODE_CBC, bytes(16)).encrypt(p)[-16:]
72
# Check the MAC to be sure the message isn't forged.
73
if t != t_:
74
return None
75
76
return unpad(p, 16)
77
78
def test_eam_key_reuse(self):
79
key = randbytes(16)
80
for i in range(16):
81
p = randbytes(i + 1)
82
iv, c, t = self._encrypt_eam(key, p)
83
p_ = eam_key_reuse.attack(lambda iv, c, t: self._decrypt_eam(key, iv, c, t), iv, c, t)
84
self.assertEqual(p, p_)
85
86
def test_etm_key_reuse(self):
87
key = randbytes(16)
88
for i in range(16):
89
p = randbytes(i + 1)
90
iv, c, t = self._encrypt_etm(key, p)
91
p_ = etm_key_reuse.attack(lambda p: self._encrypt_etm(key, p), lambda iv, c, t: self._decrypt_etm(key, iv, c, t), iv, c, t)
92
self.assertEqual(p, p_)
93
94
def test_mte_key_reuse(self):
95
key = randbytes(16)
96
encrypted_zeroes = self._encrypted_zeroes(key)
97
for i in range(16):
98
p = randbytes(i + 1)
99
iv, c = self._encrypt_mte(key, p)
100
p_ = mte_key_reuse.attack(lambda iv, c: self._decrypt_mte(key, iv, c), iv, c, encrypted_zeroes)
101
self.assertEqual(p, p_)
102
103