enigma_engine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a7993aac6d914e32caaff615000fe8f2fc58eebd
4
+ data.tar.gz: d133d5e09085fa866689d6b04d104ad95d34a455
5
+ SHA512:
6
+ metadata.gz: 912ba2f5bc17c679c7aaf7146726e914352926f5113116e4fcad0f4842a68ed732d574bc4472c75c07e55836ee4745d518aedaab8e9c5ab91a21ffe44b414b15
7
+ data.tar.gz: 87c75bae1d47ec9fe94907a1e6ffbe9e7ee12f6a1b843a5281ae7a66ce3ca8914f6d491ce3aa0fe72e979da15e1a31a32ffd9577b8c5ca0b76166bcefcef6f88
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ repo_token: iopph6rYYZOwJMACVcCZvPgpiWnPzYgQ1
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea/
11
+ /.idea*/
12
+ /.idea/
13
+ *.xml
14
+
data/.rubocop.yml ADDED
@@ -0,0 +1,9 @@
1
+ # This is the configuration used to check the rubocop source code.
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - 'spec/*'
6
+ - 'lib/enigma_engine/version.rb'
7
+ - 'enigma_engine.gemspec'
8
+ TargetRubyVersion: 2.2
9
+
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at simon.peter@andela.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Damian Simon Peter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # EnigmaEngine [![Coverage Status](https://coveralls.io/repos/github/andela-sdamian/enigma_engine/badge.svg?branch=master)](https://coveralls.io/github/andela-sdamian/enigma_engine?branch=master) [![Circle CI](https://circleci.com/gh/andela-sdamian/enigma_engine.svg?style=svg)](https://circleci.com/gh/andela-sdamian/enigma_engine)
2
+
3
+ This is a ruby gem that simulates the Enigma Machine.
4
+ The Enigma Machine is a cipher mechanism created by [Arthur Scherbius](https://en.wikipedia.org/wiki/Arthur_Scherbius) a German Engineer. The machine is capable of transcribing text into coded information as a means of encryption. As of its time during World War II, it was the most sophisticated means of encryption. During the war, both the Allies and the Axis countries were looking for a new way to encrypt messages - a way that would result in complete security this was when the Enigma was born. By the end of World War II [Alan Turing](https://en.wikipedia.org/wiki/Alan_Turing) with the help of is friends where able to crack the enigma which helped Britain and their allies during the war. [More on the Enigma](https://en.wikipedia.org/wiki/Enigma_machine).
5
+
6
+ <img src="http://static.bbc.co.uk/history/img/ic/640/images/resources/topics/enigma.jpg" />
7
+
8
+ ## How the encryption works
9
+
10
+ The inner working of an enigma machine has three rotors, each rotors has wrapped around it the 26 letters. When a key is pressed it moves the rotor ahead one alphabet. The other rotors kick off after the first has completed a revolution and so for the third. When this is done, text in plain english becomes gibberish. Before you start encrypting you and your recipient must agree upon a key which can be set on the machine. Find out more about the enigma machine by watching this video.
11
+
12
+ <a href="http://www.youtube.com/watch?feature=player_embedded&v=G2_Q9FoD-oQ
13
+ " target="_blank"><img src="http://img.youtube.com/vi/G2_Q9FoD-oQ/0.jpg"
14
+ alt="How the Enigma Machine works" width="600" height="350" border="10" /></a>
15
+
16
+ Though, my implementation of the Enigma Machine is slightly different from that of World War II but here is the catch
17
+
18
+ <strong>The rotors: they are denoted by five digit numbers e.g. 97239</strong>
19
+ <ul>
20
+ <li>The first two digits of the key is the "A" rotation (97)</li>
21
+ <li>The second and third digits are the "B" rotation (72)</li>
22
+ <li>The third and fourth digits are the "C" rotation (23)</li>
23
+ <li>The fourth and firth digits are the "D" rotation (39)</li>
24
+ </ul>
25
+
26
+ <strong>The offsets: the date of message transmission is also factored into the encryption</strong>
27
+ <ul>
28
+ <li>Date is in the format DDMMYY e.g. 020315</li>
29
+ <li>Square the numeric form you get 412699225 pick the last four digits</li>
30
+ <li>The first digit is the "A" offset (9)</li>
31
+ <li>The second digit is the "B" offset (2)</li>
32
+ <li>The third digit is the "C" offset (2)</li>
33
+ <li>The fourth digit is the "D" offset (5)</li>
34
+ </ul>
35
+
36
+ <strong>Encrypting a message</strong>
37
+
38
+ <ul>
39
+ <li>Four characters are encrypted at a time</li>
40
+ <li>The first character is rotated forward by the "A" rotation plus the "A offset"</li>
41
+ <li> The second character is rotated forward by the "B" rotation plus the "B offset"</li>
42
+ <li>The third character is rotated forward by the "C" rotation plus the "C offset"</li>
43
+ <li>The fourth character is rotated forward by the "D" rotation plus the "D offset"</li>
44
+ </ul>
45
+
46
+ <strong>Decrypting a message</strong>
47
+
48
+ The offsets and keys can be calculated by the same methods above. Then each character is rotated backwards instead of forwards.
49
+
50
+ <strong>Cracking a message</strong>
51
+ When the key is not known, the offsets can still be calculated from the message date. We believe that each enemy message ends with the characters "..end..". Use that to determine when you’ve correctly guessed the key.
52
+
53
+ ## Installation
54
+
55
+ Add this line to your application's Gemfile:
56
+
57
+ ```ruby
58
+ gem 'enigma_engine'
59
+ ```
60
+
61
+ And then execute:
62
+
63
+ $ bundle
64
+
65
+ Or install it yourself as:
66
+
67
+ $ gem install enigma_engine
68
+
69
+ ## Usage
70
+
71
+ The tool is used from the command line like so:</p>
72
+
73
+ <strong>View Help </strong>
74
+
75
+ `enigma help` To see help file
76
+
77
+ <strong> Encrypting a message</strong>
78
+
79
+ `enigma encrypt [message.txt] [encrypted.txt]`
80
+ created encrypted.txt with key 82648 and date 090216
81
+
82
+ That will take the plaintext file message.txt and create an encrypted file encrypted.txt.
83
+
84
+ <strong> Decrypting a message</strong>
85
+ Then, if we know the key, we can decrypt like so:
86
+
87
+ `enigma decrypt [encrypted.txt] [decrypted.txt] [82648] [030415]`
88
+ created ‘decrypted.txt with key 82648 and date 030415
89
+
90
+ <strong> Cracking a message</strong>
91
+ But if we don’t know the key, we can try to crack it with just the date like so:
92
+
93
+ `enigma crack [decrypted.txt] [cracked.txt] [030415]`
94
+ created ‘cracked.txt with key 82648 and date 030415
95
+
96
+ ## Development
97
+
98
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
99
+
100
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
101
+
102
+ ## Contributing
103
+
104
+ Bug reports and pull requests are welcome on GitHub at https://github.com/andela-sdamian/EnigmaEngine. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
105
+
106
+ ## License
107
+
108
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+ task :default => :spec
@@ -0,0 +1,45 @@
1
+ def colorize(text, color_code)
2
+ "\e[#{color_code}m#{text}\e[0m"
3
+ end
4
+
5
+ def red(text)
6
+ colorize(text, 31)
7
+ end
8
+
9
+ def green(text)
10
+ colorize(text, 32)
11
+ end
12
+
13
+ def blue(text)
14
+ colorize(text, 34)
15
+ end
16
+
17
+ def yellow(text)
18
+ colorize(text, 33)
19
+ end
20
+
21
+ def call_error
22
+ puts red('Arguments error!')
23
+ puts yellow('Run [enigma help] for more info...')
24
+ exit
25
+ end
26
+
27
+ def files_valid?(arr)
28
+ arr.all? { |i| i[-4, 4] == '.txt' }
29
+ end
30
+
31
+ def key_valid?(key)
32
+ key.to_s.length.eql? 5
33
+ end
34
+
35
+ def date_valid?(date)
36
+ date.to_s.length.eql? 6
37
+ end
38
+
39
+ def fields_empty?(arr)
40
+ if arr.include? ''
41
+ true
42
+ elsif arr.nil?
43
+ true
44
+ end
45
+ end
data/bin/enigma ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'enigma_engine'
5
+ require_relative 'console_helpers'
6
+ require 'enigma_engine/crack'
7
+ require_relative 'help'
8
+
9
+ case ARGV[0]
10
+ when 'help'
11
+ show_wait_cursor(3)
12
+ puts @msg_help
13
+ when 'encrypt'
14
+ message = ARGV[1]
15
+ new_file = ARGV[2]
16
+ if fields_empty?([message, new_file])
17
+ raise call_error
18
+ end
19
+
20
+ if files_valid?([message, new_file])
21
+ EnigmaEngine::Engine.new.encrypt(message, new_file)
22
+ else
23
+ raise call_error
24
+ end
25
+ when 'decrypt'
26
+ message = ARGV[1]
27
+ new_file = ARGV[2]
28
+ key = ARGV[3]
29
+ date = ARGV[4]
30
+ if fields_empty?([message, new_file, key, date])
31
+ raise call_error
32
+ end
33
+
34
+ if files_valid?([message, new_file]) && key_valid?(key) && date_valid?(date)
35
+ EnigmaEngine::Engine.new.decrypt(message, new_file, key, date)
36
+ else
37
+ raise call_error
38
+ end
39
+ when 'crack'
40
+ message = ARGV[1]
41
+ new_file = ARGV[2]
42
+ date = ARGV[3]
43
+ if fields_empty?([message, new_file, date])
44
+ raise call_error
45
+ end
46
+
47
+ if files_valid?([message, new_file]) && date_valid?(date)
48
+ EnigmaEngine::Crack.new.crack(message, new_file, date)
49
+ else
50
+ raise call_error
51
+ end
52
+ else
53
+ raise call_error
54
+ end
data/bin/help.rb ADDED
@@ -0,0 +1,56 @@
1
+ require_relative'console_helpers'
2
+
3
+ def show_wait_cursor(seconds, fps = 10)
4
+ chars = %w(| / - \\)
5
+ delay = 1.0 / fps
6
+ (seconds * fps).round.times do |i|
7
+ print chars[i % chars.length]
8
+ sleep delay
9
+ print "\b"
10
+ end
11
+ end
12
+
13
+ show_wait_cursor(3)
14
+ @msg_help = <<HELP
15
+ . .
16
+ 8 8888888888 b. 8 8 8888 ,o888888o. ,8. ,8. .8.
17
+ 8 8888 888o. 8 8 8888 8888 `88. ,888. ,888. .888.
18
+ 8 8888 Y88888o. 8 8 8888 ,8 8888 `8. .`8888. .`8888. :88888.
19
+ 8 8888 .`Y888888o. 8 8 8888 88 8888 ,8.`8888. ,8.`8888. . `88888.
20
+ 8 888888888888 8o. `Y888888o. 8 8 8888 88 8888 ,8'8.`8888,8^8.`8888. .8. `88888.
21
+ 8 8888 8`Y8o. `Y88888o8 8 8888 88 8888 ,8' `8.`8888' `8.`8888. .8`8. `88888.
22
+ 8 8888 8 `Y8o. `Y8888 8 8888 88 8888 8888888 ,8' `8.`88' `8.`8888. .8' `8. `88888.
23
+ 8 8888 8 `Y8o. `Y8 8 8888 `8 8888 .8',8' `8.`' `8.`8888. .8' `8. `88888.
24
+ 8 8888 8 `Y8o.` 8 8888 8888 ,88',8' `8 `8.`8888. .888888888. `88888.
25
+ 8 888888888888 8 `Yo 8 8888 `8888888P' ,8' ` `8.`8888. .8' `8. `88888.
26
+
27
+
28
+ Intro
29
+ ====================================
30
+ Hello there, welcome to the EnigmaEngine! This program simulates the Enigma Machine used in World War II by the Germans.
31
+ Find out more on "#{yellow('https://github.com/andela-sdamian/enigma_engine')}"
32
+
33
+ Usage
34
+ ====================================
35
+ 1. Encrypting a file
36
+ `enigma encrypt [file_name.txt] [new_file.txt]`
37
+
38
+ 2. Decrypting a file
39
+ `enigma decrypt [encrypted_file.txt] [new_file.txt] [five_digit_key] [date]`
40
+
41
+ 3. Cracking a file
42
+ `enigma crack [file_name.txt] [new_file.txt] [date]`
43
+
44
+ All date should be in the format DDMMYY e.g. 020416
45
+
46
+ AUTHOR
47
+ =====================================
48
+ Copyright (c) 2016 Damian Simon Peter
49
+ ----------------------------------------------------------------------
50
+ |Twitter => "#{blue('http://twitter.com/damiansimonpete')}"
51
+ |StackOverflow => "#{yellow('http://goo.gl/3WIAP4')}"
52
+ |GitHub => "#{blue('http://github.com/andela-sdamian')}"
53
+ |Powered by Andela "#{green('http://twitter.com/andela')}"
54
+ ----------------------------------------------------------------------
55
+
56
+ HELP
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/circle.yml ADDED
@@ -0,0 +1,6 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.2.3
4
+ dependencies:
5
+ pre:
6
+ - gem install bundler -v 1.11.2
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'enigma_engine/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'enigma_engine'
8
+ spec.version = EnigmaEngine::VERSION
9
+ spec.authors = ['Damian Simon Peter']
10
+ spec.email = ['simon.peter@andela.com']
11
+
12
+ spec.summary = 'A gem that simulates the Enigma Machine'
13
+ spec.description = 'The inner working of an enigma machine has three rotors. Each rotors has wrapped around it the 26 letters. When a key is pressed it moves the rotor ahead one alphabet. The other rotors kick off after the first has completed a revolution and so for the third.When this is done, text in plain english becomes gibberish. Before you start encrypting you and your recipient must agree upon a key which can be set on the machine. Find out more on my GitHub page'
14
+ spec.homepage = 'https://github.com/andela-sdamian/enigma_engine'
15
+ spec.license = 'MIT'
16
+
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
+ else
20
+ raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
21
+ end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = 'bin'
25
+ spec.executables = ['enigma']
26
+ spec.require_paths = ['lib']
27
+
28
+ spec.add_development_dependency 'bundler', '~> 1.11'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec'
31
+ spec.add_development_dependency 'coveralls'
32
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'enigma_engine/version'
2
+ require_relative 'enigma_engine/date_key_helpers'
3
+ require_relative 'enigma_engine/file_helpers'
4
+ require_relative 'enigma_engine/offsets'
5
+ require_relative 'enigma_engine/rotors'
6
+ require_relative 'enigma_engine/engine'
7
+ module EnigmaEngine
8
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'engine'
2
+ module EnigmaEngine
3
+ class Crack < EnigmaEngine::Engine
4
+ def handle_get_target(encrypted_file, res)
5
+ case encrypted_file.last.length
6
+ when 4 then res[:target] = encrypted_file.last
7
+ res[:weakness] = %w(n d . .)
8
+ when 3 then res[:weakness] = %w(. . e n)
9
+ when 2 then res[:weakness] = %w(. e n d)
10
+ when 1 then res[:weakness] = %w(e n d .)
11
+ end
12
+ res
13
+ end
14
+
15
+ def get_target(encrypted_file)
16
+ res = {}
17
+ res[:target] = encrypted_file[encrypted_file.length - 2]
18
+ handle_get_target(encrypted_file, res)
19
+ end
20
+
21
+ def find_key(encrypted_file)
22
+ encrypted_file = text_to_array(open_file(encrypted_file))
23
+ char_map_with_index = Hash[characters.zip (0...characters.size)]
24
+ target_char = get_target(encrypted_file)
25
+ rotation = {}
26
+ target_char[:target].each_with_index do |item, index|
27
+ weakness_pos = char_map_with_index[target_char[:weakness][index]]
28
+ pos = char_map_with_index[item] - weakness_pos
29
+ (pos < 0) ? pos += 39 : pos
30
+ case index
31
+ when 0 then rotation[:a_rotation] = pos
32
+ when 1 then rotation[:b_rotation] = pos
33
+ when 2 then rotation[:c_rotation] = pos
34
+ when 3 then rotation[:d_rotation] = pos
35
+ end
36
+ end
37
+ rotation
38
+ end
39
+
40
+ def handle_crack_rotation(index, item, res, func)
41
+ case index
42
+ when 0 then func.call(item, res[:a_rotation])
43
+ when 1 then func.call(item, res[:b_rotation])
44
+ when 2 then func.call(item, res[:c_rotation])
45
+ when 3 then func.call(item, res[:d_rotation])
46
+ end
47
+ end
48
+
49
+ def crack(encrypted_file, new_file, date)
50
+ res = find_key(encrypted_file)
51
+ key = res.values.map(&:to_s).join('')
52
+ encrypted_file = text_to_array(open_file(encrypted_file))
53
+ cracked_chars = []
54
+ encrypted_file.each do |row|
55
+ row.each_with_index do |item, index|
56
+ brk = handle_crack_rotation(index, item, res, method(:decrypt_char))
57
+ cracked_chars.push(brk)
58
+ end
59
+ end
60
+ create_write_file(cracked_chars.join(''), new_file, key, date)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,44 @@
1
+ module EnigmaEngine
2
+ module DateKeyHelpers
3
+ def today
4
+ date = Time.now.strftime('%d, %m, %y').to_s
5
+ date.gsub!(/\,/, '').split(' ').join('').to_s
6
+ end
7
+
8
+ def colorize(text, color_code)
9
+ "\e[#{color_code}m#{text}\e[0m"
10
+ end
11
+
12
+ def red(text)
13
+ colorize(text, 31)
14
+ end
15
+
16
+ def green(text)
17
+ colorize(text, 32)
18
+ end
19
+
20
+ def blue(text)
21
+ colorize(text, 34)
22
+ end
23
+
24
+ def yellow(text)
25
+ colorize(text, 33)
26
+ end
27
+
28
+ def files_valid?(arr)
29
+ arr.all? { |i| i[-4, 4] == '.txt' }
30
+ end
31
+
32
+ def key_valid?(key)
33
+ key.to_s.length.eql? 5
34
+ end
35
+
36
+ def date_valid?(date)
37
+ date.to_s.length.eql? 6
38
+ end
39
+
40
+ def fields_empty?(arr)
41
+ arr.include? ''
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,83 @@
1
+ require_relative 'rotors'
2
+ require_relative 'offsets'
3
+ require_relative 'file_helpers'
4
+ require_relative 'date_key_helpers'
5
+
6
+ module EnigmaEngine
7
+ class Engine
8
+ include Rotors
9
+ include Offsets
10
+ include FileHelpers
11
+ include DateKeyHelpers
12
+
13
+ attr_writer :date, :key
14
+ attr_reader :date
15
+
16
+ def date=(date)
17
+ date.sub!(/^0/, '')
18
+ date_squared = date.to_i**2
19
+ last_four = date_squared.to_s.split('')[-4, 4]
20
+ @date = last_four.map(&:to_i)
21
+ end
22
+
23
+ def characters
24
+ ('a'..'z').to_a + ('0'..'9').to_a + [32.chr, 46.chr, 44.chr]
25
+ end
26
+
27
+ def encrypt_char(char, pos)
28
+ char.downcase!
29
+ char_map_hash = Hash[characters.zip(characters.rotate(pos))]
30
+ res = char.chars.map { |c| char_map_hash.fetch(c) }
31
+ res.join('')
32
+ end
33
+
34
+ def decrypt_char(char, pos)
35
+ char.downcase!
36
+ pos *= -1
37
+ char_map_hash = Hash[characters.zip(characters.rotate(pos))]
38
+ res = char.chars.map { |c| char_map_hash.fetch(c) }
39
+ res.join('')
40
+ end
41
+
42
+ def handle_rotation(index, item, func)
43
+ case index
44
+ when 0 then func.call(item, a_rotation + a_offset)
45
+ when 1 then func.call(item, b_rotation + b_offset)
46
+ when 2 then func.call(item, c_rotation + c_offset)
47
+ when 3 then func.call(item, d_rotation + d_offset)
48
+ end
49
+ end
50
+
51
+ def rand_key
52
+ rand(999_99).to_s.center(5, rand(9).to_s)
53
+ end
54
+
55
+ def encrypt(file, new_file)
56
+ @key = rand_key
57
+ @date = today
58
+ message = text_to_array(open_file(file))
59
+ encrypted_chars = []
60
+ message.each do |row|
61
+ row.each_with_index do |item, index|
62
+ rotated = handle_rotation(index, item, method(:encrypt_char))
63
+ encrypted_chars.push(rotated)
64
+ end
65
+ end
66
+ create_write_file(encrypted_chars.join(''), new_file, @key, date, true)
67
+ end
68
+
69
+ def decrypt(file, new_file, key, date)
70
+ @key = key
71
+ @date = date
72
+ message = text_to_array(open_file(file))
73
+ decrypted_chars = []
74
+ message.each do |row|
75
+ row.each_with_index do |item, index|
76
+ reversed = handle_rotation(index, item, method(:decrypt_char))
77
+ decrypted_chars.push(reversed)
78
+ end
79
+ end
80
+ create_write_file(decrypted_chars.join(''), new_file, key, date)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,36 @@
1
+ module EnigmaEngine
2
+ module FileHelpers
3
+ def open_file(file_name)
4
+ file = File.open(file_name, 'r')
5
+ if File.exist? file
6
+ data = file.read
7
+ data.gsub(/\n/, ' ')
8
+ end
9
+ rescue
10
+ raise <<NOTIFY
11
+ "Cannot find file, Run [enigma help] to see help!"
12
+ NOTIFY
13
+ end
14
+
15
+ def create_write_file(txt, file_name, key, date, type = false)
16
+ file = File.open(file_name, 'w')
17
+ file.write(txt)
18
+ file.close
19
+ show_msg(file_name, key, date, type)
20
+ end
21
+
22
+ def text_to_array(text)
23
+ text = text.split('').map(&:downcase)
24
+ text.each_slice(4).to_a
25
+ end
26
+
27
+ def show_msg(new_file, key, date, type = false)
28
+ msg = 'Please take note of the key & date in order to decrypt this file'
29
+ (type) ? msg = yellow(msg) : msg = ''
30
+ puts <<NOTIFY
31
+ Created: #{green(new_file)}\nKey: #{red(key)}\nDate: #{blue(date)}
32
+ #{msg}
33
+ NOTIFY
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ module EnigmaEngine
2
+ module Offsets
3
+ def get_date(index)
4
+ @date[index].to_i
5
+ end
6
+
7
+ def a_offset
8
+ get_date(0)
9
+ end
10
+
11
+ def b_offset
12
+ get_date(1)
13
+ end
14
+
15
+ def c_offset
16
+ get_date(2)
17
+ end
18
+
19
+ def d_offset
20
+ get_date(3)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module EnigmaEngine
2
+ module Rotors
3
+ def key
4
+ @key
5
+ end
6
+
7
+ def put_key(x, y)
8
+ key.to_s.split('')[x, y].join('').to_i
9
+ end
10
+
11
+ def a_rotation
12
+ put_key(0, 2)
13
+ end
14
+
15
+ def b_rotation
16
+ put_key(1, 2)
17
+ end
18
+
19
+ def c_rotation
20
+ put_key(2, 2)
21
+ end
22
+
23
+ def d_rotation
24
+ put_key(3, 2)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module EnigmaEngine
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enigma_engine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Damian Simon Peter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: coveralls
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: The inner working of an enigma machine has three rotors. Each rotors
70
+ has wrapped around it the 26 letters. When a key is pressed it moves the rotor ahead
71
+ one alphabet. The other rotors kick off after the first has completed a revolution
72
+ and so for the third.When this is done, text in plain english becomes gibberish.
73
+ Before you start encrypting you and your recipient must agree upon a key which can
74
+ be set on the machine. Find out more on my GitHub page
75
+ email:
76
+ - simon.peter@andela.com
77
+ executables:
78
+ - enigma
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - ".coveralls.yml"
83
+ - ".gitignore"
84
+ - ".rubocop.yml"
85
+ - CODE_OF_CONDUCT.md
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - bin/console_helpers.rb
91
+ - bin/enigma
92
+ - bin/help.rb
93
+ - bin/setup
94
+ - circle.yml
95
+ - enigma_engine.gemspec
96
+ - lib/enigma_engine.rb
97
+ - lib/enigma_engine/crack.rb
98
+ - lib/enigma_engine/date_key_helpers.rb
99
+ - lib/enigma_engine/engine.rb
100
+ - lib/enigma_engine/file_helpers.rb
101
+ - lib/enigma_engine/offsets.rb
102
+ - lib/enigma_engine/rotors.rb
103
+ - lib/enigma_engine/version.rb
104
+ homepage: https://github.com/andela-sdamian/enigma_engine
105
+ licenses:
106
+ - MIT
107
+ metadata:
108
+ allowed_push_host: https://rubygems.org
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.4.5.1
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: A gem that simulates the Enigma Machine
129
+ test_files: []