Turing Back End Engineering: Mod 1 final project, Enigma
Clone repo down, and use CL arguments to encrypt
, decrypt
, and crack
messages.
$ ruby ./lib/encrypt.rb message.txt encrypted.txt
Where message.txt
is the only file you are manually creating beforehand. A key will be randomly generated, and the date will be the day the command is run. Resulting encoded message will be saved in encrypted.txt
$ ruby ./lib/decrypt.rb encrypted.txt decrypted.txt key date
Keys are 5 characters, dates are 6 (ddmmyy).
Decrypted text will be saved in decrypted.txt
$ ruby ./lib/crack.rb encrypted.txt cracked.txt date
Creates cracked.txt
file with decrypted text from the encrypted.txt
file.
Got through all functionality, including the Enigma#crack
method and the corresponding CLI interface.
After some painstaking debugging, I discovered that the autosave function on Atom was adding a newline character to the end of my encrypted message text files, which was throwing off the algorithm for #crack
. I fixed it with a chomp!
at the end of the method that produced the message.
Before getting to this point, it was a long journey to figure out the #crack
method. I'd hit a wall after I was able get the method to crack the encrypted text, without using a date or a key, but was unable to get it to produce said key.
Eventually I returned to my original idea, which was to employ brute force (yay computational power!). Thanks, @timomitchel This worked, after I implemented it properly, of course (ha!).
This is the category I probably have the most difficulty with because I don't have enough experience to tell if my design choices actually make sense in the grand scheme of things, although I can explain them.
For this project, I created 4 classes: EnigmaRunner, Enigma, Cipher, and Key
.
-
EnigmaRunner
holds all the File I/O work that makes the CL interface work. It inherits fromEnigma
in order to access the#encrypt, #decrypt, and #crack
methods. -
Enigma
holds the three main methods mentioned above, which call on the parent classCipher
to access the methods that actually do the character shifting and key cracking. The methods inEnigma
return the required hash with info for each cipher. -
Enigma
inherits fromCipher
because it is a type of cipher. The shifting methods found inCipher
could be hypothetically used for other ciphers. -
Cipher
employs the use of theEncryptable
module, who's only function is to prepare the given data (message provided, key, and date) for encryption, decryption, or cracking. Again, these prep methods could be used for a variety of hypothetical cipher classes. -
The
Encryptable
module makes use of theKey
class to create a random key (in case one is not provided), and generate today's date in the required format (if a date is not provided). It's also in charge of divvying up the given message into arrays of 4 characters each, for ease of translation. Finally, this is also the place where the shifts used are created using key and date info. -
The
Key
class is small, but is in charge of holding an array of strings representing possible keys from"00000"
to"99999"
.Key::make
samples this array to generate a random key. As that array is stored in a constant,NUMS
, we can access it from theCipher
class (viaEncryptable
) to iterate through when forcibly cracking unknown keys.
The designer in me likes to make empty lines are placed where they make sense... :)
All methods are under 10 lines (I think the longest is 8).
All methods in Cipher
were refactored multiple times to ensure simplicity and reduce redundancy where possible.
Of particular note (in my newb opinion) is where I used each_with_index
to iterate over an array of ranges corresponding to the indices of a given key. (This is in Encryptable
) I was able to take the index corresponding to a particular range to create a hash that held the shifts for that particular key/date combo. The indices 0..3
were converted to strings and used as keys in said hash, and corresponded to a..d
"shifts".
I also used #rotate
and #zip
for my original #crack
method that would decrypt a message without a key or date. That method survives in the process gist I kept throughout the project.
I used TDD to create the Enigma
, Cipher
, and Key
classes. Spec sheet said we didn't have to test our CLI methods, and because of this, I chose not to create a EnigmaRunner
test file. I did try using mocks/stubs at first to make this test file work, but I found my efforts weren't really worthwhile, IMO.
I did use stubs in my Key
tests, however, and Simplecov shows 100%
coverage.
Not sure if this category should be a 3 or 4 as I'm unclear about the whole CLI testing situation.
67 commits, 12 branches, and 13 PR's. I also left myself process/change summary comments on most PR's (for documentation). Branches were separated by major features/functionality.