Skip to content

Commit c4dae87

Browse files
authored
Merge branch 'master' into supported-25519
2 parents 19cc88f + ab52150 commit c4dae87

File tree

6 files changed

+33
-45
lines changed

6 files changed

+33
-45
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ python:
44
- "3.6"
55
before_install:
66
- sudo apt-get update
7-
- sudo apt-get install -y libgmp-dev libmpfr-dev libmpc-dev libffi-dev build-essential python3-pip python3-dev
7+
- sudo apt-get install -y libffi-dev build-essential python3-pip python3-dev
88
- pip install coveralls
99
script: coverage run -m unittest -v
1010
after_success:

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ The code presented in this repository was created based on release R1 from 2017-
1212

1313
# Installation
1414

15-
Since the code relies on **gmpy2** for large numbers some development libraries and a compiler is required:
15+
The code relies on some C libraries so some development packages and a compiler are required:
1616

1717
So for debian:
1818
```bash
19-
apt install libgmp-dev libmpfr-dev libmpc-dev libffi-dev build-essential python3-pip python3-dev
19+
apt install libffi-dev build-essential python3-pip python3-dev
2020
```
2121

2222
After that use **pip3** to install the package:

homekit/accessoryserver.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
# limitations under the License.
1515
#
1616
import binascii
17-
import gmpy2
1817
import hashlib
1918
import io
2019
import json
@@ -974,7 +973,7 @@ def _post_pair_setup(self):
974973
self.log_message('Step #4 /pair-setup')
975974

976975
# 1) use ios pub key to compute shared secret key
977-
ios_pub_key = gmpy2.mpz(binascii.hexlify(d_req[1][1]), 16)
976+
ios_pub_key = int.from_bytes(d_req[1][1], "big")
978977
server = self.server.sessions[self.session_id]['srp']
979978
server.set_client_public_key(ios_pub_key)
980979

@@ -984,7 +983,7 @@ def _post_pair_setup(self):
984983
self.server.sessions[self.session_id]['session_key'] = session_key
985984

986985
# 2) verify ios proof
987-
ios_proof = gmpy2.mpz(binascii.hexlify(d_req[2][1]), 16)
986+
ios_proof = int.from_bytes(d_req[2][1], "big")
988987
if not server.verify_clients_proof(ios_proof):
989988
d_res.append((TLV.kTLVType_State, TLV.M4, ))
990989
d_res.append((TLV.kTLVType_Error, TLV.kTLVError_Authentication,))

homekit/crypto/srp.py

+27-36
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,18 @@
2020
Implements the Secure Remote Password (SRP) algorithm. More information can be found on
2121
https://tools.ietf.org/html/rfc5054. See HomeKit spec page 36 for adjustments imposed by Apple.
2222
"""
23-
2423
import crypt
25-
import gmpy2
24+
import math
2625
import hashlib
27-
28-
import six
29-
import binascii
26+
import sys
3027

3128

3229
class Srp:
3330
def __init__(self):
3431
# 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)
3633
# modulus as defined by 3072bit group of RFC 5054
37-
self.n = gmpy2.mpz(int(six.b('''\
34+
self.n = int(b'''\
3835
FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08\
3936
8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B\
4037
302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9\
@@ -48,7 +45,7 @@ def __init__(self):
4845
B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226\
4946
1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C\
5047
BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC\
51-
E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF'''), 16))
48+
E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF''', 16)
5249
# HomeKit requires SHA-512 (See page 36)
5350
self.h = hashlib.sha512
5451
self.A = None
@@ -62,21 +59,22 @@ def generate_private_key():
6259
"""
6360
Static function to generate a 16 byte random key.
6461
65-
:return: the key as gmpy2 multi-precision integer
62+
:return: the key as an integer
6663
"""
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")
6866

69-
def _calculate_k(self) -> gmpy2.mpz:
67+
def _calculate_k(self) -> int:
7068
# calculate k (see https://tools.ietf.org/html/rfc5054#section-2.5.3)
7169
hash_instance = self.h()
7270
n = Srp.to_byte_array(self.n)
7371
g = bytearray.fromhex((383 * '00' + '05')) # 383 * b'0' + '5'.encode()
7472
hash_instance.update(n)
7573
hash_instance.update(g)
76-
k = gmpy2.mpz(int(binascii.hexlify(hash_instance.digest()), 16))
74+
k = int.from_bytes(hash_instance.digest(), "big")
7775
return k
7876

79-
def _calculate_u(self) -> gmpy2.mpz:
77+
def _calculate_u(self) -> int:
8078
if self.A is None:
8179
raise RuntimeError('Client\'s public key is missing')
8280
if self.B is None:
@@ -86,21 +84,18 @@ def _calculate_u(self) -> gmpy2.mpz:
8684
B_b = Srp.to_byte_array(self.B)
8785
hash_instance.update(A_b)
8886
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")
9088
return u
9189

9290
def get_session_key(self) -> int:
9391
hash_instance = self.h()
9492
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")
9694
return hash_value
9795

9896
@staticmethod
9997
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"))
10499

105100
def _calculate_x(self) -> int:
106101
i = (self.username + ':' + self.password).encode()
@@ -112,7 +107,7 @@ def _calculate_x(self) -> int:
112107
hash_instance.update(Srp.to_byte_array(self.salt))
113108
hash_instance.update(hash_value)
114109

115-
return int(binascii.hexlify(hash_instance.digest()), 16)
110+
return int.from_bytes(hash_instance.digest(), "big")
116111

117112
def get_shared_secret(self):
118113
raise NotImplementedError()
@@ -133,16 +128,16 @@ def __init__(self, username: str, password: str):
133128

134129
def set_salt(self, salt):
135130
if isinstance(salt, bytearray):
136-
self.salt = gmpy2.mpz(salt.hex(), 16)
131+
self.salt = int.from_bytes(salt, "big")
137132
else:
138133
self.salt = salt
139134

140-
def get_public_key(self) -> gmpy2.mpz:
135+
def get_public_key(self):
141136
return pow(self.g, self.a, self.n)
142137

143138
def set_server_public_key(self, B):
144139
if isinstance(B, bytearray):
145-
self.B = gmpy2.mpz(B.hex(), 16)
140+
self.B = int.from_bytes(B, "big")
146141
else:
147142
self.B = B
148143

@@ -185,19 +180,18 @@ def get_proof(self):
185180
hash_instance.update(Srp.to_byte_array(self.A))
186181
hash_instance.update(Srp.to_byte_array(self.B))
187182
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")
190184

191185
def verify_servers_proof(self, M):
192186
if isinstance(M, bytearray):
193-
tmp = gmpy2.mpz(M.hex(), 16)
187+
tmp = int.from_bytes(M, "big")
194188
else:
195189
tmp = M
196190
hash_instance = self.h()
197191
hash_instance.update(Srp.to_byte_array(self.A))
198192
hash_instance.update(Srp.to_byte_array(self.get_proof()))
199193
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")
201195

202196

203197
class SrpServer(Srp):
@@ -217,14 +211,12 @@ def __init__(self, username, password):
217211
self.A = None
218212

219213
@staticmethod
220-
def _create_salt() -> gmpy2.mpz:
214+
def _create_salt() -> int:
221215
# generate random salt
222216
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)
226217
assert len(salt) == 16
227-
return gmpy2.mpz(salt_int)
218+
salt_b = salt.encode()
219+
return int.from_bytes(salt_b, "big")
228220

229221
def _get_verifier(self) -> int:
230222
hash_value = self._calculate_x()
@@ -276,14 +268,13 @@ def verify_clients_proof(self, m) -> bool:
276268
hash_instance.update(Srp.to_byte_array(self.A))
277269
hash_instance.update(Srp.to_byte_array(self.B))
278270
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")
281272

282-
def get_proof(self, m) -> gmpy2.mpz:
273+
def get_proof(self, m) -> int:
283274
hash_instance = self.h()
284275
hash_instance.update(Srp.to_byte_array(self.A))
285276
hash_instance.update(Srp.to_byte_array(m))
286277
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")
288279

289280

requirements.txt

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
zeroconf
2-
gmpy2
32
hkdf
43
ed25519
54
cryptography

setup.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import setuptools
1818

1919

20-
with open("README.md", "r") as fh:
20+
with open("README.md", "r", encoding="utf-8") as fh:
2121
long_description = fh.read()
2222

2323
setuptools.setup(
@@ -40,7 +40,6 @@
4040
],
4141
install_requires=[
4242
'zeroconf',
43-
'gmpy2',
4443
'hkdf',
4544
'ed25519',
4645
'cryptography',

0 commit comments

Comments
 (0)