Example #1
0
    def download_file(self, file_id, file_key, public=False, store_path=None):
        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
        if store_path:
            file_name = os.path.join(store_path, file_name)
        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 += b'\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')

        return file_name
Example #2
0
    def uploadfile(self, filename, dst=None):
        if not dst:
            root_id = getattr(self, 'root_id', None)
            if root_id == None:
                self.get_files()
            dst = self.root_id
        infile = open(filename, 'rb')
        size = os.path.getsize(filename)
        ul_url = self.api_req({'a': 'u', 's': size})['p']

        ul_key = [random.randint(0, 0xFFFFFFFF) for _ in range(6)]
        counter = Counter.new(
            128, initial_value=((ul_key[4] << 32) + ul_key[5]) << 64)
        encryptor = AES.new(a32_to_str(ul_key[:4]),
                            AES.MODE_CTR,
                            counter=counter)

        file_mac = [0, 0, 0, 0]
        for chunk_start, chunk_size in sorted(get_chunks(size).items()):
            chunk = infile.read(chunk_size)

            chunk_mac = [ul_key[4], ul_key[5], ul_key[4], ul_key[5]]
            for i in range(0, len(chunk), 16):
                block = chunk[i:i + 16]
                if len(block) % 16:
                    block += b'\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, ul_key[:4])

            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, ul_key[:4])

            chunk = encryptor.encrypt(chunk)
            url = '%s/%s' % (ul_url, str(chunk_start))
            outfile = requests.post(url, data=chunk, stream=True).raw

            # assume utf-8 encoding. Maybe this entire section can be simplified
            # by not looking at the raw output
            # (http://docs.python-requests.org/en/master/user/advanced/#body-content-workflow)

            completion_handle = outfile.read().decode('utf-8')
        infile.close()

        meta_mac = (file_mac[0] ^ file_mac[1], file_mac[2] ^ file_mac[3])

        attributes = {'n': os.path.basename(filename)}
        enc_attributes = base64urlencode(enc_attr(attributes, ul_key[:4]))
        key = [
            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[5], meta_mac[0], meta_mac[1]
        ]
        encrypted_key = a32_to_base64(encrypt_key(key, self.master_key))
        data = self.api_req({
            'a':
            'p',
            't':
            dst,
            'n': [{
                'h': completion_handle,
                't': 0,
                'a': enc_attributes,
                'k': encrypted_key
            }]
        })
        return data