{"id":15554450,"url":"https://github.com/markertmer/enigma","last_synced_at":"2026-06-12T00:31:15.386Z","repository":{"id":44933047,"uuid":"447763169","full_name":"markertmer/enigma","owner":"markertmer","description":"Command-line tool for encryption \u0026 decryption of text","archived":false,"fork":false,"pushed_at":"2022-03-29T14:38:33.000Z","size":170,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-28T10:37:38.090Z","etag":null,"topics":["command-line-tool","encryption","inheritance"],"latest_commit_sha":null,"homepage":"https://enigma-encryption-app.herokuapp.com/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markertmer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-13T21:53:02.000Z","updated_at":"2022-04-08T13:41:06.000Z","dependencies_parsed_at":"2022-09-03T01:10:22.601Z","dependency_job_id":null,"html_url":"https://github.com/markertmer/enigma","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/markertmer/enigma","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markertmer%2Fenigma","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markertmer%2Fenigma/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markertmer%2Fenigma/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markertmer%2Fenigma/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markertmer","download_url":"https://codeload.github.com/markertmer/enigma/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markertmer%2Fenigma/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34224103,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line-tool","encryption","inheritance"],"created_at":"2024-10-02T15:01:31.734Z","updated_at":"2026-06-12T00:31:15.194Z","avatar_url":"https://github.com/markertmer.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Enigma\nThis encryption program was built based on the requirements of the [Enigma](https://backend.turing.edu/module1/projects/enigma/index) project from [Turing School of Software and Design](https://turing.edu/).\nIt was submitted by Mark Ertmer (2111 BE) in January 2022 as the Final Project for Mod 1.\n\nAn interactive web version of this app can be found here: https://enigma-encryption-app.herokuapp.com/\n\n### Table of Contents\n* [About](#about-this-application)\n* [Getting Started](#getting-started)\n* [Encrypting Messages](#encrypting-messages)\n* [Decrypting Messages](#decrypting-messages)\n* [Cracking Encrypted Messages](#cracking-encrypted-messages)\n* [Encryption Algorithm](#encryption-algorithm)\n* [Input Handling](#input-handling)\n* [Exploration: Finding Equivalent Keys](#exploration)\n\n## About this Application\nThis application uses an algorithm to encrypt and decrypt a text-based message with the use of a 5-digit, randomly-generated `key` and the 6-digit numeric `date` of encryption in DDMMYY format. The application is run from the command line, where the user can designate an input file to encrypt/decrypt and an output file to write the resulting encryption/decryption.\n\n## Getting Started\n1. Fork and Clone this repo to your machine.\n2. In your terminal, navigate to the home directory, titled `enigma`.\n\n### Encrypting Messages\nThe command to encrypt a text file follows this structure:\n```\nruby encrypt.rb \u003csource file\u003e \u003coutput file\u003e\n```\n...where the `\u003csource file\u003e` is the filepath to the text you wish to encrypt. The program then writes the encrypted text to the `\u003coutput file\u003e` specified.\n#### EXAMPLE:\n1. You will see there is a `test_message.txt` in the `file` directory. It contains the text:\n   ```\n    Hello, this is a test! Have a super day. end\n   ```\n2. Run this command from your terminal:\n   ```\n   ruby encrypt.rb ./file/test_message.txt ./file/test_encryption.txt\n   ```\n3. The `test_encryption.txt` output is created in the `file` directory with encrypted text that might look something like this:\n   ```\n   inmiuu,hqqo xryhyizmpb!fpydkhyiybmnxhajd.hbwj\n   ```\n4. A confirmation message prints to the terminal, giving the output filepath, along with the `key` and `date`. These two pieces of information will be needed to decrypt the message later.\n   ```\n   Created ./file/test_encryption.txt with the key 32547 and date 170122\n   ```\n\n### Decrypting Messages\nThe command to encrypt a text file follows this structure:\n```\nruby decrypt.rb \u003csource file\u003e \u003coutput file\u003e \u003ckey\u003e \u003cdate\u003e\n```\nAs with `encrypt`, the `decrypt` command takes a source and output file, but also requires the `key` and `date` that were used for the encryption.\n#### EXAMPLE:\n1. To decrypt the message that was encrypted above, enter this command:\n   ```\n   ruby decrypt.rb ./file/test_encryption.txt ./file/test_decipheration.txt 32547 170122\n   ```\n   Notice that the `key` and `date` were taken from the previous example.\n2. `test_decipheration.txt` is created in `file`, and contains the decoded text:\n   ```\n    hello, this is a test! have a super day. end\n   ```\n3. A confirmation prints to the terminal, giving the output filepath, along with the `key` and `date` used:\n   ```\n   Created ./file/test_decipheration.txt with the key 32547 and date 170122\n   ```\n\n### Cracking Encrypted Messages\nIt is possible that an intercepted message could be decoded without a key, provided the following assumptions are correct:\n* The date of encryption is known.\n* The message ends in \" end\".\n\n#### EXAMPLE:\n1. To crack the encrypted message from above, enter this command:\n   ```\n   ruby crack.rb ./file/test_encryption.txt ./file/test_crack.txt 170122\n   ```\n   You'll need to include the source and output files, along with the six-digit `date` believed to be used for encryption.\n2. `test_crack.txt` is created in `file`, and contains the decoded text:\n   ```\n    hello, this is a test! have a super day. end\n   ```\n3. A confirmation prints to the terminal, giving the output filepath, along with the `date` used and cracked `key`.\n   ```\n   Created ./file/test_crack.txt with the cracked key 32547 and date 170122\n   ```\n\n## Encryption Algorithm\n1. The algorithm makes use of a 27-character set which includes all the lowercase letters in the English alphabet plus a space. The program stores this information as an array to allow easy access to each character and its index:\n   ```\n   @characters = (\"a\"..\"z\").to_a \u003c\u003c \" \"\n   ```\n2. The algorithm shifts each character __n__ number of places through the array. For example, an \"a\" shifted 3 places becomes a \"d\". It rolls back from the end of the array, so \"z\" with a shift of 2 becomes \"a\" (remember the set ends with a space).\n3. As the program moves through the message string, different shifts are applied. There is an `A` shift, a `B` shift, a `C` shift, and a `D` shift, which are rotated sequentially (the first character uses the A shift, the second is B, etc.).\n  * The `A` shift key comes from the __first two numbers__ in the key. (__57__034 -\u003e 57)\n  * The `B` shift key comes from the __second and third__ numbers in the key. (5__70__34 -\u003e 70)\n  * The `C` shift key comes from the __third and fourth__ numbers in the key. (57__03__4 -\u003e 03)\n  * The `D` shift key comes from the __fourth and fifth__ numbers in the key. (578__34__ -\u003e 34)\n4. In addition, an _offset_ is applied to each shift key that comes from the six digit date:\n  * Square the date: 170122 * 170122 = 28941494884\n  * Retain the last four digits: 4884\n    * The first digit is the `A` offset: 4\n    * The second digit is the `B` offset: 8\n    * The third digit is the `C` offset: 8\n    * The fourth digit is the `D` offset: 4\n5. The total shift is the sum of the _shift key_ and _offset_ for each letter:\n  * `A` shift = 57 + 4 = 61\n  * `B` shift = 70 + 8 = 78\n  * `C` shift = 03 + 8 = 11\n  * `D` shift = 34 + 4 = 38\n\nNote: Uppercase letters are automatically downcased before encryption, so any decrypted message will not include capitalization.\n\nNote: If the message text includes any symbols that are not included in the character set, such as numbers or punctuation, those symbols are essentially ignored and passed to the output encryption (or decryption, as the case may be) unchanged.\n\n## Input Handling\nTo avoid crashing, the program includes contingencies for the following improper input scenarios when running `encrypt.rb`, `decrypt.rb`, and `crack.rb`:\n* invalid or missing source file and path\n* invalid filepath or missing directory for output file\n* wrong number of arguments\n* invalid key syntax\n* invalid date syntax\n\nIf any of these conditions apply, the program ends after outputting a message to help the user enter a valid command:\n```\nINVALID INPUT\n- Make sure your source file is valid.\n- Make sure to use a valid filepath for your output.\n- The key must be exactly 5 digits, numbers only.\n- Enter a date using 'DDMMYY' formatting. 6 digits, numbers only.\nCOMMAND STRUCTURE:\n$ ruby decrypt.rb \u003csource filepath\u003e \u003coutput filepath\u003e \u003ckey\u003e \u003cdate\u003e\n```\n\n## Exploration\n### Finding Equivalent Keys\nWhile testing my `crack` methods, there were several isolated times when a reliable method failed. The reason was that the `key` found did not match the key used for the original encryption, although it was able to accurately decrypt the message.\n\nI realized that it is possible for more than one key to result in the same effective `A`, `B`, `C`, and `D` shifts, because numbers larger than 27 loop back around. So in other words, a shift of 30 is equivalent to a shift of 3 (because 30 = 27 + 3), or a shift of 71 is equivalent to a shift of 17 (because 71 = 27 + 27 + 17).  \n\nI was curious to see how many such sets of equivalent keys existed in all the possible keys, so I wrote a short script to find out:\n```ruby\nall_keys = (\"00000\"..\"99999\").to_a\nshifts = {}\n\nall_keys.each do |key|\n  shift_keys = {A: key[0..1].to_i, B: key[1..2].to_i, C: key[2..3].to_i, D: key[3..4].to_i}\n  shift_keys.each do |letter, shiftkey|\n    until shiftkey \u003c 27 do\n      shiftkey -= 27\n    end\n    shift_keys[letter] = shiftkey\n  end\n  shifts[shift_keys] ||= []\n  shifts[shift_keys] \u003c\u003c key\nend\n```\n### RESULTS\n* There are 14,760 __pairs of keys__ that can decrypt the same message.\n* There are 1,022 __sets of three__ keys that can decrypt the same message.\n* There is __one__ set of __four keys__ that can decrypt the same message. They are:\n  * 09090\n  * 90909\n  * 36363\n  * 63636\n\n  (Each of these keys results in an `A`, `B`, `C`, and `D` shift of 9)\n\n### IMPLICATIONS FOR PROBABILITY\nOn its face, the chance of guessing a correct 5-digit key appears to be one in 100,000 (all the numbers from 00000 to 99999). However, the chances are somewhat better than that:\n\n* There are 14,760 cases where guessing a key would result in being equivalent to __one__ other: subtract 14,760\n* There are 1,022 cases where guessing a key would result in being equivalent to __two__ other keys: subtract 2,044 (1,022 * 2)\n* There is 1 case where guessing a key would result in being equivalent to __three__ other keys: subtract 3\n\n* 100,000 - 14,760 - 2,044 - 3 = 83,193\n\nAccounting for this, the chance of guessing a correct key for a given encryption becomes one in 83,193.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkertmer%2Fenigma","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkertmer%2Fenigma","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkertmer%2Fenigma/lists"}