def _login_common(self, res, password): if res in (-2, -9): raise MegaIncorrectPasswordExcetion("Incorrect e-mail and/or password.") enc_master_key = base64_to_a32(res['k']) self.master_key = decrypt_key(enc_master_key, password) if 'tsid' in res: tsid = base64urldecode(res['tsid']) key_encrypted = a32_to_str( encrypt_key(str_to_a32(tsid[:16]), self.master_key)) if key_encrypted == tsid[-16:]: self.sid = res['tsid'] elif 'csid' in res: enc_rsa_priv_key = base64_to_a32(res['privk']) rsa_priv_key = decrypt_key(enc_rsa_priv_key, self.master_key) privk = a32_to_str(rsa_priv_key) self.rsa_priv_key = [0, 0, 0, 0] for i in range(4): l = ((ord(privk[0]) * 256 + ord(privk[1]) + 7) / 8) + 2 self.rsa_priv_key[i] = mpi2int(privk[:l]) privk = privk[l:] enc_sid = mpi2int(base64urldecode(res['csid'])) decrypter = RSA.construct( (self.rsa_priv_key[0] * self.rsa_priv_key[1], 0, self.rsa_priv_key[2], self.rsa_priv_key[0], self.rsa_priv_key[1])) sid = '%x' % decrypter.key._decrypt(enc_sid) sid = binascii.unhexlify('0' + sid if len(sid) % 2 else sid) self.sid = base64urlencode(sid[:43])
def get_files(self): files_data = self.api_req({'a': 'f', 'c': 1}) for file in files_data['f']: if file['t'] in (0, 1): key = file['k'].split(':')[1] key = decrypt_key(base64_to_a32(key), self.master_key) # file if file['t'] == 0: k = (key[0] ^ key[4], key[1] ^ key[5], key[2] ^ key[6], key[3] ^ key[7]) # directory else: k = key attributes = base64urldecode(file['a']) attributes = dec_attr(attributes, k) file['a'] = attributes file['k'] = key # Root ("Cloud Drive") elif file['t'] == 2: self.root_id = file['h'] # Inbox elif file['t'] == 3: self.inbox_id = file['h'] # Trash Bin elif file['t'] == 4: self.trashbin_id = file['h'] return files_data
def download_file(self, file_id, file_key, public=False): if public: file_key = base64_to_a32(file_key) file_data = self.api_req({'a': 'g', 'g': 1, 'p': file_id}) else: file_data = self.api_req({'a': 'g', 'g': 1, 'n': file_id}) k = (file_key[0] ^ file_key[4], file_key[1] ^ file_key[5], file_key[2] ^ file_key[6], file_key[3] ^ file_key[7]) iv = file_key[4:6] + (0, 0) meta_mac = file_key[6:8] file_url = file_data['g'] file_size = file_data['s'] attributes = base64urldecode(file_data['at']) attributes = dec_attr(attributes, k) file_name = attributes['n'] infile = requests.get(file_url, stream=True).raw outfile = open(file_name, 'wb') counter = Counter.new( 128, initial_value=((iv[0] << 32) + iv[1]) << 64) decryptor = AES.new(a32_to_str(k), AES.MODE_CTR, counter=counter) file_mac = (0, 0, 0, 0) for chunk_start, chunk_size in sorted(get_chunks(file_size).items()): chunk = infile.read(chunk_size) chunk = decryptor.decrypt(chunk) outfile.write(chunk) chunk_mac = [iv[0], iv[1], iv[0], iv[1]] for i in range(0, len(chunk), 16): block = chunk[i:i+16] if len(block) % 16: block += '\0' * (16 - (len(block) % 16)) block = str_to_a32(block) chunk_mac = [ chunk_mac[0] ^ block[0], chunk_mac[1] ^ block[1], chunk_mac[2] ^ block[2], chunk_mac[3] ^ block[3]] chunk_mac = aes_cbc_encrypt_a32(chunk_mac, k) file_mac = [ file_mac[0] ^ chunk_mac[0], file_mac[1] ^ chunk_mac[1], file_mac[2] ^ chunk_mac[2], file_mac[3] ^ chunk_mac[3]] file_mac = aes_cbc_encrypt_a32(file_mac, k) outfile.close() # Integrity check if (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3]) != meta_mac: raise ValueError('MAC mismatch')