def sha1_mac(message): keys = [] with open("/usr/share/dict/words", "r") as fd: for line in fd: keys.append(line.rstrip()) key = random.choice(keys).encode() signature = hash.sha1(key + message) return signature, key
def verify_signature(signature: tuple, msg: str, pub_key: tuple) -> bool: p, alpha, beta = pub_key hashed = int(hash.sha1(msg), 16) r, s = signature if 0 >= r or r >= p or 0 >= s or s >= p - 1: return False return pow(alpha, hashed, p) == (pow(beta, r, p) * pow(r, s, p)) % p
def do_work(filename, list_data, pkgname_parent="", flag_delete=False): logger_do_work = logging.getLogger("do_work") l = [] for sub_filename in walk_dir(filename): if os.path.islink(sub_filename): os.unlink(sub_filename) logger_do_work.debug('unlink %s' % sub_filename) continue #FIXME: 判断解压临时存储位置是否能放得下 #TODO: 考虑分片读取数据降低内存压力 file_bindata = open(sub_filename, 'rb').read() d_md5 = hash.md5(file_bindata) d_sha1 = hash.sha1(file_bindata) d_sha256 = hash.sha256(file_bindata) filesize = os.stat(sub_filename).st_size cmd = 'file "%s" | cut -c %s-' % (sub_filename, len(sub_filename) + 3) logger_do_work.debug(cmd) filetype = os.popen(cmd).read().strip() if os.path.isfile(filename): t_filename = sub_filename[sub_filename.index(pkgname_parent) + len(pkgname_parent):] else: t_filename = sub_filename.partition(filename)[2] if is_pack(sub_filename): dir_temp = o_unpack.unpack(sub_filename) pkg_info = (t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype) logger_do_work.debug("recursive do_work start: %s", t_filename) ll = do_work(dir_temp, list_data, t_filename, flag_delete=True) logger_do_work.debug("recursive do_work end: %s", t_filename) d = {} d[pkg_info] = ll l.append(d) else: l.append((t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype)) if flag_delete: removefiles(sub_filename) else: if flag_delete: removefiles(filename) return l
def sign(msg: str, priv_key: tuple, pub_key: tuple) -> tuple: p, a = priv_key alpha = pub_key[1] hashed = int(hash.sha1(msg), 16) s = 0 r = 0 while s == 0: k = 1 while k < 2 or gcd(k, p - 1) != 1: k = secrets.randbelow(p - 1) r = pow(alpha, k, p) s = ((hashed - a * r) * pow(k, -1, p - 1)) % (p - 1) return (r, s)
def extendSha1MacedMessage(message, authentication, extension, verifier): h4 = authentication & (2**32-1) h3 = authentication>>32 & (2**32-1) h2 = authentication>>64 & (2**32-1) h1 = authentication>>96 & (2**32-1) h0 = authentication>>128 & (2**32-1) guessedKeyLen = 0 while True: #Measured in bytes, not bits extraLength = ((len(message)+guessedKeyLen+64)/64)*64 newMac = hash.sha1(extension, h0, h1, h2, h3, h4, extraLength) newMessage = padMessageForKeyLength(message, guessedKeyLen)+extension if verifier(newMessage, newMac): return (newMessage, newMac) guessedKeyLen += 1
def do_work(filename, list_data, pkgname_parent="", flag_delete=False): logger_do_work = logging.getLogger("do_work") l = [] for sub_filename in walk_dir(filename): if os.path.islink(sub_filename): os.unlink(sub_filename) logger_do_work.debug('unlink %s' % sub_filename) continue #FIXME: 判断解压临时存储位置是否能放得下 #TODO: 考虑分片读取数据降低内存压力 file_bindata = open(sub_filename, 'rb').read() d_md5 = hash.md5(file_bindata) d_sha1 = hash.sha1(file_bindata) d_sha256 = hash.sha256(file_bindata) filesize = os.stat(sub_filename).st_size cmd= 'file "%s" | cut -c %s-' % (sub_filename, len(sub_filename)+3) logger_do_work.debug(cmd) filetype =os.popen(cmd).read().strip() if os.path.isfile(filename): t_filename = sub_filename[sub_filename.index(pkgname_parent)+len(pkgname_parent):] else: t_filename = sub_filename.partition(filename)[2] if is_pack(sub_filename): dir_temp = o_unpack.unpack(sub_filename) pkg_info = (t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype) logger_do_work.debug("recursive do_work start: %s", t_filename) ll = do_work(dir_temp,list_data, t_filename, flag_delete=True) logger_do_work.debug("recursive do_work end: %s", t_filename) d = {} d[pkg_info] = ll l.append(d) else: l.append((t_filename, pkgname_parent, d_md5, d_sha1, d_sha256, filesize, filetype)) if flag_delete: removefiles(sub_filename) else: if flag_delete: removefiles(filename) return l
def main(): """ Test the algorithm """ # create original signature msg = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon" sign_orig, key = sha1_mac(msg) # create a forged signature ending with exploit exploit = b";admin=true" forgery = [] # we don't know the key length, so the padding size must be bruteforced for key_len in range(1, 0x20): dummy_key = b"A" * key_len pad1 = mdpadding(dummy_key + msg) pad2 = mdpadding(dummy_key + msg + pad1 + exploit) assert (len(exploit + pad2) == 64) # send message to server with exploit message = msg + pad1 + exploit # now find the hash of our exploit to ensure it's valid new_h = sha1_states(sign_orig) state = hash._process_chunk(exploit + pad2, *new_h) signature = '%08x%08x%08x%08x%08x' % state forgery.append((signature, message)) # send forgeries to 'server'. Check signature is correct for signature, message in forgery: validation = hash.sha1(key + message) if validation == signature: print("Valid Sha1 Mac: ", message) print("Signature", signature) sys.exit() print("No successful forgeries created.")
message = int(splitLine[1], 16) signedMessages.append((message, signature)) #Find a pair of messages with matching r - indicates same k firstMessage = None secondMessage = None for message1 in signedMessages: for message2 in signedMessages: if message1 != message2: #If identical r if message1[1][0] == message2[1][0]: firstMessage = message1 secondMessage = message2 break if firstMessage is not None: break sharedK = extractK(firstMessage[0], firstMessage[1], secondMessage[0], secondMessage[1], pubKey) privKey = recoverKey(sharedK, firstMessage[1], firstMessage[0], pubKey) expectedKeyHash = 0xca8f6f7c66fa362d40760d135b763eb8527d3d52 keyHash = hash.sha1(hex(privKey)[2:-1]) print keyHash == expectedKeyHash
def starthandshake( self ): #encrypt username with atm public key, and send it back (deny connection if username doesnt exist) self.client, self.clientaddr = self.s.accept() clienthello = self.client.recv(1024) clienthello = clienthello.decode('utf-8').split('-') atmprefs = json.loads(clienthello[0]) print("ATM has initiated handshake, hello to BANK server!") # Parse hello message to select which PKC to use atmprefs = [x.lower() for x in atmprefs] common = list(set(self.methods) & set(atmprefs)) scheme = None if len(common) == 0: self.client.close() raise Exception("no common methods between atm/bank") else: scheme = common[0] print( f"Handshake info --> common encryption scheme set to use {scheme}") # Load correct keys for selected system keypairs = None if scheme == "rsa": keypairs = rsa.load_keys("local_storage/bank-rsa.txt", 4096) else: keypairs = elgamal.load_keys("local_storage/bank-elgamal.txt", 1024) pubkey = keypairs[0] privkey = keypairs[1] # Tell atm which scheme to use self.client.send(scheme.encode('utf-8')) # Begin Diffie-Hellman print("Handshake info --> recieving client random") clirand = self.client.recv(4096).decode('utf-8') print( "Handshake info --> signing client random, server random, and DH parameters" ) dhprivateaes = secrets.randbelow(((self.p - 1) // 2) + 1) dhprivatemac = secrets.randbelow(((self.p - 1) // 2) + 1) # Generate our DH values for both aes key and mac key. Send to client along with their values to ensure we received it properly clisign = str(clirand) + '-' + str(pow( 2, dhprivateaes, self.p)) + '-' + str(pow(2, dhprivatemac, self.p)) # Sign the message so atm knows it came from bank clie = None if scheme == 'rsa': clie = rsa.sign(clisign, privkey) else: clie = elgamal.sign(clisign, privkey, pubkey) self.client.send(str(clisign).encode('utf-8')) print( f"Handshake info --> client says {self.client.recv(4096).decode('utf-8')}" ) self.client.send(str(clie).encode('utf-8')) print( f"Handshake info --> client says {self.client.recv(4096).decode('utf-8')}" ) self.client.send("breaker".encode('utf-8')) #formatting # Use the DH values sent from atm previously to calculate the keys cliplain = clirand.split('-') self.aeskey = pow(int(cliplain[0]), dhprivateaes, self.p) % pow(2, 256) self.mackey = pow(int(cliplain[1]), dhprivatemac, self.p) % pow(2, 256) self.aeskey = format(self.aeskey, '064x') self.mackey = format(self.mackey, '064x') print( "Handshake info --> bank calculated aes/mac keys from DH exchange") print( f"Handshake info --> Bank ready to go, atm replied {aes.decrypt(self.client.recv(1024).decode('utf-8'),self.aeskey)}" ) # Tell client we have the keys self.client.send((aes.encrypt("finished", self.aeskey)).encode('utf-8')) # Challenge client to see if they're an ATM client_keyname = aes.decrypt( self.client.recv(1024).decode('utf-8'), self.aeskey) challenge = format(secrets.randbits(20 * 8), '040x') try: if scheme == 'rsa': client_pubkey = rsa.load_public_key( f"local_storage/{client_keyname}-rsa.pub") challenge_encrypted = rsa.encrypt(challenge, client_pubkey) else: client_pubkey = elgamal.load_public_key( f"local_storage/{client_keyname}-elgamal.pub") challenge_encrypted = elgamal.encrypt(challenge, client_pubkey) except: self.client.close() raise Exception('client identifier is invalid') self.client.send( aes.encrypt(str(challenge_encrypted), self.aeskey).encode('utf-8')) client_response = aes.decrypt( self.client.recv(1024).decode('utf-8'), self.aeskey) if client_response != hash.sha1(challenge + self.aeskey): self.client.close() raise Exception("client is not an atm") self.post_handshake()
import hash block_a = hash.sha1("IV") block_b = hash.sha1(a) block_c = hash.sha1(b) block_d = hash.sha1(c) block_e = hash.sha1(d) # Chain of block hashes print(e)
x = recoverKey(k, signature, messageHash, pubKey) testSignature = dsa.signMessageWithK(k, messageHash, x, p, q, g) if testSignature == signature: return (p, q, g, x) k += 1 if __name__ == "__main__": message = '''For those that envy a MC it can be hazardous to your health So be friendly, a matter of life and death, just like a etch-a-sketch''' pubKey, privKey = dsa.generateKeys() signature, k = dsa.signMessage(message, privKey, leakK = True) #Test of key recovery assert privKey[3]== recoverKey(k, signature, hash.sha1(message), pubKey) #Discover challenge key ''' The provided digest for the message does not match the output of my SHA-1 function or the library SHA-1 function. I have therefore concluded that this is not a problem with my implementation. ''' messageHash = 0xd2d0714f014a9784047eaeccf956520045c45265 signature = (548099063082341131477253921760299949438196259240, 857042759984254168557880549501802188789837994940) p, q, g = dsa.STANDARD_PARAMS pubKey =(p, q, g, 0x84ad4719d044495496a3201c8ff484feb45b962e7302e56a392aee4abab3e4bdebf2955b4736012f21a08084056b19bcd7fee56048e004e44984e2f411788efdc837a0d2e5abb7b555039fd243ac01f0fb2ed1dec568280ce678e931868d23eb095fde9d3779191b8c0299d6e07bbb283e6633451e535c45513b2d33c99ea17) privKey = bruteForceKey(messageHash, signature, pubKey)
def getAESKeyFromSharedSecret(sharedSecret): return convert.intToByteString(hash.sha1(convert.intToByteString(sharedSecret)))[0:16]
continue print maxMessage return (returnMessage, returnIV) if __name__ == "__main__": counterPart = DHEchoer() privateKey = dh.generatePrivateKey(dh.STANDARD_P) counterPart.sendGroupParameters(dh.STANDARD_P, dh.STANDARD_G) publicValue = counterPart.sendPublicDHValue(dh.generatePublicValue(privateKey, dh.STANDARD_G, dh.STANDARD_P)) sharedSecret = dh.deriveSecret(publicValue, privateKey, dh.STANDARD_P) aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(sharedSecret)))[0:16] aesIV = aes.generateRandomKey() returnMessage, returnIV = counterPart.sendAESMessage(aes.aesCBCEncrypt("Test Message", aesKey, aesIV), aesIV) print aes.aesCBCDecrypt(returnMessage, aesKey, returnIV) #Now for the MITM attack # g = 1 newCounterpart = PAlteringDHMITM(counterPart, 1, [1]) newCounterpart.sendGroupParameters(dh.STANDARD_P, dh.STANDARD_G) publicValue = newCounterpart.sendPublicDHValue(dh.generatePublicValue(privateKey, dh.STANDARD_G, dh.STANDARD_P)) sharedSecret = dh.deriveSecret(publicValue, privateKey, dh.STANDARD_P)
def sign(msg: str, priv_key: tuple) -> int: hashed = int(hash.sha1(msg), 16) return pow(hashed, priv_key[1], priv_key[0])
def post_handshake( self): #takes in user input to interact with bank indefinitely # Generate random starting counter value and send it to the bank self.counter = secrets.randbelow(pow(2, 2048)) sendstr = str(self.counter) sendstr = aes.encrypt( str(self.counter) + "-" + hash.hmac(sendstr, self.mackey), self.aeskey) self.s.send(sendstr.encode('utf-8')) # Ensure bank correctly received our counter bankret = self.s.recv(99999).decode('utf-8') bankret = aes.decrypt(bankret, self.aeskey) bankret = bankret.split('-') try: self.countercheck(bankret) except Exception as e: print(str(e)) self.s.close() return chkhash = bankret[-1] bankret.remove(chkhash) againsthash = '-'.join(bankret) bankret = bankret[1:] # Check if bank return message was modified if hash.hmac(againsthash, self.mackey) != chkhash: print("bank return msg integrity compromised") self.s.close() return print(f"Counter set, bank replied with '{bankret[0]}'") print("ATM") # User does not start logged in, so get their sign in credentials username = "" password = "" while True: print("Please log in") # Get credentials from user username = input("username: "******"password: "******"-" + hash.hmac(sendstr, self.mackey), self.aeskey) self.s.send(sendstr.encode('utf-8')) bankret = self.s.recv(99999).decode('utf-8') #parse this out bankret = aes.decrypt(bankret, self.aeskey) bankret = bankret.split('-') # Ensure not some sort of replay try: self.countercheck(bankret) except Exception as e: print(str(e)) continue chkhash = bankret[-1] bankret.remove(chkhash) againsthash = '-'.join(bankret) bankret = bankret[1:] # Ensure message hasn't been tampered with if hash.hmac(againsthash, self.mackey) != chkhash: print("bank return msg integrity compromised") continue print(f"bank responded with '{bankret[2]}' to the login attempt") if bankret[2] == "login successful": break print("\nExample withdraw: 'withdraw [positive_int]'") print("Example deposit: 'deposit [positive_int]'") print("Example check: 'check balance'") print("To close ATM, type q") print("---------------------------------------------------") while True: inp = input("command: ") inp = inp.strip() if inp == 'q': break # Start packet with username sendstr = username + '-' inp = inp.split(' ') # All atm operations require 2 parameters, so check that first if len(inp) != 2: print("not a valid operation supported by bank") continue # Parse user input if inp[0].lower() == 'withdraw': sendstr += inp[0].lower() elif inp[0].lower() == 'deposit': sendstr += inp[0].lower() elif inp[0].lower() == 'check': sendstr += inp[0].lower() else: print("not a valid operation supported by bank") continue # Ensure number is positive, if it is a number if inp[1].isnumeric() and int(inp[1]) > 0: sendstr += '-' + inp[1] elif inp[0].lower() == 'check' and inp[1].lower() == 'balance': sendstr += '-' + inp[1] else: print("invalid money amount") continue sendstr = str(self.counter) + '-' + sendstr sendstr = aes.encrypt( sendstr + "-" + hash.hmac(sendstr, self.mackey), self.aeskey) self.s.send(sendstr.encode('utf-8')) # Get bank's response to our request bankret = self.s.recv(99999).decode('utf-8') #parse this out bankret = aes.decrypt(bankret, self.aeskey) bankret = bankret.split('-') # Ensure not replay try: self.countercheck(bankret) except Exception as e: print(str(e)) continue chkhash = bankret[-1] bankret.remove(chkhash) againsthash = '-'.join(bankret) bankret = bankret[1:] # Check if message tampered with if hash.hmac(againsthash, self.mackey) != chkhash: print("bank return msg integrity compromised") continue print( f"bank responded with '{bankret[2]}' to the request, money in account: {bankret[1]}" ) self.s.close()
def starthandshake(self): # Send supported PKCs as a hello packet self.s.send((str(json.dumps(self.prefs))).encode('utf-8')) bankhello = self.s.recv(4096) scheme = bankhello.decode('utf-8') # Parse bank response to see which PKC to use if scheme == "rsa": keypairs = rsa.load_keys("local_storage/atm-rsa.txt", 4096) bankpubkey = rsa.load_public_key( "local_storage/bank-rsa.txt" ) # simulates the bank's public keys being hardcoded into the atm. This way if we chose to reset the bank key, we don't have to update this else: keypairs = elgamal.load_keys("local_storage/atm-elgamal.txt", 2048) bankpubkey = elgamal.load_public_key( "local_storage/bank-elgamal.txt") # see above pubkey = keypairs[0] privkey = keypairs[1] # Begin Diffie-Hellman print("Handshake info --> sending client random") # Generate random numbers and send to bank dhprivateaes = secrets.randbelow(((self.p - 1) // 2) + 1) dhprivatemac = secrets.randbelow(((self.p - 1) // 2) + 1) dh_message = str(pow(2, dhprivateaes, self.p)) + '-' + str( pow(2, dhprivatemac, self.p)) self.s.send(dh_message.encode('utf-8')) # Get the bank's response clirandplain = self.s.recv(99999).decode('utf-8') self.s.send("recieved plaintext signature".encode('utf-8')) # Get the bank's signature to prove it sent the previous response clirandsign = self.s.recv(4096).decode('utf-8') # Verify the signature to ensure bank sent the message if scheme == 'rsa': clirandsign = rsa.verify_signature(int(clirandsign), clirandplain, bankpubkey) else: clirandsign = clirandsign.strip("(").strip(")").split(",") clirandsign = [x.strip() for x in clirandsign ] #take away tuple space or wierd stuff clirandsign = (int(clirandsign[0]), int(clirandsign[1])) clirandsign = elgamal.verify_signature(clirandsign, clirandplain, bankpubkey) clirandplain = clirandplain.split('-') # Make sure the signature verified, and ensure our DH numbers were received by the bank properly if clirandsign and (clirandplain[0] + '-' + clirandplain[1]) == dh_message: self.s.send("signature verify success".encode('utf-8')) else: self.s.send("signature verify failed".encode('utf-8')) self.s.close() raise Exception("signature verify failed") self.s.recv(4096) #formatting # The bank got our DH numbers correctly and sent its own, so calculate keys print( "Handshake info --> bank signature verified, DH parameters recieved" ) self.aeskey = pow(int(clirandplain[-2]), dhprivateaes, self.p) % pow( 2, 256) self.mackey = pow(int(clirandplain[-1]), dhprivatemac, self.p) % pow( 2, 256) self.aeskey = format(self.aeskey, '064x') self.mackey = format(self.mackey, '064x') print( "Handshake info --> atm calculated aes/mac keys from DH exchange") # Tell bank that we have the keys and are ready to use AES self.s.send((aes.encrypt("finished", self.aeskey)).encode('utf-8')) print( f"Handshake info --> ATM ready to go, bank replied {aes.decrypt(self.s.recv(1024).decode('utf-8'),self.aeskey)}" ) # Prove to bank that we're actually an ATM # Tell the atm what our keys should be saved as self.s.send( aes.encrypt(f'atm{self.id_num}', self.aeskey).encode('utf-8')) # Receive a random number from the bank that is encrypted to our public key bank_challenge = aes.decrypt( self.s.recv(4096).decode('utf-8'), self.aeskey) # Decrypt the random number if scheme == 'rsa': response = rsa.decrypt(int(bank_challenge), privkey) else: bank_challenge = bank_challenge.strip('(').strip(')').split(',') bank_challenge = [int(c) for c in bank_challenge] response = elgamal.decrypt(bank_challenge, privkey) # Send back the hash of the random number and our encryption key to prove that we are the atm we said we are response = hash.sha1(response + self.aeskey) self.s.send(aes.encrypt(response, self.aeskey).encode('utf-8')) self.post_handshake()
def sendPublicDHValue(self, A, p, g): self.sharedSecret = 0 self.aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(self.sharedSecret)))[0:16] self.realDestination.sendPublicDHValue(p, p, g) return p
def sendPublicDHValue(self, A, p, g): self.privateKey = dh.generatePrivateKey(p) self.sharedSecret = dh.deriveSecret(A, self.privateKey, p) self.aesKey = convert.intToByteString(hash.sha1(convert.intToByteString(self.sharedSecret)))[0:16] return dh.generatePublicValue(self.privateKey, g, p)
def main(): a = input() print(hash.sha1(a.encode('utf-8 '))) """ Attempt to break hash
def verify_signature(signature: int, msg: str, pub_key: tuple) -> bool: hashed = int(hash.sha1(msg), 16) return hashed == pow(signature, pub_key[1], pub_key[0])