20
20
Implements the Secure Remote Password (SRP) algorithm. More information can be found on
21
21
https://tools.ietf.org/html/rfc5054. See HomeKit spec page 36 for adjustments imposed by Apple.
22
22
"""
23
-
24
23
import crypt
25
- import gmpy2
24
+ import math
26
25
import hashlib
27
-
28
- import six
29
- import binascii
26
+ import sys
30
27
31
28
32
29
class Srp :
33
30
def __init__ (self ):
34
31
# generator as defined by 3072bit group of RFC 5054
35
- self .g = gmpy2 . mpz ( int (six . b ( '5' ) , 16 ) )
32
+ self .g = int (b '5' , 16 )
36
33
# modulus as defined by 3072bit group of RFC 5054
37
- self .n = gmpy2 . mpz ( int (six . b ( '''\
34
+ self .n = int (b '''\
38
35
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
39
36
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
40
37
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
@@ -48,7 +45,7 @@ def __init__(self):
48
45
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
49
46
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
50
47
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
51
- E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF''') , 16 ) )
48
+ E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF''' , 16 )
52
49
# HomeKit requires SHA-512 (See page 36)
53
50
self .h = hashlib .sha512
54
51
self .A = None
@@ -62,21 +59,22 @@ def generate_private_key():
62
59
"""
63
60
Static function to generate a 16 byte random key.
64
61
65
- :return: the key as gmpy2 multi-precision integer
62
+ :return: the key as an integer
66
63
"""
67
- return gmpy2 .mpz (int (binascii .hexlify (crypt .mksalt (crypt .METHOD_SHA512 )[3 :].encode ()), 16 ))
64
+ private_key = crypt .mksalt (crypt .METHOD_SHA512 )[3 :].encode ()
65
+ return int .from_bytes (private_key , "big" )
68
66
69
- def _calculate_k (self ) -> gmpy2 . mpz :
67
+ def _calculate_k (self ) -> int :
70
68
# calculate k (see https://tools.ietf.org/html/rfc5054#section-2.5.3)
71
69
hash_instance = self .h ()
72
70
n = Srp .to_byte_array (self .n )
73
71
g = bytearray .fromhex ((383 * '00' + '05' )) # 383 * b'0' + '5'.encode()
74
72
hash_instance .update (n )
75
73
hash_instance .update (g )
76
- k = gmpy2 . mpz ( int ( binascii . hexlify (hash_instance .digest ()), 16 ) )
74
+ k = int . from_bytes (hash_instance .digest (), "big" )
77
75
return k
78
76
79
- def _calculate_u (self ) -> gmpy2 . mpz :
77
+ def _calculate_u (self ) -> int :
80
78
if self .A is None :
81
79
raise RuntimeError ('Client\' s public key is missing' )
82
80
if self .B is None :
@@ -86,21 +84,18 @@ def _calculate_u(self) -> gmpy2.mpz:
86
84
B_b = Srp .to_byte_array (self .B )
87
85
hash_instance .update (A_b )
88
86
hash_instance .update (B_b )
89
- u = gmpy2 . mpz ( int ( binascii . hexlify (hash_instance .digest ()), 16 ) )
87
+ u = int . from_bytes (hash_instance .digest (), "big" )
90
88
return u
91
89
92
90
def get_session_key (self ) -> int :
93
91
hash_instance = self .h ()
94
92
hash_instance .update (Srp .to_byte_array (self .get_shared_secret ()))
95
- hash_value = int ( binascii . hexlify (hash_instance .digest ()), 16 )
93
+ hash_value = int . from_bytes (hash_instance .digest (), "big" )
96
94
return hash_value
97
95
98
96
@staticmethod
99
97
def to_byte_array (num : int ) -> bytearray :
100
- h = gmpy2 .digits (num , 16 )
101
- if len (h ) % 2 == 1 :
102
- h = '0' + h
103
- return bytearray .fromhex (h )
98
+ return bytearray (num .to_bytes (int (math .ceil (num .bit_length () / 8 )), "big" ))
104
99
105
100
def _calculate_x (self ) -> int :
106
101
i = (self .username + ':' + self .password ).encode ()
@@ -112,7 +107,7 @@ def _calculate_x(self) -> int:
112
107
hash_instance .update (Srp .to_byte_array (self .salt ))
113
108
hash_instance .update (hash_value )
114
109
115
- return int ( binascii . hexlify (hash_instance .digest ()), 16 )
110
+ return int . from_bytes (hash_instance .digest (), "big" )
116
111
117
112
def get_shared_secret (self ):
118
113
raise NotImplementedError ()
@@ -133,16 +128,16 @@ def __init__(self, username: str, password: str):
133
128
134
129
def set_salt (self , salt ):
135
130
if isinstance (salt , bytearray ):
136
- self .salt = gmpy2 . mpz (salt . hex (), 16 )
131
+ self .salt = int . from_bytes (salt , "big" )
137
132
else :
138
133
self .salt = salt
139
134
140
- def get_public_key (self ) -> gmpy2 . mpz :
135
+ def get_public_key (self ):
141
136
return pow (self .g , self .a , self .n )
142
137
143
138
def set_server_public_key (self , B ):
144
139
if isinstance (B , bytearray ):
145
- self .B = gmpy2 . mpz ( B . hex (), 16 )
140
+ self .B = int . from_bytes ( B , "big" )
146
141
else :
147
142
self .B = B
148
143
@@ -185,19 +180,18 @@ def get_proof(self):
185
180
hash_instance .update (Srp .to_byte_array (self .A ))
186
181
hash_instance .update (Srp .to_byte_array (self .B ))
187
182
hash_instance .update (K )
188
- r = binascii .hexlify (hash_instance .digest ())
189
- return int (r , 16 )
183
+ return int .from_bytes (hash_instance .digest (), "big" )
190
184
191
185
def verify_servers_proof (self , M ):
192
186
if isinstance (M , bytearray ):
193
- tmp = gmpy2 . mpz ( M . hex (), 16 )
187
+ tmp = int . from_bytes ( M , "big" )
194
188
else :
195
189
tmp = M
196
190
hash_instance = self .h ()
197
191
hash_instance .update (Srp .to_byte_array (self .A ))
198
192
hash_instance .update (Srp .to_byte_array (self .get_proof ()))
199
193
hash_instance .update (Srp .to_byte_array (self .get_session_key ()))
200
- return tmp == gmpy2 . mpz ( binascii . hexlify ( hash_instance .digest ()), 16 )
194
+ return tmp == int . from_bytes ( hash_instance .digest (), "big" )
201
195
202
196
203
197
class SrpServer (Srp ):
@@ -217,14 +211,12 @@ def __init__(self, username, password):
217
211
self .A = None
218
212
219
213
@staticmethod
220
- def _create_salt () -> gmpy2 . mpz :
214
+ def _create_salt () -> int :
221
215
# generate random salt
222
216
salt = crypt .mksalt (crypt .METHOD_SHA512 )[3 :]
223
- salt_b = salt .encode ()
224
- salt_hex = binascii .hexlify (salt_b )
225
- salt_int = int (salt_hex , 16 )
226
217
assert len (salt ) == 16
227
- return gmpy2 .mpz (salt_int )
218
+ salt_b = salt .encode ()
219
+ return int .from_bytes (salt_b , "big" )
228
220
229
221
def _get_verifier (self ) -> int :
230
222
hash_value = self ._calculate_x ()
@@ -276,14 +268,13 @@ def verify_clients_proof(self, m) -> bool:
276
268
hash_instance .update (Srp .to_byte_array (self .A ))
277
269
hash_instance .update (Srp .to_byte_array (self .B ))
278
270
hash_instance .update (K )
279
- r = binascii .hexlify (hash_instance .digest ())
280
- return m == gmpy2 .mpz (r , 16 )
271
+ return m == int .from_bytes (hash_instance .digest (), "big" )
281
272
282
- def get_proof (self , m ) -> gmpy2 . mpz :
273
+ def get_proof (self , m ) -> int :
283
274
hash_instance = self .h ()
284
275
hash_instance .update (Srp .to_byte_array (self .A ))
285
276
hash_instance .update (Srp .to_byte_array (m ))
286
277
hash_instance .update (Srp .to_byte_array (self .get_session_key ()))
287
- return gmpy2 . mpz ( binascii . hexlify ( hash_instance .digest ()), 16 )
278
+ return int . from_bytes ( hash_instance .digest (), "big" )
288
279
289
280
0 commit comments