def generatePasswordToken(): mt = MT19937(int(time())) rawOutput = b'' for i in range(6): rawOutput += mt.extract_number().to_bytes(4, byteorder='big') b64Output = rawToBase64(rawOutput) return b64Output
def MTStreamCipher(seed, rawInput): mt = MT19937(seed) rawOutput = b'' mtOut = 0 for i in range(len(rawInput)): if (i % 4 == 0): mtOut = mt.extract_number() thisKey = (mtOut >> (8 * (3 - (i % 4)))) & 0xff rawOutput += (rawInput[i] ^ thisKey).to_bytes(1, byteorder='big') return rawOutput
def cloneMT(dolly): clone = MT19937(0) # Note that the call to extract_number() is going to # call dolly.generate_numbers(), mucking with dolly's MT values # before we get to untemper # thus, the returned clone will be identical to dolly's state after # this function is finished, not before for i in range(624): clone.MT[i] = untemper(dolly.extract_number()) return clone
def recoverSeed(output, timeNow): # we're pretty sure that the seed is in the range (timeNow - 2005, timeNow) # but we'll push the range check out to 10000 just for fun for i in range(10000): #guess seed mt = MT19937(timeNow - i) #check seed if (output == mt.extract_number()): print("Seed: ", timeNow - i) return i print("Failed to recover seed") return -1
def checkPasswordToken(b64Token): rawToken = base64toRaw(b64Token) now = int(time()) for i in range(-100, 100): # +/- one hour mt = MT19937(now + i) mtOutput = b'' for i in range(6): mtOutput += mt.extract_number().to_bytes(4, byteorder='big') if (rawToken == mtOutput): print("MT seed time = ", (now + i)) return (now - i) return (-1)
def randFromTime(): # * Seeds the RNG with the current Unix timestamp mt = MT19937(initialTime + delay1) #* Returns the first 32 bit output of the RNG. return mt.extract_number()
def test_mt(): mt1 = MT19937(8675309) mt2 = MT19937(8675309) for i in range(10000): if (mt1.extract_number() != mt2.extract_number()): print("Fail MT test!")
# generator, and splice that state into a new instance of the MT19937 # generator. def cloneMT(dolly): clone = MT19937(0) # Note that the call to extract_number() is going to # call dolly.generate_numbers(), mucking with dolly's MT values # before we get to untemper # thus, the returned clone will be identical to dolly's state after # this function is finished, not before for i in range(624): clone.MT[i] = untemper(dolly.extract_number()) return clone # How would you modify MT19937 to make this attack hard? What would # happen if you subjected each tempered output to a cryptographic hash? '''The root problem is that one can connect an output value to PRNG state. Preventing an attacker from working backwards (output = sha256(y)) would prevent that... However, given that (y) is 32 bits, the attacker could build a 4-billion-entry table to invert such outputs. A better solution would be to use, say, the last 4 bytes of MT has an AES key, and then have (output = AES(y|000...00, key)). The keyspace prevents the attacker from building the table.''' if __name__ == "__main__": temperTest() dolly = MT19937(8675309) clone = cloneMT(dolly) for i in range(10000): if (dolly.extract_number() != clone.extract_number()): raise Exception("Clone failed") print("Clone succeeded")