1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
import binascii
from flask import Flask, render_template, request, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired, Length, ValidationError
from aesgcmanalysis import xor, gmac, gcm_encrypt, nonce_reuse_recover_secrets, gf128_to_bytes
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
def hex_check(form, field):
if len(field.data) % 2 != 0:
raise ValidationError(f'not valid hex; must have even length')
if not all(c in '1234567890abcdef' for c in field.data):
raise ValidationError(f'not valid hex; contains non-hex character')
def not_equal_to(other):
def helper(form, field):
print(other, form['m1'], field)
if other not in form:
return
if form[other].data == field.data:
raise ValidationError(f'must not be equal to {other}')
return helper
class NonceReuseForm(FlaskForm):
key = StringField('key', validators=[DataRequired(), Length(min=32, max=32), hex_check])
nonce = StringField('nonce', validators=[DataRequired(), Length(min=24, max=24), hex_check])
m1 = StringField('first message', validators=[DataRequired(), Length(min=1, max=64)])
m2 = StringField('second message', validators=[DataRequired(), Length(min=1, max=64), not_equal_to('m1')])
mf = StringField('forged message', validators=[DataRequired(), Length(min=1, max=64)])
@app.route('/nonce-reuse', methods=['GET', 'POST'])
def nonce_reuse():
form = NonceReuseForm(meta={'csrf': False})
key = nonce = None
m1 = m2 = mf = c_forged = ''
macs = None
if form.is_submitted():
key, nonce, m1, m2, mf = form.key.data, form.nonce.data, form.m1.data, form.m2.data, form.mf.data
if form.validate():
skey = binascii.unhexlify(key)
snonce = binascii.unhexlify(nonce)
c_forged, macs = solve(skey, snonce, bytes(m1, 'utf-8'), bytes(m2, 'utf-8'), bytes(mf, 'utf-8'))
return render_template('nonce-reuse.html', form=form, key=key, nonce=nonce, m1=m1, m2=m2, mf=mf, c_forged=c_forged, macs=macs)
def solve(k, nonce, m1, m2, mf):
aad1 = aad2 = b""
c1, mac1 = gcm_encrypt(k, nonce, aad1, m1)
c2, mac2 = gcm_encrypt(k, nonce, aad2, m2)
possible_secrets = nonce_reuse_recover_secrets(nonce, aad1, aad2, c1, c2, mac1, mac2)
c_forged = xor(c1, xor(m1, mf))
aad_forged = b""
macs = []
for h, s in possible_secrets:
mac = gmac(h, s, aad_forged, c_forged)
macs.append((gf128_to_bytes(h), s, mac))
return c_forged, macs
|