Skip to content

Instantly share code, notes, and snippets.

@acabreragnz
Last active November 10, 2017 16:35
Show Gist options
  • Save acabreragnz/87482d5b2ea19086761c8faa1fdd6b17 to your computer and use it in GitHub Desktop.
Save acabreragnz/87482d5b2ea19086761c8faa1fdd6b17 to your computer and use it in GitHub Desktop.
Caesar Cipher, using a different key for each different word (key_seed for word in first place, key_seed + 1 for word in second_place, ...). Also we have a force brute function to find the possible keys
defmodule CryptoSystem do
def encrypt(text, key_seed) do
words = String.split(text, " ");
words
|> Enum.with_index()
|> Enum.map(&encrypt_word(&1, key_seed))
|> Enum.join(" ")
end
defp encrypt_word({word, index}, key_seed) do
current_key = calculate_current_key(index, key_seed)
offset_word(word, current_key)
end
defp offset_word(word, offset) do
(for c <- to_charlist(word), do: c >= 65 && c <= 90 && rem(c - 65 + offset, 26) + 65 || c)
|> List.to_string()
end
defp calculate_current_key(word_position, key_seed) do
current_key = key_seed + word_position
cond do
current_key > 25 -> rem(key_seed + word_position, 26) + 1
current_key -> current_key
end
end
def decrypt(text, key_seed) do
words = String.split(text, " ");
words
|> Enum.with_index()
|> Enum.map(&decrypt_word(&1, key_seed))
|> Enum.join(" ")
end
defp decrypt_word({word, index}, key_seed) do
current_key = calculate_current_key(index, key_seed)
unoffset_word(word, current_key)
end
defp unoffset_word(word, offset) do
(for c <- to_charlist(word), do: c >= 65 && c <= 90 && unoffset_char(c, offset) || c)
|> List.to_string()
end
defp unoffset_char(c, offset) do
calc = rem(c - 65 - offset, 26)
cond do
calc < 0 -> calc + 26 + 65
true -> calc + 65
end
end
def possible_keys(plain_word, encrypted_text) do
encrypted_words = String.split(encrypted_text, " ")
Enum.flat_map(1..25, &in_text_for_key(&1, plain_word, encrypted_words))
|> Enum.reject(&is_nil/1)
|> Enum.uniq()
|> Enum.sort()
end
defp in_text_for_key(key, plain_word, encrypted_words) do
encrypted_word = encrypt(plain_word, key)
index_in_encrypted_text = find_indexes(encrypted_words, encrypted_word)
Enum.map(index_in_encrypted_text, &build_possible_key_if_value(&1, key))
end
defp build_possible_key_if_value(index_in_encrypted_text, key) do
if index_in_encrypted_text != nil, do: build_possible_key(index_in_encrypted_text, key), else: nil
end
defp build_possible_key(position_in_text, tried_key) do
calc = tried_key - position_in_text
if calc <= 0, do: calc + 25, else: calc
end
defp find_indexes(encrypted_word_from_text, word) do
Enum.with_index(encrypted_word_from_text) |> Enum.filter_map(fn {x, _} -> x == word end, fn {_, i} -> i end)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment