-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathgen-vecs.sage
122 lines (93 loc) · 3.34 KB
/
gen-vecs.sage
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# sage -pip install pycryptodome
# from Crypto.Hash import SHA256, HMAC
from struct import *
# P-256 constants and helper functions
px = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
py = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
p256 = 2^256 - 2^224 + 2^192 + 2^96 - 1
b256 = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
FF = GF(p256)
EC = EllipticCurve([FF(p256 - 3), FF(b256)])
P = EC(FF(px), FF(py))
mcomp = 0x02886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f
ncomp = 0x03d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49
mx = 0x886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f
nx = 0xd8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b49
my = 0x5ff355163e43ce224e0b0e65ff02ac8e5c7be09419c785e0ca547d55a12e2d20
ny = 0x07d60aa6bfade45008a636337f5168c64d9bd36034808cd564490b1e656edbe7
M = EC(FF(mx), FF(my))
N = EC(FF(nx), FF(ny))
def wrap_print(arg, *args):
line_length = 70
string = arg + " " + " ".join(args)
for hunk in (string[0+i:line_length+i] for i in range(0, len(string), line_length)):
if hunk and len(hunk.strip()) > 0:
print(hunk)
def print_integer(name, x):
wrap_print(name + ' = 0x' + format(x, 'x').zfill(64))
def encode_point(point):
return '04' + format(int(point[0]), 'x').zfill(64) + format(int(point[1]), 'x').zfill(64)
def print_point(name, point):
wrap_print(name + ' = 0x' + encode_point(point))
def pack_point(point):
return pack_len(bytes.fromhex(encode_point(point)))
def pack_len(data):
return pack('<Q', len(data)) + data
def pack_string(s):
return pack_len(s.encode('utf-8'))
def hkdf(ikm, info):
return HKDF(ikm, 32, None, SHA256, 1, context=info)
def hmac(k, m):
h = HMAC.new(k, digestmod=SHA256)
h.update(m)
return h.hexdigest()
def derive_keys(TT):
# Ka || Ke = Hash(TT)
sk = SHA256.new(data=TT).digest()
Ka = sk[:16]
Ke = sk[16:]
wrap_print('Ka = 0x' + Ka.hex())
wrap_print('Ke = 0x' + Ke.hex())
# KDF(nil, Ka, "ConfirmationKeys") = KcA || KcB
ck = hkdf(Ka, b'ConfirmationKeys')
KcA = ck[:16]
KcB = ck[16:]
wrap_print('KcA = 0x' + KcA.hex())
wrap_print('KcB = 0x' + KcB.hex())
return Ke, KcA, KcB
def spake2(A, B):
print("spake2: A='%s', B='%s'"%(A,B))
w = int(FF.random_element())
# Print w
print_integer('w', w)
# A generates key share S
x = int(FF.random_element())
print_integer('x', x)
S = int(x) * P + w * M
print_point('S', S)
# B generates key share T
y = int(FF.random_element())
print_integer('y', y)
T = int(y) * P + w * N
print_point('T', T)
# A computes shared key K
K = x * (T - w * N)
print_point('K', K)
# B computes shared keys K
assert K == y * (S-w*M)
TT = pack_string(A)
TT += pack_string(B)
TT += pack_point(S)
TT += pack_point(T)
TT += pack_point(K)
TT += pack_len(bytes.fromhex(format(w, '064x')))
wrap_print('TT = 0x' + TT.hex())
# Derive key schedule
# Ke, KcA, KcB = derive_keys(TT)
# MAC = HMAC(KcA/KcB, Y/X)
# wrap_print('HMAC(KcA, Y) = 0x' + hmac(KcA, bytes.fromhex(TT)))
# wrap_print('HMAC(KcB, X) = 0x' + hmac(KcB, bytes.fromhex(TT)))
spake2(A='server', B='client')
spake2(A='', B='client')
spake2(A='server', B='')
spake2(A='', B='')