def SRPSetup(sock, email, password): g = 2 k = 3 N = int( 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) sock.send(email.encode() + b'\n') a = random.randint(0, 10000) A = dh.modexp(g, a, N) message = (str(A) + '\n').encode() sock.send(message) salt = ReadUntilNewline(sock) B = ReadUntilNewline(sock) u = ReadUntilNewline(sock) sha = hashlib.sha256() sha.update(salt) sha.update(password.encode()) x = int(sha.hexdigest(), 16) exp = (a + int(u) * x) S = dh.modexp(int(B), exp, N) sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest() return K, salt
def SRPSetup(sock, email, password): g = 2 k = 3 N = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) sock.send(email.encode() + b'\n') a = random.randint(0, 10000) A = dh.modexp(g, a, N) message = (str(A) + '\n').encode() sock.send(message) salt = ReadUntilNewline(sock) B = ReadUntilNewline(sock) u = ReadUntilNewline(sock) sha = hashlib.sha256() sha.update(salt) sha.update(password.encode()) x = int(sha.hexdigest(), 16) exp = (a + int(u) * x) S = dh.modexp(int(B), exp, N) sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest() return K, salt
def SRPSetup(sock, email, password, isClientGood): g = 2 k = 3 N = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) sock.send(email.encode() + b'\n') a = random.randint(0, 10000) if isClientGood: A = dh.modexp(g, a, N) else: # Sending this means that S = 0 server-side, since # A is the base of the modexp computing S, so all the # other parameters get ignored. # The other tweaking proposed, A = N or A = kN, have the # exact same effect, since you compute S = (A ** x) % A # which is equal to 0 no matter what 'x' is. A = 0 message = (str(A) + '\n').encode() sock.send(message) salt = ReadUntilNewline(sock) B = ReadUntilNewline(sock) sha = hashlib.sha256() sha.update(str(A).encode()) sha.update(B) u = int(sha.hexdigest(), 16) sha = hashlib.sha256() sha.update(salt) sha.update(password.encode()) x = int(sha.hexdigest(), 16) if isClientGood: exp = (a + u * x) base = (int(B) - k * dh.modexp(g, x, N)) S = dh.modexp(base, exp, N) else: # If we have been bad, we know the server has computed S = 0, # so we do the same on our side. We could also avoid computing # a bunch of other parameters before (namely, x and u). # At this point the secret is independent of which password # we send to the server, so we can send an empty one and still # be accepted as good users. S = 0 sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest() return K, salt
def SRPSetup(clientsocket): g = 2 k = 3 # Use the same large prime we used before. N = int( 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) # Random salt. salt = random.randint(1, 100000) saltBytes = str(salt).encode() # Hash salt|password and convert the result to an integer, x. We do # this by simply taking the decimal equivalent of the hash. sha = hashlib.sha256() sha.update(saltBytes) sha.update(PASSWORD) xhash = sha.hexdigest() x = int(xhash, 16) v = dh.modexp(g, x, N) # We don't actually make any use of the email in this exercise, # but in a real implementation we would associate the email with # the expected password, and/or do other verifications. email = ReadUntilNewline(clientsocket) A = ReadUntilNewline(clientsocket) b = random.randint(1, 10000) B = k * v + dh.modexp(g, b, N) clientsocket.send(saltBytes + b'\n') clientsocket.send(str(B).encode() + b'\n') sha = hashlib.sha256() sha.update(A) sha.update(str(B).encode()) u = int(sha.hexdigest(), 16) S = dh.modexp((int(A) * dh.modexp(v, u, N)), b, N) sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest() # Returns both K and saltBytes as byte strings. This helps later # since we hash them. return K.encode(), saltBytes
def SRPSetup(clientsocket): g = 2 k = 3 N = int('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) # Random salt. salt = str(random.randint(1, 100000)).encode() # Hash salt|password and convert the result to an integer, x. We do # this by simply taking the decimal equivalent of the hash. sha = hashlib.sha256() sha.update(salt) sha.update(PASSWORD) xhash = sha.hexdigest() x = int(xhash, 16) v = dh.modexp(g, x, N) # We don't actually make any use of the email in this exercise, # but in a real implementation we would associate the email with # the expected password, and/or do other verifications. email = ReadUntilNewline(clientsocket) A = ReadUntilNewline(clientsocket) b = random.randint(1, 10000) B = dh.modexp(g, b, N) clientsocket.send(salt + b'\n') clientsocket.send(str(B).encode() + b'\n') u = random.getrandbits(128) clientsocket.send(str(u).encode() + b'\n') S = dh.modexp((int(A) * dh.modexp(v, u, N)), b, N) sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest() # Returns both K and salt as byte strings. This is used for verification. return K.encode(), salt
def DHExchangeClient(serverHost, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((serverHost, port)) # Usual parameters as recommended by NIST. pHex = ( 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff' ) p = int(pHex, 16) g = 2 a = random.randint(0, p - 1) A = dh.modexp(g, a, p) B = 0 # Sends the message in the predefined format. message = 'BEGIN\n%s\n%s\n%s\nEND' % (str(p), str(g), str(A)) sock.send(message.encode()) # Gets a similar message back from the server. See the comments # on dh_server which has a similar loop. exchange = b'' while b'D' not in exchange: exchange += sock.recv(100) exchange = exchange.decode() pieces = exchange.split('\n') B = int(pieces[1]) secret = dh.modexp(B, a, p) print('My secret is', str(secret)) VerifyKey(sock, secret) sock.close()
def DHExchangeServer(clientsocket): A = 0 p = 0 g = 0 exchange = b'' # In this scenario, the DH exchange message has this form: # BEGIN # p # g # A # END # (including newlines). Therefore we keep reading 100 bytes # until we read D. We do not try and read the whole word # because it could fall across a boundary. However this only # works because the D is unique (p, g and A are integers). while b'D' not in exchange: exchange += clientsocket.recv(100) exchange = exchange.decode() pieces = exchange.split('\n') p = int(pieces[1]) g = int(pieces[2]) A = int(pieces[3]) # Computes B and then the secret. b = random.randint(0, g - 1) B = dh.modexp(g, b, p) secret = dh.modexp(A, b, p) # Perform our side of the exchange, sending B to the client # with the same format. messageForClient = 'BEGIN\n%s\nEND' % str(B) clientsocket.send(messageForClient.encode()) return secret
def DHExchangeClient(serverHost, port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((serverHost, port)) # Usual parameters as recommended by NIST. pHex = ('ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff') p = int(pHex, 16) g = 2 a = random.randint(0, p - 1) A = dh.modexp(g, a, p) B = 0 # Sends the message in the predefined format. message = 'BEGIN\n%s\n%s\n%s\nEND' % (str(p), str(g), str(A)) sock.send(message.encode()) # Gets a similar message back from the server. See the comments # on dh_server which has a similar loop. exchange = b'' while b'D' not in exchange: exchange += sock.recv(100) exchange = exchange.decode() pieces = exchange.split('\n') B = int(pieces[1]) secret = dh.modexp(B, a, p) print('My secret is', str(secret)) VerifyKey(sock, secret) sock.close()
def SRPDictionaryAttack(clientsocket): # The server needs to know at least g and N, basic parameters of the protocol, # for this to work, since they are both used several times below. g = 2 #k = 3 N = int( 'ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e340' '4ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f40' '6b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8f' 'd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff', 16) # Random salt. salt = str(random.randint(1, 100000)).encode() # Do all the communication with the client upfront (minus the final "yes or # no" from the server) so we have the client's digest to compare with our # own. # Note that this is only possible because the computation of B does not # depend on the password digest itself. email = ReadUntilNewline(clientsocket) A = ReadUntilNewline(clientsocket) b = random.randint(1, 10000) # The challenge mentions to have an arbitrary value for B, but it has # to be this one or the S differs between client and server, and therefore # the password digests never match. # Anyway B depends on b which is random, and g and N which are protocol # parameters. B = dh.modexp(g, b, N) clientsocket.send(salt + b'\n') clientsocket.send(str(B).encode() + b'\n') u = random.getrandbits(128) clientsocket.send(str(u).encode() + b'\n') clientDigest = clientsocket.recv(64) # Most systems have /usr/share/dict/words, but here that contains bytes, # while this has the usual "one string per line" format. with open('/usr/share/dict/cracklib-small', 'r') as w: # For each password, compute the final digest and compare with the # digest received by the client. If we find a match we cracked the # password, otherwise the client was smart enough not to pick a # password that can be broken with a dictionary attack. for p in w.readlines(): password = p.strip().encode() sha = hashlib.sha256() sha.update(salt) sha.update(password) xhash = sha.hexdigest() x = int(xhash, 16) v = dh.modexp(g, x, N) S = dh.modexp((int(A) * dh.modexp(v, u, N)), b, N) sha = hashlib.sha256() sha.update(str(S).encode()) K = sha.hexdigest().encode() sha = hashlib.sha256() sha.update(salt) sha.update(K) digest = sha.hexdigest().encode() if clientDigest == digest: print('Cracked password:'******'Unable to crack password, sorry.')