0

I have been trying to calculate the master secret used to encrypt some data using the client public key B, the server private key a and the client and server random values. I have calculated k=B^a, which to my understanding gives me the premaster secret. I then input this together with the random values into the following PRF function (page 15 of this pdf):

def prf(secret,label,seed,numblocks):
    seed=label+seed
    output = ''
    a=hmac.new(secret,msg=seed,digestmod=hashlib.sha256).digest()
    for j in range(numblocks):
        output += hmac.new(secret,msg=a+seed,digestmod=hashlib.sha256).digest()
        a=hmac.new(secret,msg=a,digestmod=hashlib.sha256).digest()
    return output
def master_secret(pms,client_random,server_random):
    out=prf(pms,"master secret",client_random+server_random,2)
    return out[:48]

According to the RFC specification for TLS1.2, this should output the master secret, but when verifying it with the data I have, it is wrong. Where is my mistake?

1

After trying to solve the problem for several hours, I noticed that there was a mistake in the server/client random values which caused the function to return a wrong value; the code posted above is correct.

EDIT: here is a working example to verify the code works:

#!/usr/bin/python2
import hmac
import hashlib
pre_secret = '\x77\xdc\x17\xff\x36\xd7\xaf\x80\x99\x9c\xdd\x47\xbf\x5d\x45\x78\xd2\x82\xb6\x71\x54\x74\x26\x88\xac\xff\x70\x48\x94\x34\xef\x58\x68\x08\x63\xb5\xad\x31\x4e\x8a\xf7\xf1\xfa\xa7\x15\x05\xf1\x4c\x5d\xa5\x40\x17\x98\x48\xb7\x9e\x4b\x19\x5f\x40\xc2\x9c\x6e\x29\x0a\x68\xeb\x22\xa3\xee\xb8\x5b\xe5\xce\x8f\x91\x73\x58\x33\xba\x15\xa0\x0c\x87\xbd\x3f\x0a\x9a\x03\xc0\xf6\x3c\xe3\x60\x79\xa8\xb4\x6f\x25\x26\xa7\xe1\x7f\x37\x51\x76\x59\x0b\xb0\x4f\x63\x35\xd2\x6d\x50\x8f\x55\xde\x19\x61\x55\x93\x56\x72\xde\x98\x42\x78\x51\xe2\x1a\x7e\xe1\xb7\x6a\x68\xfa\x55\x02\x64\x33\x04\x79\x33\x06\xf4\x10\x46\x4b\x40\xaf\xce\x33\x3d\x46\x01\xdb\xc9\x41\x54\x08\x1f\xfa\x3d\x9e\x88\x34\x8d\x64\x2f\x85\xa6\x46\x4d\xe7\xb1\x72\x42\x4f\xf9\xf4\xc7\x7e\x46\x2e\xed\xb1\xeb\x2d\x28\x95\x12\xf8\xc3\xf2\x2e\xbe\xde\xa2\xdd\xf6\x3a\x62\x0f\x9d\x17\x71\xf8\xf2\x07\x52\x72\x17\xba\x03\xbf\x1a\x2a\x26\xc6\x39\x87\xfb\xc8\x09\x48\x32\xf5\x2a\x89\x3d\x90\x1a\x74\x81\x4b\x2e\x24\xea\xb0\x75\x00\xce\x3f\x26\xe7\x1f\xa2\x80\xe7\x70\xf5\x74\xb0\x91\xa5\xd7\x1a\xbc\x40\x70\x05\x23\x5b\x19\x9b\xe7\x57\x29\xb9\x18\x32\xa9\xc2\xc2\xdc\xc5\x5b\xca\xfb\xb6\x25\x93\x76\x74\x09\x3c\x57\xde\x75\x07\x6e\x11\xe9\x2b\x9d\xd1\x1b\xa7\xe7\x1f\x21\x9e\xc6\x49\x80\xa4\x84\x8d\xd0\xc9\x75\x3f\x5c\xd9\x8b\x88\x6f\x5a\x49\x0e\xd6\x60\x87\x5c\x36\xf9\xe1\x99\x19\x26\xa4\xbd\x9a\x5a\xd5\x30\x9c\xa1\xe7\x99\x3a\x3d\xfd\x08\xeb\xf0\x51\x89\x2d\xd8\x0f\x70\x90\xde\x5f\x8e\xb2\x52\x05\x9b\x4d\x12\x6a\xff\x14\x17\x7f\xa5\x28\xf4\x3b\x55\xcf\x49\x09\x56\x1d\x61\xcd\x27\x5e\x02\x05\x87\x18\xf3\x75\xfa\x43\x40\x21\x6c\xe1\xc4\x51\x5b\xfe\xb6\x34\xea\x8f\x0d\x92\x0a\xe2\x79\xb7\xd5\x46\x3b\xf2\x3f\x6b\x76\xea\x48\xb8\xa7\xf1\xf6\x51\x84\x08\x43\x18\x4b\x63\x8f\x82\x56\x52\x13\xd8\x73\xc7\xd1\x17\xfa\xaa\x98\x21\x8f\x78\x13\x61\x5f\x43\xba\x32\x48\xbc\xc9\x60\xc8\xfa\x60\x57\x1b\xc9\x15\xee\x2d\xb8\xce\xb3\xea\xdd\x44\x19\x4d\x69\x63\xee\xc8\x7f\xd4\xf8\x80\x7d\x08\x82\xa8\xbe\x84\x4d\x92\x06\xa7\x92\x4e\x8d\xf1\xa1\x75\x07\xd5\x04\xb2\x7e\x93\xb9\x24\x11\x64\x6b\x23\xe4\x2e\x83\x4f\x60'
server_random = '\x89\x68\xc0\x01\xfc\xf6\xc1\xbf\x0d\xff\xe9\x3e\x5a\x98\x81\x04\x6c\x37\xce\x9f\x36\xb3\x76\x61\xcb\x0d\x26\x84\x50\x4b\x0e\xaf'
client_random = '\x59\x6c\xaa\x43\x97\xad\xb3\xe5\x08\xd6\x92\xa6\x2b\xe2\xc8\xc6\x98\x42\x0b\x24\x74\x1d\xd8\x9d\x32\xfd\x01\xb9\x70\xbe\x13\xde'
expected_output = '47acd374aad14df1e3c1636c234c186a63ebfb35a1c1b864fdf3204597f7b7ce29f6a41931ac41e8f3f0addb1d322c42'
def prf(secret,label,seed,numblocks):
        seed=label+seed
        output = ''
        a=hmac.new(secret,msg=seed,digestmod=hashlib.sha256).digest()
        for j in range(numblocks):
                output += hmac.new(secret,msg=a+seed,digestmod=hashlib.sha256).digest()
                a=hmac.new(secret,msg=a,digestmod=hashlib.sha256).digest()
        return output
def master_secret(pms,client_random,server_random):
        out=prf(pms,"master secret",client_random+server_random,2)
        return out[:48]
print(''.join([hex(ord(b))[2:].zfill(2) for b in master_secret(pre_secret, client_random, server_random)]) == expected_output)
  • Interesting stuff that. Might try that python bit myself some time. If it now works to your satisfaction you could accept your own reply as "Answer". -- Maybe add a "run this on your python prompt and see that it works" session transcript as well? (I'd be interested.) – StackzOfZtuff Nov 23 '17 at 15:25
  • @StackzOfZtuff I added my complete code so if you need it, here you go – Lukor Nov 23 '17 at 15:32
  • Great! Thanks. Can't get it to run though. (SyntaxError: EOL while scanning string literal) Something is broken with the line breaks in the string literal. I couldn't find a way to fix it. (Then I only got: ValueError: invalid \x escape.) Could you try again with no manually inserted hard line breaks? – StackzOfZtuff Nov 23 '17 at 17:50
  • @StackzOfZtuff actually there should be no line breaks, I'll fix that as soon as I get home – Lukor Nov 23 '17 at 17:58
  • @StackzOfZtuff I fixed the line breaks, it should work now (it does on my PC) – Lukor Nov 24 '17 at 1:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.