def test_mt19937(s): seed = 0xdeadbeef mt = mt19937(seed) random.seed(seed) s.assertEqual(mt.next(), 956529277) s.assertEqual(mt.next(), 3842322136) s.assertEqual(mt.next(), 3319553134) s.assertEqual(mt.next(), 1843186657) s.assertEqual(mt.next(), 2704993644) d = [] for _ in xrange(624): d += [random.getrandbits(32)] mt = prngutil.crack_mt19937(d) for x in xrange(624): s.assertEqual(mt.next(), d[x]) for x in xrange(624): s.assertEqual(mt.next(), random.getrandbits(32)) for x in xrange(624): mt.prev() for x in d[::-1]: s.assertEqual(mt.prev(), x) mt = mt19937(seed) rand = [mt.next() for _ in xrange(624)] s.assertEqual( prngutil.crack_mt19937_using_index_difference( rand[227], rand[0], 227, 0), [seed])
def crack_mt19937(random_bits): """ Attack to MT19937 : Known Random-bits Args: random_bits : A list of 624 random elements Return: mt19937 class object """ from scryptos.crypto import mt19937 assert len(random_bits) == mt19937.N mt = mt19937(state=list(map(mt19937.untempering, random_bits))) return mt
def crack_mt19937_using_index_difference(mA, mB, idxA, idxB): """ Attack to MT19937 : Guess initial state and seed cracking Args: mA : A generated random value 1 mB : A generated random value 2 idxA : An index of `mA` idxB : An index of `mB` Return: Seed Candidates See: Scrapbox [Mersenne Twister] """ from scryptos.math import modinv from scryptos.crypto import mt19937 assert (idxA + 397) % 624 == idxB # untempering mA_ = mt19937.untempering(mA) mB_ = mt19937.untempering(mB) res = [] y_ = (mA_ ^ mB_) # Guess LSB for lsb in [0, 1]: y = y_ if lsb == 1: y ^= mt19937.MATRIX_A y = (y << 1) & 0xffffffff if lsb == 1: y |= 1 # Guess MSB of mt[idxA] and mt[idxA+1] invMult = modinv(0x6c078965, mt19937.MOD) for msb_mA in [0, 1]: for msb_mC in [0, 1]: mC = y ^ (msb_mA << 31) ^ (msb_mC << 31) x = mC for i in range(idxA + 1, 0, -1): x = ((x - i) * invMult) % mt19937.MOD x = x ^ (x >> 30) res += [x] ret = set() for seed in res: mt = mt19937(seed=seed) rand = [mt.next() for _ in range(max(idxA, idxB) + 1)] if mA in rand and mB in rand: ret.add(seed) return sorted(map(int, ret))