Attempts to find the key by using frequency analysis on the resulting plaintexts.

Best key lengths are estimated using the hamming distance of blocks of keylength bytes. Ciphertext is then transposed in such a way that it can be solved by sequences of SingleByteXor (one for each offset in the key).

min_keylength and max_keylength are limits as to what key lengths are tested. considered_keylength_count is the number of best key lengths that are kept to be analysed by the SingleByteXor frequency analysis.

Property definitions

crapto :: xor $ RepeatingKeyXorCipher :: find_key
	# Attempts to find the key by using frequency analysis on the resulting plaintexts.
	# Best key lengths are estimated using the hamming distance of blocks of keylength bytes.
	# Ciphertext is then transposed in such a way that it can be solved by sequences of
	# SingleByteXor (one for each offset in the key).
	#
	# `min_keylength` and `max_keylength` are limits as to what key lengths are tested.
	# `considered_keylength_count` is the number of best key lengths that are kept to be
	# analysed by the SingleByteXor frequency analysis.
	fun find_key(min_keylength, max_keylength, considered_keylength_count: nullable Int)  do

		# Set default values
		if min_keylength == null then min_keylength = 2
		if max_keylength == null then max_keylength = 40
		if considered_keylength_count == null then considered_keylength_count = 3

		# Find the best candidate key lengths based on the normalized hamming distances
		var best_sizes = get_normalized_hamming_distances(min_keylength, max_keylength, considered_keylength_count)

		var best = 0.0
		var best_key: nullable Bytes = null
		for ks in best_sizes do

			# Rearrange ciphertext to be in SingleByteXORable blocks
			var transposed = transpose_ciphertext(ks)

			var key = new Bytes.empty
			for slot in transposed do
				var sbx = new SingleByteXorCipher
				sbx.ciphertext = slot
				sbx.find_key
				key.add sbx.key
			end

			# Evaluate the resulting plaintext based on english frequency analysis
			var eng_score = ciphertext.xorcipher(key).to_s.english_scoring
			if eng_score > best then
				best_key = key
				best = eng_score
			end

			assert best_key != null
			self.key = best_key

		end
	end
lib/crapto/xor.nit:52,2--96,4