Solved

Need Python Code Converted To Delphi

Posted on 2010-11-28
1
399 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
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 if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …

724 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