return s, statesToIndices[h] def findSecondPreimage(m, hashFn, iv, blockLength, hashLength): blockCount = (len(m) + blockLength - 1) // blockLength k = blockCount.bit_length() prefixState, blocks = makeExpandablePrefix(hashFn, iv, blockLength, k) intermediateStateIter = getIntermediateStates(m, hashFn, iv, blockLength) bridge, collisionBlockCount = findIntermediateStateCollision( hashFn, prefixState, blockLength, hashLength, intermediateStateIter, k) m2 = makeExpandedPrefix(blockLength, blocks, k, collisionBlockCount) + bridge m2 += m[len(m2):] return m2 if __name__ == '__main__': m = get_random_bytes(100) h = challenge52.badHash(m, b'') m2 = findSecondPreimage(m, challenge52.badHash, b'', challenge52.badHashBlockLength, challenge52.badHashHashLength) h2 = challenge52.badHash(m2, b'') print(m, m2, h, h2) if len(m2) != len(m): raise Exception('{0} != {1}'.format(len(m2), len(m))) if h2 != h: raise Exception(h2 + b' != ' + h)
i += 1 if not statesToIndices: raise Exception('unexpected') s, h = findCollisionInSet(hashFn, iv, blockLength, statesToIndices) return s, statesToIndices[h] def findSecondPreimage(m, hashFn, iv, blockLength, hashLength): blockCount = (len(m) + blockLength - 1) // blockLength k = blockCount.bit_length() prefixState, blocks = makeExpandablePrefix(hashFn, iv, blockLength, k) intermediateStateIter = getIntermediateStates(m, hashFn, iv, blockLength) bridge, collisionBlockCount = findIntermediateStateCollision(hashFn, prefixState, blockLength, hashLength, intermediateStateIter, k) m2 = makeExpandedPrefix(blockLength, blocks, k, collisionBlockCount) + bridge m2 += m[len(m2):] return m2 if __name__ == '__main__': m = util.randbytes(100) h = challenge52.badHash(m, b'') m2 = findSecondPreimage(m, challenge52.badHash, b'', challenge52.badHashBlockLength, challenge52.badHashHashLength) h2 = challenge52.badHash(m2, b'') print(m, m2, h, h2) if len(m2) != len(m): raise Exception('{0} != {1}'.format(len(m2), len(m))) if h2 != h: raise Exception(h2 + b' != ' + h)
totalBlockLength += k + 1 totalLength = totalBlockLength * blockLength return hashFn(padFn(b'', totalLength), collisionTree[-1][0][0], pad=False) def forgePrediction(hashFn, iv, padFn, initialStateMap, collisionTree, messageLength, blockLength, m): if len(m) > messageLength: raise Exception('message too big') paddedMessageLength = messageLength + (-messageLength % blockLength) m += b'\x00' * (paddedMessageLength - len(m)) h = hashFn(m, iv, pad=False) glue, h = challenge53.findCollisionInSet(hashFn, h, blockLength, initialStateMap) m += glue suffix = getSuffixFromCollisionTree(initialStateMap, collisionTree, h) m += suffix return m if __name__ == '__main__': k = 5 messageLength = 100 (initialStateMap, collisionTree) = constructCollisionTree(challenge52.badHash, challenge52.badHashBlockLength, challenge52.badHashHashLength, k) prediction = generatePrediction(challenge52.badHash, challenge52.badHashPadMessage, initialStateMap, collisionTree, messageLength, challenge52.badHashBlockLength) print('Prediction', prediction) forgedPrediction = b'Dodgers win the World Series!!' forgedPredictionMessage = forgePrediction(challenge52.badHash, b'', challenge52.badHashPadMessage, initialStateMap, collisionTree, messageLength, challenge52.badHashBlockLength, forgedPrediction) h = challenge52.badHash(forgedPredictionMessage, b'') print('Forged prediction', forgedPredictionMessage, h)