/
chat_client.py
173 lines (133 loc) · 5.59 KB
/
chat_client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# -*- encoding: utf-8 -*-
import os
import socket
import sys
import select
import ssl
import getpass
import hashlib
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_PSS
from Crypto.Hash import SHA512
from communication import send, receive
import requests
from OpenSSL import crypto
class chat_client(object):
def __init__(self, name):
self.name = name
# Quit flag
self.flag = False
self.port = 3490
self.host = 'localhost'
print "Enter your password"
#Encrypt the password
self.password = hashlib.sha512(getpass.getpass())
#print self.password.hexdigest()
#print self.password.digest_size
# Initial prompt
self.prompt = '[' + '@'.join((name, socket.gethostname().split('.')[0])) + ']> '
#May not need (Maximus)
# Generate client certificate
#print "Generating client certificate"
#self.createClientCert(self.name)
#print "Client certificate created"
client_privateKey = RSA.generate(4096, os.urandom)
client_pubkey = client_privateKey.publickey()
self.decryptor = client_privateKey
# Connect to server at port
try:
self.context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
self.context.verify_mode = ssl.CERT_REQUIRED
self.context.check_hostname = True
#Get the servers CA certificate
file_location = os.getcwd()
self.context.load_verify_locations(file_location + "/server.crt")
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Check server certificate
self.ssl_sock = self.context.wrap_socket(self.sock, server_hostname=self.host)
self.ssl_sock.settimeout(2)
except:
print "Server certificate invalid, closing chat."
exit(0)
#Check cipher used, we expect none since we didn't specify any
#print self.ssl_sock.cipher()
self.ssl_sock.connect((self.host, self.port))
print 'Connected to chat server %s:%d' % (self.host, self.port)
# Send my pubkey...
send(self.ssl_sock, client_pubkey.exportKey())
server_pubkey = receive(self.ssl_sock)
self.encryptionKey = RSA.importKey(server_pubkey)
# Send my name...
send(self.ssl_sock, 'NAME: ' + self.name)
# Send my password...
send(self.ssl_sock, 'PASSWORD: ' + self.password.hexdigest())
#send(self.ssl_sock, 'PASSWORD: ' + self.password)
# Print out users connected to server
print receive(self.ssl_sock)
data = receive(self.ssl_sock)
# Contains client address, set it
addr = data.split('CLIENT: ')[1]
if len(addr) > 15:#Means the server is not sending IP address of client
print 'Password Verification Failed'
print addr
exit(0)
self.prompt = '[' + '@'.join((self.name, addr)) + ']> '
except socket.error:
print 'Could not connect to chat server @%d' % self.port
sys.exit(1)
def cmdloop(self):
while not self.flag:
try:
sys.stdout.write(self.prompt)
sys.stdout.flush()
# Wait for input from stdin & socket
inputready, outputready, exceptrdy = select.select([0, self.sock], [], [])
for i in inputready:
if i == 0:
# grab message
data = sys.stdin.readline().strip()
try:
# encrypt
data = self.encryptionKey.encrypt(data, 0)
data = data[0]
# append signature
signkey = self.decryptor
message_hash = SHA512.new()
message_hash.update(data)
signer = PKCS1_PSS.new(signkey)
signature = signer.sign(message_hash)
data = '%s#^[[%s' % (data, signature)
except ValueError:
print 'Too large text, cannot encrypt, not sending.'
data = None
if data:
send(self.ssl_sock, data)
elif i == self.sock:
data = receive(self.ssl_sock)
if not data:
print 'Shutting down.'
self.flag = True
break
else:
if 'PLAIN:' in data:
data = data.strip('PLAIN:').strip()
else:
#data = str(data)
data = self.decryptor.decrypt(data)
sys.stdout.write(data + '\n')
sys.stdout.flush()
except KeyboardInterrupt:
print 'Interrupted.'
self.sock.close()
break
def createClientCert(self, name):
try:
os.system("python createClientCert.py %s" % name )
except IOError:
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit('Usage: python %s username' % sys.argv[0])
client = chat_client(sys.argv[1])
client.cmdloop()