""" Now optional CSC 15 Lab 6b: RSA Authentication First, you need to complete the last part of lab 6, which asks you to come up with your own set of public and private keys, i.e., some numbers e,d,n as specified by the RSA algorithm. Please use prime numbers that are at least three digits long. Remember that (e,n) is your public key but you should keep d to yourself. You should have also written the procedures to encrypt/decrypt two characters at a time, but if you haven't I've included them below in the code skeleton that I'm giving you. I've written a set of procedures and examples for you to communicate easily over a TCP/IP socket with a server, which I will "man." We will invent and implement a "Simplified Certificate Request Protocol". # Simified Certificate Request Protocol Details (SCRP): # 1. Client connect to TCP port 10015, default host 147.4.180.148 # 2. Client sends request in plain text, on three separate lines: # Line 1: Username # Line 2: e # Line 3: n # All data need to be send over the socket in string format, # so convert to str(e) and str(n) before sending. Similarly, # when reading numbers from a socket, you need to call int(..) to # convert them from strings to numbers. # 3. Server authenticates public key of client: # Server sends some encrypted text message to client using (e,n) # Remember that encrypted messages have the form of an array of numbers. # 4. Client reads and decrypts message, and sends back the message in # plain text. Sever checks that the message matches original # 4b. Server sends client a second, unencrypted message indicating if # the keys are valid # 5. If step 4 succeeds above, server will generate and encrypt (using # its private key) a certificate stating that user has public key (e,n). # The certificate, when decrypted with the authentication server's # public key, (SIGNERD,SIGNERN), should read, on separate lines: # First line text message stating certification, or error message # Username # e # n # 5b. If step 4 fails, or if certificate has already been issued for user, # server sends back a plain text message rejecting request. The certificate forces the user to only use the public key (e,n). But now say somebody stole your certificate. Can they pretend to be you? No, because they still won't have your private key. The certificate authenticates that "user named x has public key (e,n)". But to varify that you are indeed user x, we still need to encrypted some random message using your public key, and ask you to decrypted it, which would prove that you hold the corresponding private key. This step is similar to the CertServer program that you're communicating with: before certifying your public key, the server makes sure that you have a produced a valid set of keys. """ from random import randint from socket import * from getpass import getpass # input without echo import sys import re # MASTER PUBLIC KEY OF AUTHENTICATION PROVIDER (use to DECRYPT certificate) SIGNERD = 3253 SIGNERN = 3231677 ############ Procedure used for two-char encryption/decryption: def fastexp(m,e,n): # compute m**e % n efficiently if (e<0): return 1//fastexp(int(1/e +.5)) factor = m % n ax = 1 # accumulator while e>0: if (e%2==1): ax = (ax * factor) % n factor = (factor*factor) % n e = e//2 # return ax #fastexp # encoding a single, two-char string into a (16 bit) number: def twinenc1(s): if len(s)!=2: raise Exception("invalid input to twinenc1") return ord(s[0])*128 + ord(s[1]) #twinenc1 def twindec1(c): # inverse of twinenc1 s = chr((c//128) % 128) # first char s = s+chr(c%128) return s #twindec1 # encode a string as a sequence of two-char values: def twinenc(s): # pad string if needed to be of even length #if len(s)%2==1: s=s+" " s = s + (" "*(len(s)%2)) E = [] # list of codes to be returned i =0 # indexes s while i0: data = socketread(cfd) print(data) # echo data read locally sys.stdout.flush() # forces immediate print cfd.close() csocket.close() ## simple www client # call as follows: www("www.hofstra.edu") # comment out after testing ###### Functions to read, decrypt an parse a certificate generated by ## the SCRP server into a tuple (username,e,n) def decryptcertificate(fd,d,n): # decrypts and parses certificate from socket C = ReadArray(fd) M = decrypt(C,d,n) info = re.split("[/\n]+",M) # returns array of three strings return (info[1],int(info[2]),int(info[3])) # (user,e,n) # decryptcertificate def readcertificate(filename,d,n): # read certificate from file fd = open(filename,"r") C = ReadArray(fd) M = decrypt(C,d,n) fd.close() info = re.split("[/\n]+",M) # returns array of three strings return (info[1],int(info[2]),int(info[3])) # (user,e,n) #readcertificate # Sample set of keys to test that are valid (you also need your own) ce,cd,cn = 323, 23507, 787*1381 ############## Code for the SCRP Server: you can't run this because you ############## don't have SIGNERE, the server's private key. # random message prefix to send back to client: Messages = ["I'm ok and you're ok ","There was once a student named ","Can you read this ","this is a really cool message ","we'll make a nerd out of you yet ","don't you love csc15 ","your key looks awesome ","nice looking key ","come on, what kind of key is that ","hope nobody can break your key ","certificates aren't free "] CSPORT = 10015 # fixed server SCRP port. def CertServer(port): SERVED = [] # keep track of certificates already issued, by username sfd = socket(AF_INET,SOCK_STREAM) sfd.bind(('0.0.0.0',port)) sfd.listen(20) print("Starting Simplified Certificate Request Protocol Server...") sys.stdout.flush() # forces immediate print while True: (csocket,caddr) = sfd.accept() # accept connection from client csocket.settimeout(1.5) # server timeout on reads cfd = csocket.makefile("rw") # can use socket like a file try: # try needed for read timeout print("SCRP connection from",caddr[0],"...") user = socketread(cfd) #replaces cfd.readline() ce = int(socketread(cfd)) cn = int(socketread(cfd)) print("Info from client: user", user," E",ce," N",cn) sys.stdout.flush() # forces immediate print # Construct verification message message = getpass("Enter message for verification: ") # no echo input if len(message)<1: mi = randint(0,len(Messages)-1) message = Messages[mi]+user if len(message)%2==1: message = message+"." # pad for encryption Cm = encrypt(message,ce,cn) # encrypt message with key received WriteArray(cfd,Cm) # use ReadArray(cfd) on client side # expect message echoed in plaintext from client: rm = socketread(cfd) print("message from client:",rm) print("message expected:",message) ok = (rm==message) # and not(user in SERVED) if ok: # generate authentication certificate print("Client passed test, sending certificate") socketwrite(cfd,"Client possesion of private key verified, sending certificate...") cert="The following public key is certified:\n" cert = cert + user+"\n" + str(ce)+"\n"+str(cn)+"\n" ccert = encrypt(cert,SIGNERE,SIGNERN) WriteArray(cfd,ccert) #SERVED.append(user) else: # not ok print("Client didn't pass test") socketwrite(cfd,"You don't hold the correct private key.\n0\n0\n0") sys.stdout.flush() except Exception as ste: print("Error:",ste) cfd.close() csocket.close() # server while loop #CertServer #### YOU NEED TO FINISH THIS... def CertClient(saddr,port,user,ce,cd,cn): csocket = socket(AF_INET,SOCK_STREAM) csocket.connect((saddr,port)) cfd = csocket.makefile("rw") socketwrite(cfd,user) # send request to server socketwrite(cfd,str(ce)) socketwrite(cfd,str(cn)) # ... you need to write the rest ... cfd.close() csocket.close() #CertClient def goodtest(): CertClient("147.4.180.148",CSPORT,"Nev Erstudy",ce,cd,cn) # valid def badtest(): CertClient("147.4.180.148",CSPORT,"Haten Umbers",3331,cd,cn) # bogus # Now instead of publishing your public key, you will publish the # "signed" certificate, which when decrypted using the master d,n will # give your public key. People can then authenticate you by sending # you a message using this key, which you can only read if you have the # corresponding private key. # but there's still a vulnerability to this setup... ########### (optional) ########### PART II: Simiplified Authenticated Messaging Protocol (SAMP) # After you have completed the above, formulate your own protocol for # authentication using the certificate and public key. Implement both a # client and a server to test the protocol.