Remove import-froms for crypto.
This commit is contained in:
parent
6d59de416e
commit
015e5a2773
1 changed files with 78 additions and 84 deletions
162
src/mega/mega.py
162
src/mega/mega.py
|
@ -19,12 +19,6 @@ from tenacity import retry, wait_exponential, retry_if_exception_type
|
||||||
|
|
||||||
from . import crypto
|
from . import crypto
|
||||||
from . import errors
|
from . import errors
|
||||||
from .crypto import (
|
|
||||||
a32_to_base64, encrypt_key, base64_url_encode, encrypt_attr, base64_to_a32,
|
|
||||||
base64_url_decode, decrypt_attr, a32_to_str, get_chunks, str_to_a32,
|
|
||||||
decrypt_key, mpi_to_int, stringhash, prepare_key, make_id, makebyte,
|
|
||||||
modular_inverse, interleave_xor_8
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -41,7 +35,7 @@ class Mega:
|
||||||
self.timeout = 160 # max secs to wait for resp from api requests
|
self.timeout = 160 # max secs to wait for resp from api requests
|
||||||
self.sid = None
|
self.sid = None
|
||||||
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
self.sequence_num = random.randint(0, 0xFFFFFFFF)
|
||||||
self.request_id = make_id(10)
|
self.request_id = crypto.make_id(10)
|
||||||
self._trash_folder_node_id = None
|
self._trash_folder_node_id = None
|
||||||
self.shared_keys = {}
|
self.shared_keys = {}
|
||||||
|
|
||||||
|
@ -128,22 +122,22 @@ class Mega:
|
||||||
(account_version, user_salt) = self._api_account_version_and_salt(email)
|
(account_version, user_salt) = self._api_account_version_and_salt(email)
|
||||||
logger.debug('User account is version %d.', account_version)
|
logger.debug('User account is version %d.', account_version)
|
||||||
if account_version >= 2:
|
if account_version >= 2:
|
||||||
user_salt = base64_to_a32(user_salt)
|
user_salt = crypto.base64_to_a32(user_salt)
|
||||||
# Parameters specified by MEGA's webclient security.js, search for
|
# Parameters specified by MEGA's webclient security.js, search for
|
||||||
# "numOfIterations" and deriveKeyWithWebCrypto to cross-reference.
|
# "numOfIterations" and deriveKeyWithWebCrypto to cross-reference.
|
||||||
pbkdf2_key = hashlib.pbkdf2_hmac(
|
pbkdf2_key = hashlib.pbkdf2_hmac(
|
||||||
hash_name='sha512',
|
hash_name='sha512',
|
||||||
password=password.encode(),
|
password=password.encode(),
|
||||||
salt=a32_to_str(user_salt),
|
salt=crypto.a32_to_str(user_salt),
|
||||||
iterations=100000,
|
iterations=100000,
|
||||||
dklen=32
|
dklen=32
|
||||||
)
|
)
|
||||||
password_aes = str_to_a32(pbkdf2_key[:16])
|
password_aes = crypto.str_to_a32(pbkdf2_key[:16])
|
||||||
user_hash = base64_url_encode(pbkdf2_key[-16:])
|
user_hash = crypto.base64_url_encode(pbkdf2_key[-16:])
|
||||||
else:
|
else:
|
||||||
password_a32 = str_to_a32(password)
|
password_a32 = crypto.str_to_a32(password)
|
||||||
password_aes = prepare_key(password_a32)
|
password_aes = crypto.prepare_key(password_a32)
|
||||||
user_hash = stringhash(email, password_aes)
|
user_hash = crypto.stringhash(email, password_aes)
|
||||||
|
|
||||||
resp = self._api_start_session(email, user_hash)
|
resp = self._api_start_session(email, user_hash)
|
||||||
if isinstance(resp, int):
|
if isinstance(resp, int):
|
||||||
|
@ -156,10 +150,10 @@ class Mega:
|
||||||
password_key = [random.randint(0, 0xFFFFFFFF)] * 4
|
password_key = [random.randint(0, 0xFFFFFFFF)] * 4
|
||||||
session_self_challenge = [random.randint(0, 0xFFFFFFFF)] * 4
|
session_self_challenge = [random.randint(0, 0xFFFFFFFF)] * 4
|
||||||
|
|
||||||
k = a32_to_base64(encrypt_key(master_key, password_key))
|
k = crypto.a32_to_base64(crypto.encrypt_key(master_key, password_key))
|
||||||
ts = a32_to_str(session_self_challenge)
|
ts = crypto.a32_to_str(session_self_challenge)
|
||||||
ts += a32_to_str(encrypt_key(session_self_challenge, master_key))
|
ts += crypto.a32_to_str(crypto.encrypt_key(session_self_challenge, master_key))
|
||||||
ts = base64_url_encode(ts)
|
ts = crypto.base64_url_encode(ts)
|
||||||
user = self._api_request({'a': 'up', 'k': k, 'ts': ts})
|
user = self._api_request({'a': 'up', 'k': k, 'ts': ts})
|
||||||
|
|
||||||
resp = self._api_start_session(user)
|
resp = self._api_start_session(user)
|
||||||
|
@ -168,24 +162,24 @@ class Mega:
|
||||||
self._login_process(resp, password_key)
|
self._login_process(resp, password_key)
|
||||||
|
|
||||||
def _login_process(self, resp, password):
|
def _login_process(self, resp, password):
|
||||||
encrypted_master_key = base64_to_a32(resp['k'])
|
encrypted_master_key = crypto.base64_to_a32(resp['k'])
|
||||||
self.master_key = decrypt_key(encrypted_master_key, password)
|
self.master_key = crypto.decrypt_key(encrypted_master_key, password)
|
||||||
# tsid is for temporary sessions
|
# tsid is for temporary sessions
|
||||||
if 'tsid' in resp:
|
if 'tsid' in resp:
|
||||||
tsid = base64_url_decode(resp['tsid'])
|
tsid = crypto.base64_url_decode(resp['tsid'])
|
||||||
key_encrypted = a32_to_str(
|
key_encrypted = crypto.a32_to_str(
|
||||||
encrypt_key(str_to_a32(tsid[:16]), self.master_key)
|
crypto.encrypt_key(crypto.str_to_a32(tsid[:16]), self.master_key)
|
||||||
)
|
)
|
||||||
if key_encrypted == tsid[-16:]:
|
if key_encrypted == tsid[-16:]:
|
||||||
self.sid = resp['tsid']
|
self.sid = resp['tsid']
|
||||||
# csid is for user logins
|
# csid is for user logins
|
||||||
elif 'csid' in resp:
|
elif 'csid' in resp:
|
||||||
encrypted_rsa_private_key = base64_to_a32(resp['privk'])
|
encrypted_rsa_private_key = crypto.base64_to_a32(resp['privk'])
|
||||||
rsa_private_key = decrypt_key(
|
rsa_private_key = crypto.decrypt_key(
|
||||||
encrypted_rsa_private_key, self.master_key
|
encrypted_rsa_private_key, self.master_key
|
||||||
)
|
)
|
||||||
|
|
||||||
private_key = a32_to_str(rsa_private_key)
|
private_key = crypto.a32_to_str(rsa_private_key)
|
||||||
# The private_key contains 4 MPI integers concatenated together.
|
# The private_key contains 4 MPI integers concatenated together.
|
||||||
rsa_private_key = [0, 0, 0, 0]
|
rsa_private_key = [0, 0, 0, 0]
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
|
@ -195,7 +189,7 @@ class Mega:
|
||||||
bytelength = math.ceil(bitlength / 8)
|
bytelength = math.ceil(bitlength / 8)
|
||||||
# Add 2 bytes to accommodate the MPI header
|
# Add 2 bytes to accommodate the MPI header
|
||||||
bytelength += 2
|
bytelength += 2
|
||||||
rsa_private_key[i] = mpi_to_int(private_key[:bytelength])
|
rsa_private_key[i] = crypto.mpi_to_int(private_key[:bytelength])
|
||||||
private_key = private_key[bytelength:]
|
private_key = private_key[bytelength:]
|
||||||
|
|
||||||
first_factor_p = rsa_private_key[0]
|
first_factor_p = rsa_private_key[0]
|
||||||
|
@ -206,7 +200,7 @@ class Mega:
|
||||||
# RSA.construct and it does not seem to be necessary.
|
# RSA.construct and it does not seem to be necessary.
|
||||||
rsa_modulus_n = first_factor_p * second_factor_q
|
rsa_modulus_n = first_factor_p * second_factor_q
|
||||||
phi = (first_factor_p - 1) * (second_factor_q - 1)
|
phi = (first_factor_p - 1) * (second_factor_q - 1)
|
||||||
public_exponent_e = modular_inverse(private_exponent_d, phi)
|
public_exponent_e = crypto.modular_inverse(private_exponent_d, phi)
|
||||||
|
|
||||||
rsa_components = (
|
rsa_components = (
|
||||||
rsa_modulus_n,
|
rsa_modulus_n,
|
||||||
|
@ -217,11 +211,11 @@ class Mega:
|
||||||
)
|
)
|
||||||
rsa_decrypter = RSA.construct(rsa_components)
|
rsa_decrypter = RSA.construct(rsa_components)
|
||||||
|
|
||||||
encrypted_sid = mpi_to_int(base64_url_decode(resp['csid']))
|
encrypted_sid = crypto.mpi_to_int(crypto.base64_url_decode(resp['csid']))
|
||||||
|
|
||||||
sid = '%x' % rsa_decrypter._decrypt(encrypted_sid)
|
sid = '%x' % rsa_decrypter._decrypt(encrypted_sid)
|
||||||
sid = binascii.unhexlify('0' + sid if len(sid) % 2 else sid)
|
sid = binascii.unhexlify('0' + sid if len(sid) % 2 else sid)
|
||||||
self.sid = base64_url_encode(sid[:43])
|
self.sid = crypto.base64_url_encode(sid[:43])
|
||||||
|
|
||||||
def _parse_url(self, url):
|
def _parse_url(self, url):
|
||||||
"""
|
"""
|
||||||
|
@ -247,13 +241,13 @@ class Mega:
|
||||||
key = None
|
key = None
|
||||||
# my objects
|
# my objects
|
||||||
if uid in keys:
|
if uid in keys:
|
||||||
key = decrypt_key(base64_to_a32(keys[uid]), self.master_key)
|
key = crypto.decrypt_key(crypto.base64_to_a32(keys[uid]), self.master_key)
|
||||||
# shared folders
|
# shared folders
|
||||||
elif 'su' in file and 'sk' in file and ':' in file['k']:
|
elif 'su' in file and 'sk' in file and ':' in file['k']:
|
||||||
shared_key = decrypt_key(
|
shared_key = crypto.decrypt_key(
|
||||||
base64_to_a32(file['sk']), self.master_key
|
crypto.base64_to_a32(file['sk']), self.master_key
|
||||||
)
|
)
|
||||||
key = decrypt_key(base64_to_a32(keys[file['h']]), shared_key)
|
key = crypto.decrypt_key(crypto.base64_to_a32(keys[file['h']]), shared_key)
|
||||||
if file['su'] not in self.shared_keys:
|
if file['su'] not in self.shared_keys:
|
||||||
self.shared_keys[file['su']] = {}
|
self.shared_keys[file['su']] = {}
|
||||||
self.shared_keys[file['su']][file['h']] = shared_key
|
self.shared_keys[file['su']][file['h']] = shared_key
|
||||||
|
@ -263,26 +257,26 @@ class Mega:
|
||||||
shared_key = self.shared_keys[file['u']][hkey]
|
shared_key = self.shared_keys[file['u']][hkey]
|
||||||
if hkey in keys:
|
if hkey in keys:
|
||||||
key = keys[hkey]
|
key = keys[hkey]
|
||||||
key = decrypt_key(base64_to_a32(key), shared_key)
|
key = crypto.decrypt_key(crypto.base64_to_a32(key), shared_key)
|
||||||
break
|
break
|
||||||
if file['h'] and file['h'] in self.shared_keys.get('EXP', ()):
|
if file['h'] and file['h'] in self.shared_keys.get('EXP', ()):
|
||||||
shared_key = self.shared_keys['EXP'][file['h']]
|
shared_key = self.shared_keys['EXP'][file['h']]
|
||||||
encrypted_key = str_to_a32(
|
encrypted_key = crypto.str_to_a32(
|
||||||
base64_url_decode(file['k'].split(':')[-1])
|
crypto.base64_url_decode(file['k'].split(':')[-1])
|
||||||
)
|
)
|
||||||
key = decrypt_key(encrypted_key, shared_key)
|
key = crypto.decrypt_key(encrypted_key, shared_key)
|
||||||
file['shared_folder_key'] = shared_key
|
file['shared_folder_key'] = shared_key
|
||||||
if key is not None:
|
if key is not None:
|
||||||
if file['t'] == NODE_TYPE_FILE:
|
if file['t'] == NODE_TYPE_FILE:
|
||||||
k = interleave_xor_8(key)
|
k = crypto.interleave_xor_8(key)
|
||||||
file['iv'] = key[4:6] + (0, 0)
|
file['iv'] = key[4:6] + (0, 0)
|
||||||
file['meta_mac'] = key[6:8]
|
file['meta_mac'] = key[6:8]
|
||||||
else:
|
else:
|
||||||
k = key
|
k = key
|
||||||
file['key'] = key
|
file['key'] = key
|
||||||
file['k'] = k
|
file['k'] = k
|
||||||
attributes = base64_url_decode(file['a'])
|
attributes = crypto.base64_url_decode(file['a'])
|
||||||
attributes = decrypt_attr(attributes, k)
|
attributes = crypto.decrypt_attr(attributes, k)
|
||||||
file['a'] = attributes
|
file['a'] = attributes
|
||||||
# other => wrong object
|
# other => wrong object
|
||||||
elif file['k'] == '':
|
elif file['k'] == '':
|
||||||
|
@ -309,8 +303,8 @@ class Mega:
|
||||||
ok_dict = {}
|
ok_dict = {}
|
||||||
|
|
||||||
for ok_item in files.get('ok', []):
|
for ok_item in files.get('ok', []):
|
||||||
shared_key = decrypt_key(
|
shared_key = crypto.decrypt_key(
|
||||||
base64_to_a32(ok_item['k']), self.master_key
|
crypto.base64_to_a32(ok_item['k']), self.master_key
|
||||||
)
|
)
|
||||||
ok_dict[ok_item['h']] = shared_key
|
ok_dict[ok_item['h']] = shared_key
|
||||||
for s_item in files.get('s', []):
|
for s_item in files.get('s', []):
|
||||||
|
@ -414,8 +408,8 @@ class Mega:
|
||||||
file = file['f'][0]
|
file = file['f'][0]
|
||||||
public_handle = self._api_request({'a': 'l', 'n': file['h']})
|
public_handle = self._api_request({'a': 'l', 'n': file['h']})
|
||||||
file_key = file['k'][file['k'].index(':') + 1:]
|
file_key = file['k'][file['k'].index(':') + 1:]
|
||||||
decrypted_key = a32_to_base64(
|
decrypted_key = crypto.a32_to_base64(
|
||||||
decrypt_key(base64_to_a32(file_key), self.master_key)
|
crypto.decrypt_key(crypto.base64_to_a32(file_key), self.master_key)
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
f'{self.schema}://{self.domain}'
|
f'{self.schema}://{self.domain}'
|
||||||
|
@ -439,7 +433,7 @@ class Mega:
|
||||||
"Can't get a public link from that file "
|
"Can't get a public link from that file "
|
||||||
"(is this a shared file?)"
|
"(is this a shared file?)"
|
||||||
)
|
)
|
||||||
decrypted_key = a32_to_base64(file['key'])
|
decrypted_key = crypto.a32_to_base64(file['key'])
|
||||||
return (
|
return (
|
||||||
f'{self.schema}://{self.domain}'
|
f'{self.schema}://{self.domain}'
|
||||||
f'/#!{public_handle}!{decrypted_key}'
|
f'/#!{public_handle}!{decrypted_key}'
|
||||||
|
@ -465,7 +459,7 @@ class Mega:
|
||||||
"Can't get a public link from that file "
|
"Can't get a public link from that file "
|
||||||
"(is this a shared file?)"
|
"(is this a shared file?)"
|
||||||
)
|
)
|
||||||
decrypted_key = a32_to_base64(file['shared_folder_key'])
|
decrypted_key = crypto.a32_to_base64(file['shared_folder_key'])
|
||||||
return (
|
return (
|
||||||
f'{self.schema}://{self.domain}'
|
f'{self.schema}://{self.domain}'
|
||||||
f'/#F!{public_handle}!{decrypted_key}'
|
f'/#F!{public_handle}!{decrypted_key}'
|
||||||
|
@ -661,18 +655,18 @@ class Mega:
|
||||||
except (errors.RequestError, KeyError):
|
except (errors.RequestError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
master_key_cipher = AES.new(a32_to_str(self.master_key), AES.MODE_ECB)
|
master_key_cipher = AES.new(crypto.a32_to_str(self.master_key), AES.MODE_ECB)
|
||||||
ha = base64_url_encode(
|
ha = crypto.base64_url_encode(
|
||||||
master_key_cipher.encrypt(node_data['h'].encode("utf8") + node_data['h'].encode("utf8"))
|
master_key_cipher.encrypt(node_data['h'].encode("utf8") + node_data['h'].encode("utf8"))
|
||||||
)
|
)
|
||||||
|
|
||||||
share_key = secrets.token_bytes(16)
|
share_key = secrets.token_bytes(16)
|
||||||
ok = base64_url_encode(master_key_cipher.encrypt(share_key))
|
ok = crypto.base64_url_encode(master_key_cipher.encrypt(share_key))
|
||||||
|
|
||||||
share_key_cipher = AES.new(share_key, AES.MODE_ECB)
|
share_key_cipher = AES.new(share_key, AES.MODE_ECB)
|
||||||
node_key = node_data['k']
|
node_key = node_data['k']
|
||||||
encrypted_node_key = base64_url_encode(
|
encrypted_node_key = crypto.base64_url_encode(
|
||||||
share_key_cipher.encrypt(a32_to_str(node_key))
|
share_key_cipher.encrypt(crypto.a32_to_str(node_key))
|
||||||
)
|
)
|
||||||
|
|
||||||
node_id = node_data['h']
|
node_id = node_data['h']
|
||||||
|
@ -718,7 +712,7 @@ class Mega:
|
||||||
):
|
):
|
||||||
if file is None:
|
if file is None:
|
||||||
if is_public:
|
if is_public:
|
||||||
file_key = base64_to_a32(file_key)
|
file_key = crypto.base64_to_a32(file_key)
|
||||||
request = {
|
request = {
|
||||||
'a': 'g',
|
'a': 'g',
|
||||||
'g': 1,
|
'g': 1,
|
||||||
|
@ -732,7 +726,7 @@ class Mega:
|
||||||
}
|
}
|
||||||
file_data = self._api_request(request)
|
file_data = self._api_request(request)
|
||||||
|
|
||||||
k = interleave_xor_8(file_key)
|
k = crypto.interleave_xor_8(file_key)
|
||||||
iv = file_key[4:6] + (0, 0)
|
iv = file_key[4:6] + (0, 0)
|
||||||
meta_mac = file_key[6:8]
|
meta_mac = file_key[6:8]
|
||||||
else:
|
else:
|
||||||
|
@ -748,8 +742,8 @@ class Mega:
|
||||||
raise errors.RequestError('File not accessible anymore')
|
raise errors.RequestError('File not accessible anymore')
|
||||||
file_url = file_data['g']
|
file_url = file_data['g']
|
||||||
file_size = file_data['s']
|
file_size = file_data['s']
|
||||||
attribs = base64_url_decode(file_data['at'])
|
attribs = crypto.base64_url_decode(file_data['at'])
|
||||||
attribs = decrypt_attr(attribs, k)
|
attribs = crypto.decrypt_attr(attribs, k)
|
||||||
|
|
||||||
if dest_filename is not None:
|
if dest_filename is not None:
|
||||||
file_name = dest_filename
|
file_name = dest_filename
|
||||||
|
@ -766,7 +760,7 @@ class Mega:
|
||||||
with tempfile.NamedTemporaryFile(
|
with tempfile.NamedTemporaryFile(
|
||||||
mode='w+b', prefix='megapy_', delete=False
|
mode='w+b', prefix='megapy_', delete=False
|
||||||
) as temp_output_file:
|
) as temp_output_file:
|
||||||
k_str = a32_to_str(k)
|
k_str = crypto.a32_to_str(k)
|
||||||
counter = Counter.new(
|
counter = Counter.new(
|
||||||
128, initial_value=((iv[0] << 32) + iv[1]) << 64
|
128, initial_value=((iv[0] << 32) + iv[1]) << 64
|
||||||
)
|
)
|
||||||
|
@ -774,9 +768,9 @@ class Mega:
|
||||||
|
|
||||||
mac_str = '\0' * 16
|
mac_str = '\0' * 16
|
||||||
mac_encryptor = AES.new(k_str, AES.MODE_CBC, mac_str.encode("utf8"))
|
mac_encryptor = AES.new(k_str, AES.MODE_CBC, mac_str.encode("utf8"))
|
||||||
iv_str = a32_to_str([iv[0], iv[1], iv[0], iv[1]])
|
iv_str = crypto.a32_to_str([iv[0], iv[1], iv[0], iv[1]])
|
||||||
|
|
||||||
for chunk_start, chunk_size in get_chunks(file_size):
|
for chunk_start, chunk_size in crypto.get_chunks(file_size):
|
||||||
chunk = input_file.read(chunk_size)
|
chunk = input_file.read(chunk_size)
|
||||||
chunk = aes.decrypt(chunk)
|
chunk = aes.decrypt(chunk)
|
||||||
temp_output_file.write(chunk)
|
temp_output_file.write(chunk)
|
||||||
|
@ -801,7 +795,7 @@ class Mega:
|
||||||
logger.info(
|
logger.info(
|
||||||
'%s of %s downloaded', file_info.st_size, file_size
|
'%s of %s downloaded', file_info.st_size, file_size
|
||||||
)
|
)
|
||||||
file_mac = str_to_a32(mac_str)
|
file_mac = crypto.str_to_a32(mac_str)
|
||||||
# check mac integrity
|
# check mac integrity
|
||||||
if (
|
if (
|
||||||
file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]
|
file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]
|
||||||
|
@ -826,7 +820,7 @@ class Mega:
|
||||||
|
|
||||||
# generate random aes key (128) for file
|
# generate random aes key (128) for file
|
||||||
ul_key = [random.randint(0, 0xFFFFFFFF) for _ in range(6)]
|
ul_key = [random.randint(0, 0xFFFFFFFF) for _ in range(6)]
|
||||||
k_str = a32_to_str(ul_key[:4])
|
k_str = crypto.a32_to_str(ul_key[:4])
|
||||||
count = Counter.new(
|
count = Counter.new(
|
||||||
128, initial_value=((ul_key[4] << 32) + ul_key[5]) << 64
|
128, initial_value=((ul_key[4] << 32) + ul_key[5]) << 64
|
||||||
)
|
)
|
||||||
|
@ -837,9 +831,9 @@ class Mega:
|
||||||
|
|
||||||
mac_str = '\0' * 16
|
mac_str = '\0' * 16
|
||||||
mac_encryptor = AES.new(k_str, AES.MODE_CBC, mac_str.encode("utf8"))
|
mac_encryptor = AES.new(k_str, AES.MODE_CBC, mac_str.encode("utf8"))
|
||||||
iv_str = a32_to_str([ul_key[4], ul_key[5], ul_key[4], ul_key[5]])
|
iv_str = crypto.a32_to_str([ul_key[4], ul_key[5], ul_key[4], ul_key[5]])
|
||||||
if file_size > 0:
|
if file_size > 0:
|
||||||
for chunk_start, chunk_size in get_chunks(file_size):
|
for chunk_start, chunk_size in crypto.get_chunks(file_size):
|
||||||
chunk = input_file.read(chunk_size)
|
chunk = input_file.read(chunk_size)
|
||||||
upload_progress += len(chunk)
|
upload_progress += len(chunk)
|
||||||
|
|
||||||
|
@ -856,7 +850,7 @@ class Mega:
|
||||||
|
|
||||||
block = chunk[i:i + 16]
|
block = chunk[i:i + 16]
|
||||||
if len(block) % 16:
|
if len(block) % 16:
|
||||||
block += makebyte('\0' * (16 - len(block) % 16))
|
block += crypto.makebyte('\0' * (16 - len(block) % 16))
|
||||||
mac_str = mac_encryptor.encrypt(encryptor.encrypt(block))
|
mac_str = mac_encryptor.encrypt(encryptor.encrypt(block))
|
||||||
|
|
||||||
# encrypt file and upload
|
# encrypt file and upload
|
||||||
|
@ -879,7 +873,7 @@ class Mega:
|
||||||
logger.info('Chunks uploaded')
|
logger.info('Chunks uploaded')
|
||||||
logger.info('Setting attributes to complete upload')
|
logger.info('Setting attributes to complete upload')
|
||||||
logger.info('Computing attributes')
|
logger.info('Computing attributes')
|
||||||
file_mac = str_to_a32(mac_str)
|
file_mac = crypto.str_to_a32(mac_str)
|
||||||
|
|
||||||
# determine meta mac
|
# determine meta mac
|
||||||
meta_mac = (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3])
|
meta_mac = (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3])
|
||||||
|
@ -887,15 +881,15 @@ class Mega:
|
||||||
dest_filename = dest_filename or os.path.basename(filename)
|
dest_filename = dest_filename or os.path.basename(filename)
|
||||||
attribs = {'n': dest_filename}
|
attribs = {'n': dest_filename}
|
||||||
|
|
||||||
encrypt_attribs = base64_url_encode(
|
encrypt_attribs = crypto.base64_url_encode(
|
||||||
encrypt_attr(attribs, ul_key[:4])
|
crypto.encrypt_attr(attribs, ul_key[:4])
|
||||||
)
|
)
|
||||||
key = [
|
key = [
|
||||||
ul_key[0] ^ ul_key[4], ul_key[1] ^ ul_key[5],
|
ul_key[0] ^ ul_key[4], ul_key[1] ^ ul_key[5],
|
||||||
ul_key[2] ^ meta_mac[0], ul_key[3] ^ meta_mac[1], ul_key[4],
|
ul_key[2] ^ meta_mac[0], ul_key[3] ^ meta_mac[1], ul_key[4],
|
||||||
ul_key[5], meta_mac[0], meta_mac[1]
|
ul_key[5], meta_mac[0], meta_mac[1]
|
||||||
]
|
]
|
||||||
encrypted_key = a32_to_base64(encrypt_key(key, self.master_key))
|
encrypted_key = crypto.a32_to_base64(crypto.encrypt_key(key, self.master_key))
|
||||||
logger.info('Sending request to update attributes')
|
logger.info('Sending request to update attributes')
|
||||||
# update attributes
|
# update attributes
|
||||||
request = {
|
request = {
|
||||||
|
@ -921,8 +915,8 @@ class Mega:
|
||||||
|
|
||||||
# encrypt attribs
|
# encrypt attribs
|
||||||
attribs = {'n': name}
|
attribs = {'n': name}
|
||||||
encrypt_attribs = base64_url_encode(encrypt_attr(attribs, ul_key[:4]))
|
encrypt_attribs = crypto.base64_url_encode(crypto.encrypt_attr(attribs, ul_key[:4]))
|
||||||
encrypted_key = a32_to_base64(encrypt_key(ul_key[:4], self.master_key))
|
encrypted_key = crypto.a32_to_base64(crypto.encrypt_key(ul_key[:4], self.master_key))
|
||||||
|
|
||||||
# update attributes
|
# update attributes
|
||||||
request = {
|
request = {
|
||||||
|
@ -973,9 +967,9 @@ class Mega:
|
||||||
# create new attribs
|
# create new attribs
|
||||||
attribs = {'n': new_name}
|
attribs = {'n': new_name}
|
||||||
# encrypt attribs
|
# encrypt attribs
|
||||||
encrypt_attribs = base64_url_encode(encrypt_attr(attribs, file['k']))
|
encrypt_attribs = crypto.base64_url_encode(crypto.encrypt_attr(attribs, file['k']))
|
||||||
encrypted_key = a32_to_base64(
|
encrypted_key = crypto.a32_to_base64(
|
||||||
encrypt_key(file['key'], self.master_key)
|
crypto.encrypt_key(file['key'], self.master_key)
|
||||||
)
|
)
|
||||||
# update attributes
|
# update attributes
|
||||||
request = {
|
request = {
|
||||||
|
@ -1115,7 +1109,7 @@ class Mega:
|
||||||
else:
|
else:
|
||||||
raise TypeError(f'Invalid dest_node {dest_node}.')
|
raise TypeError(f'Invalid dest_node {dest_node}.')
|
||||||
|
|
||||||
folder_key = base64_to_a32(folder_key)
|
folder_key = crypto.base64_to_a32(folder_key)
|
||||||
|
|
||||||
nodes = self.get_public_folder_files(folder_handle)
|
nodes = self.get_public_folder_files(folder_handle)
|
||||||
|
|
||||||
|
@ -1134,8 +1128,8 @@ class Mega:
|
||||||
import_list = []
|
import_list = []
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
k = node['k'].split(':')[1]
|
k = node['k'].split(':')[1]
|
||||||
k = decrypt_key(base64_to_a32(k), folder_key)
|
k = crypto.decrypt_key(crypto.base64_to_a32(k), folder_key)
|
||||||
new_k = a32_to_base64(encrypt_key(k, self.master_key))
|
new_k = crypto.a32_to_base64(crypto.encrypt_key(k, self.master_key))
|
||||||
|
|
||||||
node_import_args = {
|
node_import_args = {
|
||||||
'h': node['h'],
|
'h': node['h'],
|
||||||
|
@ -1147,7 +1141,7 @@ class Mega:
|
||||||
# This is the root public folder.
|
# This is the root public folder.
|
||||||
if dest_name is not None:
|
if dest_name is not None:
|
||||||
new_a = {'n': dest_name}
|
new_a = {'n': dest_name}
|
||||||
new_a = base64_url_encode(encrypt_attr(new_a, k))
|
new_a = crypto.base64_url_encode(crypto.encrypt_attr(new_a, k))
|
||||||
node_import_args['a'] = new_a
|
node_import_args['a'] = new_a
|
||||||
else:
|
else:
|
||||||
node_import_args['a'] = node['a']
|
node_import_args['a'] = node['a']
|
||||||
|
@ -1181,11 +1175,11 @@ class Mega:
|
||||||
if 'at' not in data or 's' not in data:
|
if 'at' not in data or 's' not in data:
|
||||||
raise ValueError("Unexpected result", data)
|
raise ValueError("Unexpected result", data)
|
||||||
|
|
||||||
key = base64_to_a32(file_key)
|
key = crypto.base64_to_a32(file_key)
|
||||||
k = interleave_xor_8(key)
|
k = crypto.interleave_xor_8(key)
|
||||||
|
|
||||||
size = data['s']
|
size = data['s']
|
||||||
unencrypted_attrs = decrypt_attr(base64_url_decode(data['at']), k)
|
unencrypted_attrs = crypto.decrypt_attr(crypto.base64_url_decode(data['at']), k)
|
||||||
if not unencrypted_attrs:
|
if not unencrypted_attrs:
|
||||||
return None
|
return None
|
||||||
result = {'size': size, 'name': unencrypted_attrs['n']}
|
result = {'size': size, 'name': unencrypted_attrs['n']}
|
||||||
|
@ -1206,11 +1200,11 @@ class Mega:
|
||||||
pl_info = self.get_public_file_info(file_handle, file_key)
|
pl_info = self.get_public_file_info(file_handle, file_key)
|
||||||
dest_name = pl_info['name']
|
dest_name = pl_info['name']
|
||||||
|
|
||||||
key = base64_to_a32(file_key)
|
key = crypto.base64_to_a32(file_key)
|
||||||
k = interleave_xor_8(key)
|
k = crypto.interleave_xor_8(key)
|
||||||
|
|
||||||
encrypted_key = a32_to_base64(encrypt_key(key, self.master_key))
|
encrypted_key = crypto.a32_to_base64(crypto.encrypt_key(key, self.master_key))
|
||||||
encrypted_name = base64_url_encode(encrypt_attr({'n': dest_name}, k))
|
encrypted_name = crypto.base64_url_encode(crypto.encrypt_attr({'n': dest_name}, k))
|
||||||
request = {
|
request = {
|
||||||
'a': 'p',
|
'a': 'p',
|
||||||
't': dest_node['h'],
|
't': dest_node['h'],
|
||||||
|
|
Loading…
Reference in a new issue