Example #1
0
    def send_message(self, message_data):
        """
        Forming the message frame and sending message to server
        :param message: byte string to send
        """

        message_id = struct.pack('<Q', int(time() * 2**30) * 4)

        if self.auth_key is None or self.server_salt is None:
            # Unencrypted data send
            message = (b'\x00\x00\x00\x00\x00\x00\x00\x00' + message_id +
                       struct.pack('<I', len(message_data)) + message_data)
        else:
            # Encrypted data send
            encrypted_data = (
                self.server_salt + self.session_id + message_id +
                struct.pack('<II', self.number, len(message_data)) +
                message_data)
            message_key = SHA.new(encrypted_data).digest()[-16:]
            padding = os.urandom((-len(encrypted_data)) % 16)
            print(len(encrypted_data + padding))
            aes_key, aes_iv = self.aes_calculate(message_key)

            message = (
                self.auth_key_id + message_key +
                crypt.ige_encrypt(encrypted_data + padding, aes_key, aes_iv))

        step1 = struct.pack('<II', len(message) + 12, self.number) + message
        step2 = step1 + struct.pack('<I', crc32(step1))
        self.sock.send(step2)
        self.number += 1
Example #2
0
    def send_message(self, message_data):
        """
        Forming the message frame and sending message to server
        :param message: byte string to send
        """

        message_id = struct.pack('<Q', int((time()+self.timedelta)*2**30)*4)

        if self.auth_key is None or self.server_salt is None:
            # Unencrypted data send
            message = (b'\x00\x00\x00\x00\x00\x00\x00\x00' +
                       message_id +
                       struct.pack('<I', len(message_data)) +
                       message_data)
        else:
            # Encrypted data send
            encrypted_data = (self.server_salt +
                              self.session_id +
                              message_id +
                              struct.pack('<II', self.number, len(message_data)) +
                              message_data)
            message_key = SHA.new(encrypted_data).digest()[-16:]
            padding = os.urandom((-len(encrypted_data)) % 16)
            print(len(encrypted_data+padding))
            aes_key, aes_iv = self.aes_calculate(message_key)

            message = (self.auth_key_id + message_key +
                       crypt.ige_encrypt(encrypted_data+padding, aes_key, aes_iv))

        step1 = struct.pack('<II', len(message)+12, self.number) + message
        step2 = step1 + struct.pack('<I', crc32(step1))
        self.sock.send(step2)
        self.number += 1
Example #3
0
    def send_message(self, message_data):
        """
        Forming the message frame and sending message to server
        :param message: byte string to send
        """

        message_id = pack('<Q', int((time() + self.timedelta) * 2**30) * 4)

        if self.auth_key is None or self.server_salt is None:
            # Unencrypted data send
            message = (b'\x00\x00\x00\x00\x00\x00\x00\x00' + message_id +
                       pack('<I', len(message_data)) + message_data)
        else:
            # Encrypted data send
            encrypted_data = (self.server_salt + self.session_id + message_id +
                              pack('<II', self.number, len(message_data)) +
                              message_data)
            r = randint(12, 1024 - 16)
            encrypted_data += urandom(r - ((r + len(encrypted_data)) % 16))
            message_key = SHA256.new(self.auth_key[88:88 + 32] +
                                     encrypted_data).digest()[8:8 + 16]
            aes_key, aes_iv = self.KDF2(message_key)
            message = (self.auth_key_id + message_key +
                       crypt.ige_encrypt(encrypted_data, aes_key, aes_iv))

        if self.padded:
            # Use Padded intermediate instead
            padding = urandom(randint(12, 1024))  # MTProto 2.0
            self.sock.send(
                pack("<I",
                     len(padding) + len(message)) + message + padding)
        elif self.intermediate:
            self.sock.send(pack("<I", len(message)) + message)
        else:
            len_div4 = int(len(message) / 4)
            if len_div4 > 127:
                abridged_pack = pack("<I", (len_div4 << 8) + 0x7f)
            else:
                abridged_pack = pack("<B", len_div4)
            abridged_pack += message
            self.sock.send(abridged_pack)
Example #4
0
    def create_auth_key(self):

        nonce = os.urandom(16)
        print("Requesting pq")

        ResPQ = self.method_call('req_pq', nonce=nonce)
        server_nonce = ResPQ['server_nonce']

        # TODO: selecting RSA public key based on this fingerprint
        public_key_fingerprint = ResPQ['server_public_key_fingerprints'][0]

        pq_bytes = ResPQ['pq']
        pq = bytes_to_long(pq_bytes)

        [p, q] = prime.primefactors(pq)
        if p > q: (p, q) = (q, p)
        assert p * q == pq and p < q

        print("Factorization %d = %d * %d" % (pq, p, q))
        p_bytes = long_to_bytes(p)
        q_bytes = long_to_bytes(q)
        f = open(os.path.join(os.path.dirname(__file__), "rsa.pub"))
        key = RSA.importKey(f.read())

        new_nonce = os.urandom(32)
        data = TL.serialize_obj('p_q_inner_data',
                                pq=pq_bytes,
                                p=p_bytes,
                                q=q_bytes,
                                nonce=nonce,
                                server_nonce=server_nonce,
                                new_nonce=new_nonce)

        sha_digest = SHA.new(data).digest()
        random_bytes = os.urandom(255 - len(data) - len(sha_digest))
        to_encrypt = sha_digest + data + random_bytes
        encrypted_data = key.encrypt(to_encrypt, 0)[0]

        print("Starting Diffie Hellman key exchange")
        server_dh_params = self.method_call(
            'req_DH_params',
            nonce=nonce,
            server_nonce=server_nonce,
            p=p_bytes,
            q=q_bytes,
            public_key_fingerprint=public_key_fingerprint,
            encrypted_data=encrypted_data)
        assert nonce == server_dh_params['nonce']
        assert server_nonce == server_dh_params['server_nonce']

        encrypted_answer = server_dh_params['encrypted_answer']

        tmp_aes_key = SHA.new(new_nonce + server_nonce).digest() + SHA.new(
            server_nonce + new_nonce).digest()[0:12]
        tmp_aes_iv = SHA.new(server_nonce + new_nonce).digest(
        )[12:20] + SHA.new(new_nonce + new_nonce).digest() + new_nonce[0:4]

        answer_with_hash = crypt.ige_decrypt(encrypted_answer, tmp_aes_key,
                                             tmp_aes_iv)

        answer_hash = answer_with_hash[:20]
        answer = answer_with_hash[20:]
        # TODO: SHA hash assertion here

        server_DH_inner_data = TL.deserialize(io.BytesIO(answer))
        assert nonce == server_DH_inner_data['nonce']
        assert server_nonce == server_DH_inner_data['server_nonce']
        dh_prime_str = server_DH_inner_data['dh_prime']
        g = server_DH_inner_data['g']
        g_a_str = server_DH_inner_data['g_a']
        server_time = server_DH_inner_data['server_time']
        self.timedelta = server_time - time()
        print("Server-client time delta = %.1f s" % self.timedelta)

        dh_prime = bytes_to_long(dh_prime_str)
        g_a = bytes_to_long(g_a_str)

        assert prime.isprime(dh_prime)
        retry_id = 0
        b_str = os.urandom(256)
        b = bytes_to_long(b_str)
        g_b = pow(g, b, dh_prime)

        g_b_str = long_to_bytes(g_b)

        data = TL.serialize_obj('client_DH_inner_data',
                                nonce=nonce,
                                server_nonce=server_nonce,
                                retry_id=retry_id,
                                g_b=g_b_str)
        data_with_sha = SHA.new(data).digest() + data
        data_with_sha_padded = data_with_sha + os.urandom(
            -len(data_with_sha) % 16)
        encrypted_data = crypt.ige_encrypt(data_with_sha_padded, tmp_aes_key,
                                           tmp_aes_iv)

        Set_client_DH_params_answer = self.method_call(
            'set_client_DH_params',
            nonce=nonce,
            server_nonce=server_nonce,
            encrypted_data=encrypted_data)

        auth_key = pow(g_a, b, dh_prime)
        auth_key_str = long_to_bytes(auth_key)
        auth_key_sha = SHA.new(auth_key_str).digest()
        auth_key_aux_hash = auth_key_sha[:8]

        new_nonce_hash1 = SHA.new(new_nonce + b'\x01' +
                                  auth_key_aux_hash).digest()[-16:]
        new_nonce_hash2 = SHA.new(new_nonce + b'\x02' +
                                  auth_key_aux_hash).digest()[-16:]
        new_nonce_hash3 = SHA.new(new_nonce + b'\x03' +
                                  auth_key_aux_hash).digest()[-16:]

        assert Set_client_DH_params_answer['nonce'] == nonce
        assert Set_client_DH_params_answer['server_nonce'] == server_nonce
        assert Set_client_DH_params_answer[
            'new_nonce_hash1'] == new_nonce_hash1
        print("Diffie Hellman key exchange processed successfully")

        self.server_salt = strxor(new_nonce[0:8], server_nonce[0:8])
        self.auth_key = auth_key_str
        self.auth_key_id = auth_key_sha[-8:]
        print("Auth key generated")
Example #5
0
    def create_auth_key(self):

        nonce = os.urandom(16)
        print("Requesting pq")

        ResPQ = self.method_call('req_pq', nonce=nonce)
        server_nonce = ResPQ['server_nonce']

        # TODO: selecting RSA public key based on this fingerprint
        public_key_fingerprint = ResPQ['server_public_key_fingerprints'][0]

        pq_bytes = ResPQ['pq']
        pq = bytes_to_long(pq_bytes)

        [p, q] = prime.primefactors(pq)
        if p > q: (p, q) = (q, p)
        assert p*q == pq and p < q

        print("Factorization %d = %d * %d" % (pq, p, q))
        p_bytes = long_to_bytes(p)
        q_bytes = long_to_bytes(q)
        f = open(os.path.join(os.path.dirname(__file__), "rsa.pub"))
        key = RSA.importKey(f.read())

        new_nonce = os.urandom(32)
        data = TL.serialize_obj('p_q_inner_data',
                                pq=pq_bytes,
                                p=p_bytes,
                                q=q_bytes,
                                nonce=nonce,
                                server_nonce=server_nonce,
                                new_nonce=new_nonce)

        sha_digest = SHA.new(data).digest()
        random_bytes = os.urandom(255-len(data)-len(sha_digest))
        to_encrypt = sha_digest + data + random_bytes
        encrypted_data = key.encrypt(to_encrypt, 0)[0]

        print("Starting Diffie Hellman key exchange")
        server_dh_params = self.method_call('req_DH_params',
                                            nonce=nonce,
                                            server_nonce=server_nonce,
                                            p=p_bytes,
                                            q=q_bytes,
                                            public_key_fingerprint=public_key_fingerprint,
                                            encrypted_data=encrypted_data)
        assert nonce == server_dh_params['nonce']
        assert server_nonce == server_dh_params['server_nonce']

        encrypted_answer = server_dh_params['encrypted_answer']

        tmp_aes_key = SHA.new(new_nonce + server_nonce).digest() + SHA.new(server_nonce + new_nonce).digest()[0:12]
        tmp_aes_iv = SHA.new(server_nonce + new_nonce).digest()[12:20] + SHA.new(new_nonce + new_nonce).digest() + new_nonce[0:4]

        answer_with_hash = crypt.ige_decrypt(encrypted_answer, tmp_aes_key, tmp_aes_iv)

        answer_hash = answer_with_hash[:20]
        answer = answer_with_hash[20:]
        # TODO: SHA hash assertion here

        server_DH_inner_data = TL.deserialize(io.BytesIO(answer))
        assert nonce == server_DH_inner_data['nonce']
        assert server_nonce == server_DH_inner_data['server_nonce']
        dh_prime_str = server_DH_inner_data['dh_prime']
        g = server_DH_inner_data['g']
        g_a_str = server_DH_inner_data['g_a']
        server_time = server_DH_inner_data['server_time']
        self.timedelta = server_time - time()
        print("Server-client time delta = %.1f s" % self.timedelta)

        dh_prime = bytes_to_long(dh_prime_str)
        g_a = bytes_to_long(g_a_str)

        assert prime.isprime(dh_prime)
        retry_id = 0
        b_str = os.urandom(256)
        b = bytes_to_long(b_str)
        g_b = pow(g, b, dh_prime)

        g_b_str = long_to_bytes(g_b)

        data = TL.serialize_obj('client_DH_inner_data',
                                nonce=nonce,
                                server_nonce=server_nonce,
                                retry_id=retry_id,
                                g_b=g_b_str)
        data_with_sha = SHA.new(data).digest()+data
        data_with_sha_padded = data_with_sha + os.urandom(-len(data_with_sha) % 16)
        encrypted_data = crypt.ige_encrypt(data_with_sha_padded, tmp_aes_key, tmp_aes_iv)

        for i in range(1, self.AUTH_MAX_RETRY): # retry when dh_gen_retry or dh_gen_fail
            Set_client_DH_params_answer = self.method_call('set_client_DH_params',
                                                       nonce=nonce,
                                                       server_nonce=server_nonce,
                                                       encrypted_data=encrypted_data)

            # print Set_client_DH_params_answer
            auth_key = pow(g_a, b, dh_prime)
            auth_key_str = long_to_bytes(auth_key)
            auth_key_sha = SHA.new(auth_key_str).digest()
            auth_key_aux_hash = auth_key_sha[:8]

            new_nonce_hash1 = SHA.new(new_nonce+b'\x01'+auth_key_aux_hash).digest()[-16:]
            new_nonce_hash2 = SHA.new(new_nonce+b'\x02'+auth_key_aux_hash).digest()[-16:]
            new_nonce_hash3 = SHA.new(new_nonce+b'\x03'+auth_key_aux_hash).digest()[-16:]

            assert Set_client_DH_params_answer['nonce'] == nonce
            assert Set_client_DH_params_answer['server_nonce'] == server_nonce

            if Set_client_DH_params_answer.name == 'dh_gen_ok':
                assert Set_client_DH_params_answer['new_nonce_hash1'] == new_nonce_hash1
                print("Diffie Hellman key exchange processed successfully")

                self.server_salt = strxor(new_nonce[0:8], server_nonce[0:8])
                self.auth_key = auth_key_str
                self.auth_key_id = auth_key_sha[-8:]
                print("Auth key generated")
                return "Auth Ok"
            elif Set_client_DH_params_answer.name == 'dh_gen_retry':
                assert Set_client_DH_params_answer['new_nonce_hash2'] == new_nonce_hash2
                print ("Retry Auth")
            elif Set_client_DH_params_answer.name == 'dh_gen_fail':
                assert Set_client_DH_params_answer['new_nonce_hash3'] == new_nonce_hash3
                print("Auth Failed")
                raise Exception("Auth Failed")
            else: raise Exception("Response Error")