2 from hashlib
import sha1
3 from cryptography
.hazmat
.backends
import default_backend
4 from cryptography
.hazmat
.primitives
.asymmetric
.padding
import PKCS1v15
5 from cryptography
.hazmat
.primitives
.serialization
import load_der_public_key
6 from cryptography
.hazmat
.primitives
.ciphers
import Cipher
, algorithms
, modes
9 def generate_shared_secret():
13 def create_AES_cipher(shared_secret
):
14 cipher
= Cipher(algorithms
.AES(shared_secret
), modes
.CFB8(shared_secret
),
15 backend
=default_backend())
19 def encrypt_token_and_secret(pubkey
, verification_token
, shared_secret
):
20 """Encrypts the verification token and shared secret
21 with the server's public key.
23 :param pubkey: The RSA public key provided by the server
24 :param verification_token: The verification token provided by the server
25 :param shared_secret: The generated shared secret
26 :return: A tuple containing (encrypted token, encrypted secret)
28 pubkey
= load_der_public_key(pubkey
, default_backend())
30 encrypted_token
= pubkey
.encrypt(verification_token
, PKCS1v15())
31 encrypted_secret
= pubkey
.encrypt(shared_secret
, PKCS1v15())
32 return encrypted_token
, encrypted_secret
35 def generate_verification_hash(server_id
, shared_secret
, public_key
):
36 verification_hash
= sha1()
38 verification_hash
.update(server_id
.encode('utf-8'))
39 verification_hash
.update(shared_secret
)
40 verification_hash
.update(public_key
)
42 return minecraft_sha1_hash_digest(verification_hash
)
45 def minecraft_sha1_hash_digest(sha1_hash
):
46 # Minecraft first parses the sha1 bytes as a signed number and then
47 # spits outs its hex representation
48 number_representation
= _number_from_bytes(sha1_hash
.digest(), signed
=True)
49 return format(number_representation
, 'x')
52 def _number_from_bytes(b
, signed
=False):
54 return int.from_bytes(b
, byteorder
='big', signed
=signed
)
55 except AttributeError: # pragma: no cover
59 num
= int(str(b
).encode('hex'), 16)
60 if signed
and (ord(b
[0]) & 0x80):
61 num
-= 2 ** (len(b
) * 8)
65 class EncryptedFileObjectWrapper(object):
66 def __init__(self
, file_object
, decryptor
):
67 self
.actual_file_object
= file_object
68 self
.decryptor
= decryptor
70 def read(self
, length
):
71 return self
.decryptor
.update(self
.actual_file_object
.read(length
))
74 return self
.actual_file_object
.fileno()
77 self
.actual_file_object
.close()
80 class EncryptedSocketWrapper(object):
81 def __init__(self
, socket
, encryptor
, decryptor
):
82 self
.actual_socket
= socket
83 self
.encryptor
= encryptor
84 self
.decryptor
= decryptor
86 def recv(self
, length
):
87 return self
.decryptor
.update(self
.actual_socket
.recv(length
))
90 self
.actual_socket
.send(self
.encryptor
.update(data
))
93 return self
.actual_socket
.fileno()
96 return self
.actual_socket
.close()
98 def shutdown(self
, *args
, **kwds
):
99 return self
.actual_socket
.shutdown(*args
, **kwds
)