Solved

Need Python Code Converted To Delphi

Posted on 2010-11-28
1
386 Views
Last Modified: 2016-09-29
The most important block is tlsobject, thank you.


def P_hash(secret, seed, length, hashfunc):

    a = {}

    a[0] = seed

    s = ""

    n = 1

    while len(s) < length:

        if n not in a:

            a[n] = hmac.new(secret, a[n-1], hashfunc).digest()

        s += hmac.new(secret, a[n] + seed, hashfunc).digest()

        n += 1

        

    return s[0:length]

        

def binaryxor(s1, s2):

    out = ""

    for i in xrange(len(s1)):

        out += chr(ord(s1[i]) ^ ord(s2[i]))

        

    return out

    

def PRF(secret, label, seed, size):

    slen = (len(secret) + 1) / 2

    a = P_hash(secret[:slen], label + seed, size, hashlib.md5)

    b = P_hash(secret[-slen:], label + seed, size, hashlib.sha1)

    return binaryxor(a, b)

    

def makerandomdata():

    st = ""

    for i in xrange(28):

        st += chr(random.randint(0, 255))

        

    return struct.pack(">L", int(time.time())) + st

    



class tlsobject(object):

    def __init__(self, logger, is_server = True):

        self.logger = logger

        self.is_server = is_server

        self.serverrandom = ""

        self.clientrandom = ""

        self.pre_master_secret = ""

        self.master_secret = ""

        

        self.allhandshakedata = ""

        self.version = "\x03\x01"

        self.client_encryption = False

        self.server_encryption = False

        

        self.clientseqnum = 0

        self.serverseqnum = 0

        

    def init_cryptosystem(self):

        self.master_secret = PRF(self.pre_master_secret, "master secret", self.clientrandom + self.serverrandom, 48)



        key_block = PRF(self.master_secret, "key expansion", self.serverrandom + self.clientrandom, 64)

        self.client_write_MAC = key_block[0:16]

        self.server_write_MAC = key_block[16:32]

        self.client_write_key = key_block[32:48]

        self.server_write_key = key_block[48:64]

        self.clientcrypt = ARC4.new(self.client_write_key)

        self.servercrypt = ARC4.new(self.server_write_key)



    def parsedata(self, data):

        appdata = []

        i = 0

        while i < len(data):

            header = data[i:i+5]

            if len(header) != 5:

                self.logger.error("Not enough data for header! %s %d", binascii.b2a_hex(data), i)

                sys.exit()

                

            i += 5

            contenttype = ord(header[0])

            version = header[1:3]

            if version != self.version:

                self.logger.error("Invalid version %d", repr(version))

                sys.exit()

                

            size = struct.unpack(">H", header[3:5])[0]

            fragment = data[i:i+size]

            if len(fragment) != size:

                self.logger.error("Not enough data for fragment! %s %d %d", binascii.b2a_hex(data), i, size)

                sys.exit()

            

            i += size

            

            self.logger.debug("Found content %d %d", contenttype, size)

            

            if (self.is_server and self.client_encryption) or (not self.is_server and self.server_encryption):

                fragment = self.decrypt_and_check_mac(contenttype, fragment)

                

            if contenttype == 20:

                self.parse_cipherchange(fragment)

            elif contenttype == 22:

                self.parse_handshake(fragment)

            elif contenttype == 23:

                self.logger.debug("Got application data %s", binascii.b2a_hex(fragment))

                appdata.append(fragment)

            else:

                self.logger.error("Unhandled content type %s %d", binascii.b2a_hex(fragment), contenttype)

                sys.exit()

                

        return appdata

        

    def decrypt_and_check_mac(self, contenttype, ciphertext):

        if self.is_server:

            plaintext = self.clientcrypt.decrypt(ciphertext)

            fragment = plaintext[:-16]

            MAC = plaintext[-16:]

            calcMAC = hmac.new(self.client_write_MAC, struct.pack(">Q", self.clientseqnum) + chr(contenttype) + self.version + struct.pack(">H", len(fragment)) + fragment, hashlib.md5).digest()

            if MAC != calcMAC:

                self.logger.error("DIFFERING MACS! %s %s", binascii.b2a_hex(plaintext), binascii.b2a_hex(fragment + calcMAC))

                sys.exit()

            

            self.clientseqnum += 1

            

            return fragment

            

        else:

            plaintext = self.servercrypt.decrypt(ciphertext)

            fragment = plaintext[:-16]

            MAC = plaintext[-16:]

            calcMAC = hmac.new(self.server_write_MAC, struct.pack(">Q", self.serverseqnum) + chr(contenttype) + self.version + struct.pack(">H", len(fragment)) + fragment, hashlib.md5).digest()

            if MAC != calcMAC:

                self.logger.error("DIFFERING MACS! %s %s", binascii.b2a_hex(plaintext), binascii.b2a_hex(fragment + calcMAC))

                sys.exit()

            

            self.serverseqnum += 1

            

            return fragment

            

    def parse_cipherchange(self, fragment):

        if fragment != "\x01":

            self.logger.error("Weird cipher change fragment! %s", repr(fragment))

            sys.exit()

        

        if self.is_server:

            self.client_encryption = True

        else:

            self.server_encryption = True

            

    def parse_handshake(self, fragment):

        i = 0

        while i < len(fragment):

            header = fragment[i:i+4]

            if len(header) != 4:

                self.logger.error("Not enough data for header! %s %d", binascii.b2a_hex(fragment), i)

                sys.exit()

            i += 4

            handshaketype = ord(header[0])

            size = struct.unpack(">L", header)[0] & 0x00ffffff

            handshakedata = fragment[i:i+size]

            if len(handshakedata) != size:

                self.logger.error("not enough data for handshake data! %s %d %d", binascii.b2a_hex(fragment), i, size)

                sys.exit()

            i += size

            

            self.logger.debug("Found handshake %d %d", handshaketype, size)

            

            if handshaketype == 1:

                self.parse_clienthello(handshakedata)

            elif handshaketype == 2:

                self.parse_serverhello(handshakedata)

            elif handshaketype == 11:

                self.parse_certificate(handshakedata)

            elif handshaketype == 14:

                if size != 0:

                    self.logger.error("Server_hello_done has nonstandard length %d", size)

                    sys.exit()

            elif handshaketype == 16:

                self.parse_clientkeyexchange(handshakedata)

            elif handshaketype == 20:

                self.parse_finished(handshakedata)

            else:

                self.logger.error("Unhandled handshake %d", handshaketype)

                sys.exit()

                

        self.allhandshakedata += fragment

        

    def parse_clienthello(self, data):

        version = data[0:2]

        if version != self.version:

            self.logger.error("Invalid version %s", repr(version))

            sys.exit()

        self.clientrandom = data[2:34]

        extrasettings = data[34:]

        if extrasettings != binascii.a2b_hex("00001600040005000a000900640062000300060013001200630100"):

            self.logger.warning("Unexpected client settings %s %s", binascii.b2a_hex(data), binascii.b2a_hex(extrasettings))

        

    def parse_serverhello(self, data):

        version = data[0:2]

        if version != self.version:

            self.logger.error("Invalid version %s", repr(version))

            sys.exit()

        self.serverrandom = data[2:34]

        sessionidlength = ord(data[34])

        if sessionidlength != 32:

            self.logger.error("Nonstandard session ID length! %d", sessionidlength)

            sys.exit()

            

        self.sessionid = data[35:67]

        if data[67:70] != "\x00\x04\x00":

            self.logger.error("Nonstandard cipher suite! %s", repr(data[67:70]))

            sys.exit()

        

    def parse_certificate(self, data):

        certhash = hashlib.md5(data).hexdigest()

        

        # 512-bit RSA key

        if certhash == "81e1e85248f3de66f88f56c0fdf6614c":

            self.rsakey = real_key_2_sign

            self.rsasize = 512

        elif certhash == "0fbfa0185aa1f7972fa4d63b0594ca6a":

            self.rsakey = fake_key2_sign

            self.rsasize = 512

        elif certhash == "0a1ba2bb7dcf9aec94e9c7df115d60f5":

            self.rsakey = real_key_sign

            self.rsasize = 2048

        else:

            self.logger.error("Unknown certificate %s %s", certhash, binascii.b2a_hex(data))

            sys.exit()

        

    def parse_clientkeyexchange(self, data):

        length = struct.unpack(">H", data[0:2])[0]

        if len(data) != length + 2:

            self.logger.error("Client key exchange length failed!")

            sys.exit()

            

        decryptedkey = self.rsakey.decrypt(data[2:])

        self.logger.debug("Decrypted key %s" , binascii.b2a_hex(decryptedkey))

        self.pre_master_secret = decryptedkey[-48:]

        self.init_cryptosystem()





    def parse_finished(self, handshakedata):

        if self.is_server:

            finishedmessage = PRF(self.master_secret, "client finished", hashlib.md5(self.allhandshakedata).digest() + hashlib.sha1(self.allhandshakedata).digest(), 12)

            

            if handshakedata != finishedmessage:

                self.logger.error("Finished handshake doesn't match! %s %s", binascii.b2a_hex(finishedmessage), binascii.b2a_hex(handshakedata))

                sys.exit()

        else:

            finishedmessage = PRF(self.master_secret, "server finished", hashlib.md5(self.allhandshakedata).digest() + hashlib.sha1(self.allhandshakedata).digest(), 12)

            

            if handshakedata != finishedmessage:

                self.logger.error("Finished handshake doesn't match! %s %s", binascii.b2a_hex(finishedmessage), binascii.b2a_hex(handshakedata))

                sys.exit()



    def make_message(self, contenttype, data):

        if contenttype == 22:

            self.allhandshakedata += data

            

        if (self.is_server and self.server_encryption) or (not self.is_server and self.client_encryption):

            if self.is_server:

                MAC = hmac.new(self.server_write_MAC, struct.pack(">Q", self.serverseqnum) + chr(contenttype) + self.version + struct.pack(">H", len(data)) + data, hashlib.md5).digest()

                data = self.servercrypt.encrypt(data + MAC)

                self.serverseqnum += 1

            else:

                MAC = hmac.new(self.client_write_MAC, struct.pack(">Q", self.clientseqnum) + chr(contenttype) + self.version + struct.pack(">H", len(data)) + data, hashlib.md5).digest()

                data = self.clientcrypt.encrypt(data + MAC)

                self.clientseqnum += 1

            

        message = chr(contenttype) + self.version + struct.pack(">H", len(data)) + data

        return message

        

    def make_handshake(self, handshaketype, data):

        handshake = chr(handshaketype) + struct.pack(">L", len(data))[1:4] + data

        return handshake



    def make_clienthello(self):

        self.clientrandom = makerandomdata()

        

        sessionid = ""

        ciphercompressuite = binascii.a2b_hex("001600040005000a000900640062000300060013001200630100")

        

        handshake = self.make_handshake(1, self.version + self.clientrandom + chr(len(sessionid)) + sessionid + ciphercompressuite)

        

        return self.make_message(22, handshake)

        

    def make_serverhello(self, sessionid, certificate):

        self.serverrandom = makerandomdata()

        self.sessionid = sessionid

        

        # FIX LATER

        if len(certificate) == 469:

            self.rsakey = fake_key2

        elif len(certificate) == 1189:

            self.rsakey = fake_key

        

        ciphercompressuite = "\x00\x04\x00"

        handshake = self.make_handshake(2, self.version + self.serverrandom + chr(len(sessionid)) + sessionid + ciphercompressuite)

        

        certificates = struct.pack(">L", len(certificate))[1:4] + certificate

        handshake += self.make_handshake(11, struct.pack(">L", len(certificates))[1:4] + certificates)

        

        handshake += self.make_handshake(14, "")

        

        return self.make_message(22, handshake)



    def make_serverchangefinish(self):

        # chance cipher spec

        message = self.make_message(20, "\x01")

        

        self.server_encryption = True

        

        finishedmessage = PRF(self.master_secret, "server finished", hashlib.md5(self.allhandshakedata).digest() + hashlib.sha1(self.allhandshakedata).digest(), 12)

        message += self.make_message(22, self.make_handshake(20, finishedmessage))

        

        return message

        

    def make_client_key_exchange(self):

        st = ""

        for i in xrange(46):

            st += chr(random.randint(0, 255))

        

        self.pre_master_secret = self.version + st

        

        if self.rsasize == 512:

            encrypted = self.rsakey.encrypt("\x02" + "\xff" * 13 + "\x00" + self.pre_master_secret, 0)[0]

            encrypted = encrypted.rjust(64, "\x00")

            if len(encrypted) != 64:

                self.logger.error("Invalid size after encrypt %d", len(encrypted))

                sys.exit()

                

            handshake = self.make_handshake(16, struct.pack(">H", len(encrypted)) + encrypted)

            

            message = self.make_message(22, handshake)

        elif self.rsasize == 2048:

            encrypted = self.rsakey.encrypt("\x02" + "\xff" * 205 + "\x00" + self.pre_master_secret, 0)[0]

            encrypted = encrypted.rjust(256, "\x00")

            if len(encrypted) != 256:

                self.logger.error("Invalid size after encrypt %d", len(encrypted))

                sys.exit()

                

            handshake = self.make_handshake(16, struct.pack(">H", len(encrypted)) + encrypted)

            

            message = self.make_message(22, handshake)

        else:

            self.logger.error("Unknown RSA size %d", self.rsasize)

            sys.exit()

            

        message += self.make_message(20, "\x01")

        

        self.init_cryptosystem()

        self.client_encryption = True

        

        finishedmessage = PRF(self.master_secret, "client finished", hashlib.md5(self.allhandshakedata).digest() + hashlib.sha1(self.allhandshakedata).digest(), 12)

        message += self.make_message(22, self.make_handshake(20, finishedmessage))

        

        return message

        

    def make_appdata(self, data):

        return self.make_message(23, data)

Open in new window

0
Comment
Question by:rotem156
1 Comment
 
LVL 14

Accepted Solution

by:
systan earned 500 total points
ID: 34225304
That code's encrypt and decrypt data, function that ask for key/seed to encrypt or decrypt using certificates, the code also ask as client/server and depends on the user option.

Why need to convert, while you can look for that functions here.
http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20554541.html
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi TcxGrid group footer summary 3 200
How to call a form that is in a DLL  from an application? 13 64
Python mysql Insert data error 3 79
Python Encoding Problem \u2013 4 104
Strings in Python are the set of characters that, once defined, cannot be changed by any other method like replace. Even if we use the replace method it still does not modify the original string that we use, but just copies the string and then modif…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
Learn the basics of strings in Python: declaration, operations, indices, and slicing. Strings are declared with quotations; for example: s = "string": Strings are immutable.: Strings may be concatenated or multiplied using the addition and multiplic…
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…

937 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now