kyle 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e3f01dd717ea2c77c86f500aac403598e5dff92
4
- data.tar.gz: 7769d19716cacdd3bd146c99163b7bea667a2344
3
+ metadata.gz: 3f04555392f57d6f09a00cc5f1e2a5bc5f185efe
4
+ data.tar.gz: 5369fc8ad09357dd2791e3945c967f7f95290ae0
5
5
  SHA512:
6
- metadata.gz: b8e9f48d5d94cb23a7fe63474494180cf77a98e76950e10185d9a8c4a4ad81a2f8beb2a39e6cdd32b42cdda297fbc55e00be8daa60df732e9dc178ee8f5477fb
7
- data.tar.gz: 05770529219032c2338a956d9853d9dccf58263cfc24f324a6e04af4eaec073fd6fc282c0d57b8cfc9972e0b889bb0b8714baa55138de473d89895a77751a756
6
+ metadata.gz: 5d2565eeb14b542d6afbbb0e940734329168172caa165535ac2679716a3d9fb9108b68af11ce49b89b9a92bc15ff38f860f4043895f898875ac0527d141e2799
7
+ data.tar.gz: af2beb34df3ae60876544336624936850695812c1f5a2b4d97e2ba3db9d46bb0d39ed3033f35c47b8316382936935e9deca50ad7a9031bcfd6f99b97414fab6d
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ .DS_Store
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kyle (0.0.3)
5
+ highline (~> 1.6, >= 1.6.20)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.0.0)
11
+ astrolabe (1.3.0)
12
+ parser (>= 2.2.0.pre.3, < 3.0)
13
+ diff-lcs (1.2.5)
14
+ highline (1.6.21)
15
+ parser (2.2.0.pre.4)
16
+ ast (>= 1.1, < 3.0)
17
+ slop (~> 3.4, >= 3.4.5)
18
+ powerpack (0.0.9)
19
+ rainbow (2.0.0)
20
+ rspec (3.0.0)
21
+ rspec-core (~> 3.0.0)
22
+ rspec-expectations (~> 3.0.0)
23
+ rspec-mocks (~> 3.0.0)
24
+ rspec-core (3.0.3)
25
+ rspec-support (~> 3.0.0)
26
+ rspec-expectations (3.0.3)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.0.0)
29
+ rspec-mocks (3.0.3)
30
+ rspec-support (~> 3.0.0)
31
+ rspec-support (3.0.3)
32
+ rubocop (0.26.0)
33
+ astrolabe (~> 1.3)
34
+ parser (>= 2.2.0.pre.4, < 3.0)
35
+ powerpack (~> 0.0.6)
36
+ rainbow (>= 1.99.1, < 3.0)
37
+ ruby-progressbar (~> 1.4)
38
+ ruby-progressbar (1.5.1)
39
+ slop (3.6.0)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ kyle!
46
+ rspec (~> 3.0.0)
47
+ rubocop (~> 0.26)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Harun Esur
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,244 @@
1
+ Kyle
2
+ ====
3
+ A password manager for paranoids.
4
+
5
+ ### Overview
6
+
7
+ Kyle differs from other password managers, since:
8
+
9
+ * It doesn't store any passwords so there is nothing to steal/crack for
10
+ attackers.
11
+ * However, you can't store any given password, but must set one generated by
12
+ Kyle.
13
+
14
+ Kyle differs from other password generators, since:
15
+
16
+ * Generated passwords are not random, but a brute-force method can take
17
+ thousands of years to crack one:
18
+
19
+ e.g. on the test vectors Bill Gates' password tooks 12.11 seconds on a MacBook
20
+ Pro Early 2013 with 2,4 GHZ Intel Core i7. So even for a lazy master-key with
21
+ 8 chars includes small-case-letters and numbers, there are
22
+ `36^8+36^7+36^5+36^4+36^3+36^2+36 = 2901713047668` combinations; with 12.11s
23
+ per combination, it would take ***1,114,274 years*** to try all combinations.
24
+
25
+ * It doesn't use any specific hash or encryption algorithm, using a mixture of
26
+ several, chosen using the input info and key.
27
+
28
+ ### Installation
29
+
30
+ ```bash
31
+ $ gem install kyle
32
+ ```
33
+
34
+ ### Usage
35
+
36
+ Just type `kyle` on the command line to run, and pick any password depending
37
+ on your favourite animal.
38
+
39
+ ```bash
40
+ $ kyle
41
+ Hostname:
42
+ abc.com
43
+ Account:
44
+ superuser
45
+ Port:
46
+ 80
47
+ Key:
48
+
49
+
50
+ Ape _,o_iMmO5L!ZRlQH
51
+ Bat EZPBcTf6oo-jzWpM
52
+ Bear .ZmYlZ4PQpdOfish
53
+ Whale wb%EOphi7uqySwRZ
54
+ Crow eTXvLc.4FgTdIEJ%
55
+ Dog .Q,PBaMeFRO8nG-a
56
+ Cat ,lHFEMVXo%SjTlsm
57
+ Wasp e0CyUAHvs9-ljGFr
58
+ Fox 2%yxWtBZz-cOVW@b
59
+ Gull avuR86nGjG6DNkkX
60
+ Jackal +zhRwHPWCHknxlZp
61
+ Lion xMxPwb0E+5vQ_q4x
62
+ Panda qj7GQqJP7EKjU*gG
63
+ Rat kvniGIszq758@Sie
64
+ Shark 1aF3.iiV,e*OTGpT
65
+ Spider *nrvUtila0wnmb22
66
+ Turtle wYQerXRYffJJGvxZ
67
+ Wolf MD!VTDkikYxZvzM!
68
+ Zebra asVw!Q/5!QvqxiRf
69
+ ```
70
+
71
+ You can also specify the hostname, account, port, and animal when typing the
72
+ command:
73
+
74
+ ```bash
75
+ $ kyle abc.com superuser 80 jackal
76
+ Key:
77
+
78
+
79
+ +zhRwHPWCHknxlZp
80
+ ```
81
+
82
+ Arguments must in this order, but any missing ones will be prompted for.
83
+
84
+ Adding the `-c` flag will prompt for the key twice, so you can be sure you
85
+ didn't make a typo.
86
+
87
+ Adding the `-r` flag saves the hostname/account/port combination in `~/.kyle`.
88
+
89
+ Adding `-a ` flag lets you choose from one of savedhost/account/port records saved with -r;
90
+
91
+
92
+ #### Batch usage
93
+
94
+ ```bash
95
+ $ kyle -b path/to/file.kyle animal
96
+ Key:
97
+
98
+
99
+ hostname:account:port (animal) = password
100
+ hostname:account:port (animal) = password
101
+ ```
102
+
103
+ Where `file.kyle` contains triples of hostname, account, port separated by
104
+ semi-colons (`;`), one per line. E.g.:
105
+
106
+ ```
107
+ facebook.com;zuckerberg;80
108
+ amazon.com;bezos;443
109
+ ```
110
+
111
+ ### Changelog
112
+
113
+ #### 0.0.5
114
+
115
+ * Merge version with Isaac Seymour's efforts to unify multiple development lines that includes;
116
+
117
+ * Refactored code to have proper Rspec tests, and respect Rubocop conventions
118
+
119
+ * Added ability to specify hostname, account, port, and animal as args to the
120
+ executable
121
+
122
+ #### 0.0.4
123
+
124
+ * Added -a (Auto) flag
125
+
126
+ #### 0.0.2
127
+
128
+ * Added -b (BATCH) mode which help you generate bulk passwords;
129
+
130
+ * Added -r option to add entered values to <USER_HOME>/.kyle file
131
+
132
+ ### Algorithm
133
+
134
+ #### Overall
135
+
136
+ ```
137
+
138
+ +--------+ +-------+ +----+ +----------+
139
+ |HOSTNAME| |ACCOUNT| |PORT| |MASTER-KEY|
140
+ +---+----+ +---+---+ +--+-+ +-----+----+
141
+ | | | |
142
+ v v v v
143
+ +------+ +------+ +------+ +------+
144
+ |I.HASH| |I.HASH| |I.HASH| |I.HASH|
145
+ +------+ +------+ +------+ +------+
146
+ | | | |
147
+ v v v v
148
+ +------+ +------+ +------+ +------+
149
+ |I.HASH| |I.HASH| |I.HASH| |I.HASH|
150
+ +------+ +------+ +------+ +------+
151
+ + + + +
152
+ | | | |
153
+ +-----+++----+ +-----+++----+
154
+ | |
155
+ v v
156
+ +------+ +------+
157
+ |I.ENC.| |I.ENC.|
158
+ +------+ +------+
159
+ + +
160
+ | |
161
+ +------------+++-------+
162
+ |
163
+ v
164
+ +------+
165
+ |I.ENC.|
166
+ +------+ +------------+
167
+ + |ANIMAL NAMES|
168
+ | +------------+
169
+ ENC | A1..AN |
170
+ | +------------+
171
+ v
172
+ +--(A1..AN)------------------------------+
173
+ |RES = PBKDF2_HMAC_SHA1(ENC,RES,10000,32)|
174
+ +----------------------------------------+
175
+ +
176
+ v
177
+ +-----------------------------+
178
+ |HASH_TO_PASSWORD(SHA512(RES))|
179
+ +-----------------------------+
180
+ + + +
181
+ | | |
182
+ (A1..AN)
183
+ | | |
184
+ v v v
185
+
186
+ MULTIPLE PASSES
187
+
188
+ ```
189
+
190
+ #### Iterative Hash
191
+
192
+ ```
193
+ +-------------+
194
+ Iterative Hash |ALGORITHMS |
195
+ +-------------+
196
+ +-------------+ +--> |SHA512 |
197
+ |Text=(t1..tn)| | +-------------+
198
+ +------+------+ +--> |SHA384 |
199
+ | | +-------------+
200
+ | +--> |SHA256 |
201
+ v | +-------------+
202
+ +--(i=1..n)-----------------------------------------+ +--> |SHA224 |
203
+ |HASH=ALGORITHM[(ti % ALGORITHMS.SIZE)](Text | HASH)|+-+ +-------------+
204
+ +---------------------------------------------------+ +--> |SHA1 |
205
+ + | +-------------+
206
+ | +--> |SHA2 |
207
+ | | +-------------+
208
+ v +--> |MD5 |
209
+ | +-------------+
210
+ HASH +--> |MD4 |
211
+ | +-------------+
212
+ +--> |RIPEMD160 |
213
+ +-------------+
214
+ ```
215
+
216
+ #### Iterative Encryption
217
+
218
+ ```
219
+ +-------------+
220
+ Iterative Encryption |ALGORITHMS |
221
+ +-------------+
222
+ +-------------+ +--> |DES3 |
223
+ |TEXT=(t1..tn)| | +-------------+
224
+ |KEY=(k1..kn) | +--> |DESX |
225
+ +-------------+ | +-------------+
226
+ | +--> |DES |
227
+ v | +-------------+
228
+ +--(i=1..n)----------------------------------------------+ +--> |CAST |
229
+ |ENC.=ALGORITHM[(ti % ALGORITHMS.SIZE)]((Text | ENC.),KEY|--------->| +-------------+
230
+ +-------------------------------------------+------------+ +--> |BLOWFISH |
231
+ + | ^ | +-------------+
232
+ | | | +--> |AES128 |
233
+ | | | | +-------------+
234
+ | v | +--> |AES192 |
235
+ | +--------------+------------+ | +-------------+
236
+ | |KEY=PBKDF2("kyle",10000,32)| +--> |AES256 |
237
+ | | IV=SHA512(KEY) | | +-------------+
238
+ | +---------------------------+ +--> |RC4 |
239
+ | +-------------+
240
+ v
241
+
242
+ ENCRYPTED
243
+ ```
244
+
data/bin/kyle CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'kyle'
3
+ require 'kyle_commands'
4
4
 
5
- Kyle.run(ARGV)
5
+ KyleCommands.new(ARGV).run
data/kyle.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |gem|
2
+ gem.name = 'kyle'
3
+ gem.version = '0.0.5'
4
+ gem.date = '2014-09-17'
5
+
6
+ gem.summary = 'Kyle'
7
+ gem.description = 'A password manager for paranoids.'
8
+ gem.authors = ['Harun Esur', 'Isaac Seymour']
9
+ gem.email = 'harun.esur@sceptive.com'
10
+ gem.homepage = 'http://sceptive.com'
11
+ gem.license = 'MIT'
12
+ gem.requirements << 'Ruby should be compiled with openssl support.'
13
+
14
+ gem.executables << 'kyle'
15
+
16
+ gem.files = `git ls-files`.split("\n")
17
+
18
+ gem.add_runtime_dependency 'highline', '~> 1.6', '>= 1.6.20'
19
+
20
+ gem.add_development_dependency 'rubocop', '~> 0.26'
21
+ gem.add_development_dependency 'rspec', '~> 3.0.0'
22
+ end
data/lib/constants.rb ADDED
@@ -0,0 +1,15 @@
1
+ # Algorithms, password characters, animals
2
+ module Constants
3
+ ENC_ALGS = %w(des3 desx des cast bf aes128 aes192 aes256 rc4).freeze
4
+ HASH_ALGS = %w(sha512 sha384 sha256 sha224 sha1 sha md5 md4 ripemd160).freeze
5
+
6
+ LETTERS = %w(q w e r t y u i o p a s d f g h j k l z x c v b n m).freeze
7
+ BIG_LETTERS = %w(Q W E R T Y U I O P A S D F G H J K L Z X C V B N M).freeze
8
+ NUMBERS = %w(0 1 2 3 4 5 6 7 8 9).freeze
9
+ SPECIAL_CHARS = %w(. @ + - * / % _ ! ,).freeze
10
+
11
+ PASSWORD_CHARS = (LETTERS + BIG_LETTERS + NUMBERS + SPECIAL_CHARS).freeze
12
+
13
+ ANIMALS = %w(Ape Bat Bear Whale Crow Dog Cat Wasp Fox Gull Jackal Lion Panda
14
+ Rat Shark Spider Turtle Wolf Zebra).freeze
15
+ end
data/lib/kyle.rb CHANGED
@@ -1,277 +1,118 @@
1
1
  #!/usr/bin/ruby
2
2
  require 'openssl'
3
3
  require 'highline/import'
4
+ require 'constants'
4
5
 
6
+ # Password generation from 4 inputs
7
+ class Kyle
8
+ attr_accessor :hostname, :account, :port, :key
5
9
 
6
- $ENC_ALGS = [
7
- "des3", "desx", "des", "cast", "bf",
8
- "aes128", "aes192", "aes256", "rc4"
9
-
10
- ]
10
+ def initialize(hostname, account, port, key)
11
+ @hostname = hostname
12
+ @account = account
13
+ @port = port
14
+ @key = key
15
+ end
11
16
 
12
- $HSH_ALGS = [
13
- "sha512", "sha384", "sha256", "sha224", "sha1", "sha",
14
- "md5", "md4", "ripemd160"
15
- ]
17
+ def passwords
18
+ @passwords ||= generate
19
+ end
16
20
 
17
- $letters = [
18
- "q","w","e","r","t","y","u","i","o","p",
19
- "a","s","d","f","g","h","j","k","l","z",
20
- "x","c","v","b","n","m"
21
- ]
21
+ def generate
22
+ passwords = {}
22
23
 
23
- $bletters = [
24
- "Q","W","E","R","T","Y","U","I","O","P",
25
- "A","S","D","F","G","H","J","K","L","Z",
26
- "X","C","V","B","N","M"
27
- ]
24
+ salt = encrypted_inputs
25
+ cipher = salt
28
26
 
29
- $nums = [
30
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
31
- ]
27
+ Constants::ANIMALS.each do |a|
28
+ cipher = OpenSSL::PKCS5.pbkdf2_hmac_sha1(cipher, salt, 10_000, 32)
32
29
 
33
- $schars = [
34
- ".", "@", "+", "-", "*", "/", "%", "_", "!", ","
35
- ]
30
+ passwords[a] = Kyle.hash_to_password(cipher)
31
+ end
36
32
 
37
- $passctable = []
33
+ passwords
34
+ end
38
35
 
39
- $letters.each { |c| $passctable << c }
40
- $bletters.each { |c| $passctable << c }
41
- $nums.each { |c| $passctable << c }
42
- $schars.each { |c| $passctable << c }
36
+ def hashed_hostname
37
+ Kyle.hash_twice(hostname)
38
+ end
43
39
 
44
- $animalnames = [
45
- "Ape", "Bat", "Bear", "Whale", "Crow", "Dog", "Cat", "Wasp",
46
- "Fox", "Gull", "Jackal", "Lion", "Panda", "Rat", "Shark", "Spider",
47
- "Turtle", "Wolf", "Zebra"
48
- ]
40
+ def hashed_account
41
+ Kyle.hash_twice(account)
42
+ end
49
43
 
50
- class Kyle
44
+ def hashed_port
45
+ Kyle.hash_twice(port)
46
+ end
51
47
 
52
- def self.to_hex(s)
53
- s.each_byte.map { |b| b.to_s(16) }.join
48
+ def hashed_key
49
+ Kyle.hash_twice(key)
54
50
  end
55
51
 
52
+ def encrypted_inputs
53
+ Kyle.iterative_encrypt(
54
+ Kyle.iterative_encrypt(hashed_hostname, hashed_account),
55
+ Kyle.iterative_encrypt(hashed_port, hashed_key))
56
+ end
56
57
 
57
- def self.enc_it(alg,val,key)
58
- #puts "enc_it #{alg} #{to_hex(val)} #{to_hex(key)}"
59
- begin
60
- cipher = OpenSSL::Cipher::Cipher.new(alg)
61
- cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(key, "kyle", 10000, 32)
62
- cipher.iv = sha512ize(key)
63
- cipher.encrypt
64
- return cipher.update(val) + cipher.final
65
- rescue OpenSSL::Cipher::CipherError => e
66
- puts "Error: #{e.message}"
67
- end
58
+ #################
59
+ # Class methods #
60
+ #################
61
+ def self.encrypt(alg, val, key)
62
+ cipher = OpenSSL::Cipher::Cipher.new(alg)
63
+ cipher.key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(key, 'kyle', 10_000, 32)
64
+ cipher.iv = sha512ize(key)
65
+ cipher.encrypt
66
+ return cipher.update(val) + cipher.final
67
+ rescue OpenSSL::Cipher::CipherError => e
68
+ puts "Error: #{e.message}"
68
69
  end
69
70
 
70
- def self.iterative_enc(val, key)
71
+ def self.iterative_encrypt(val, key)
71
72
  ret = val
73
+
72
74
  val.each_byte do |c|
73
- ret = enc_it($ENC_ALGS[c % ($ENC_ALGS.size)], ret, key)
75
+ alg = Constants::ENC_ALGS[c % Constants::ENC_ALGS.length]
76
+ ret = encrypt(alg, ret, key)
74
77
  end
75
-
76
- return ret
78
+
79
+ ret
77
80
  end
78
81
 
79
- def self.hash_it(alg,val)
80
- #puts "hash_it #{alg} - #{to_hex(val)}"
81
- OpenSSL::Digest.digest(alg,val)
82
+ def self.hash(alg, val)
83
+ OpenSSL::Digest.digest(alg, val)
82
84
  end
83
85
 
84
86
  def self.iterative_hash(val)
85
87
  ret = val
88
+
86
89
  val.each_byte do |c|
87
- ret = hash_it($HSH_ALGS[c % ($HSH_ALGS.size)], ret)
90
+ alg = Constants::HASH_ALGS[c % Constants::HASH_ALGS.length]
91
+ ret = hash(alg, ret)
88
92
  end
89
- return ret
93
+
94
+ ret
90
95
  end
91
96
 
92
97
  def self.sha512ize(val)
93
- hash_it("sha512",val)
98
+ hash('sha512', val)
94
99
  end
95
100
 
96
- def self.di_hash(val)
101
+ def self.hash_twice(val)
97
102
  iterative_hash(iterative_hash(val))
98
103
  end
99
104
 
100
- def self.hash2pass(val)
101
- ret = ""
102
-
103
- # to be sure it is long enough
104
- h = sha512ize(val)
105
-
106
- h.each_byte do |c|
107
- ret += $passctable[c % ($passctable.size)]
108
- end
109
-
110
- return ret[0..15]
111
- end
112
-
113
-
114
-
115
- def self.generate(hostname,account,port,key)
116
-
117
- ret = Array.new
118
-
119
- harr = [ di_hash(hostname), di_hash(account), di_hash(port), di_hash(key) ]
120
-
121
- v1 = iterative_enc(harr[0],harr[1])
122
- v2 = iterative_enc(harr[2],harr[3])
105
+ def self.hash_to_password(val)
106
+ ret = ''
123
107
 
124
- v = iterative_enc(v1,v2)
125
-
126
- c = v
127
- $animalnames.each do |animal|
128
- c = OpenSSL::PKCS5.pbkdf2_hmac_sha1(c, v, 10000, 32)
129
-
130
- ret << hash2pass(c)
131
-
132
- end
133
-
134
- return ret
135
- end
136
-
137
- $testarr = [
138
- [
139
- "microsoft.com","bill.gates","666","iKnowWhatYouDidToIBMLastSummer",
140
- "WW0nQIY.0Rn6D8d2", "nXzU19faM7*gv7,I", "cgu0q7*DuT65r3rY", "ILZ,5vZLl/wRxf9y",
141
- "Od..eF2k6_l3XHxe", "sedWPnJsSb4DEJw-", "JEr_SzZBoofgI7Tb", "xbbg@ebdz3FA.n6S",
142
- "5EMS!XZP7WfPLKpO", "LcwDHUu0/ynzdSWE", "5+fDOoY.yrE+ESbj", "VWKqetfVKZtT,FI9",
143
- "EDe7XvMZ%8tt2vsT", "vks.HPeDVkklS_qb", "hcVznOxvT5YvxIlU", "iBTr-I42uz7h7XnA",
144
- "fLV,g6%@1G7xpQil", "toMFvN@Zd,b*KBC%", "FYbi/6Udx_4mO3D0"
145
- ],
146
- [
147
- $passctable.join,$passctable.join,$passctable.join,$passctable.join,
148
- "cuoTJm!UuIYCcQxs", "3HrQ3s/j53A+Rssm", "KK+IV7QE9Imd65hi", "M@FH%uduAIvn/0Fg",
149
- "C@ffelLPbsh!ps68", "mF%j06cgTaD63v5C", "5pRiaZDk%SY6quet", "d56XIGF8PhHu!TfI",
150
- "71UES8Six9G48hsc", "kmtu%gr1.k%T!tPy", "zE8*qE+uU.PsOkYY", "77Rbxcaiwp4Fwm.M",
151
- "qWT0K%tFP8w7_H0S", "2uGyZI.SzAOujmkw", ".QhaGPzV_jnnRj@F", "4FsOh0GfaM4MVUUH",
152
- "_3r0DzAdYvEp@dlA", "qcWgE@nt9SgUEsjP", "8F1BJ.OlV5Kj!wmM"
153
- ]
154
- ]
155
-
156
- def self.test_it()
157
- puts "Testing..."
158
-
159
- failed = false
160
- (0..1).each do |idx|
161
- vals = generate($testarr[idx][0],$testarr[idx][1],$testarr[idx][2],$testarr[idx][3])
162
- vals.each.with_index(0) do |v,i|
163
- if ($testarr[idx][i+4] != v)
164
- puts "Test failed: #{$testarr[idx][i+4]} <> #{v}"
165
- failed = true
166
- end
167
- end
168
- end
169
- puts "Finished #{failed ? "and Failed" : "successfully"}"
170
- end
171
-
172
- def self.getkey()
173
-
174
- key = "a"
175
- key2 = "b"
108
+ # to be sure it is long enough
109
+ hashed = sha512ize(val)
176
110
 
177
- while (key != key2)
178
- key = ask("Key:") { |q| q.echo = false }
179
- key2 = ask("Key (again):") { |q| q.echo = false }
180
-
181
- if (key != key2)
182
- puts "Passes do not match!!"
183
- end
111
+ hashed.each_byte do |c|
112
+ ret += Constants::PASSWORD_CHARS[c % Constants::PASSWORD_CHARS.length]
113
+ break if ret.length >= 16
184
114
  end
185
115
 
186
- return key
187
-
188
- end
189
-
190
- def self.run(args)
191
-
192
- puts "Kyle - A password manager for paranoids. ( 0.0.4 )"
193
- puts ""
194
-
195
- if (args.size > 0 && args[0] == "test")
196
- test_it()
197
- elsif (args.size == 3 && args[0].to_s.downcase == "-b" && args[1] != nil && args[2] != nil)
198
-
199
- # Batch MODE
200
- # -b record_file favourite_animal_name
201
-
202
- key = getkey()
203
-
204
- text=File.open(args[1]).read
205
- text.gsub!(/\r\n?/, "\n")
206
- text.each_line do |line|
207
-
208
- hostname, account, port = line.split(';')
209
-
210
- port = port.gsub(/\n/,"")
211
-
212
- vals = generate(hostname,account,port,key)
213
-
214
- $animalnames.each.with_index(0) do |animal,i|
215
-
216
- puts "#{hostname}:#{account}:#{port} = #{vals[i]}" if (animal.downcase == args[2].downcase)
217
-
218
- end
219
-
220
-
221
- end
222
-
223
- else
224
-
225
- hostname = ""
226
- account = ""
227
- port = ""
228
-
229
- # Record given parameters to .kyle file at home
230
- kyle_r_path = File.join(Dir.home,".kyle")
231
-
232
- if (args.size > 0 && args[0].to_s.downcase == "-a")
233
- recs = []
234
- iA = 0
235
- File.open(kyle_r_path).each do |line|
236
- recs << line.rstrip!
237
- puts "#{iA} - #{line}"
238
- iA+=1
239
- end
240
-
241
- puts("")
242
- idx = ask("Selection:")
243
-
244
- r = recs[idx.to_i].split(";")
245
-
246
- hostname = r[0]
247
- account = r[1]
248
- port = r[2]
249
-
250
- else
251
- hostname = ask("Hostname:")
252
- account = ask("Account:")
253
- port = ask("Port:")
254
- end
255
- key = getkey()
256
-
257
- if (args.size > 0 && args[0].to_s.downcase == "-r")
258
-
259
-
260
- line_to_add = "#{hostname};#{account};#{port}"
261
-
262
- File.open(kyle_r_path, 'a') do |file|
263
- file.puts line_to_add
264
- end
265
- end
266
-
267
- puts "Calculating..."
268
- vals = generate(hostname,account,port,key)
269
-
270
- $animalnames.each.with_index(0) do |animal,i|
271
-
272
- puts "#{animal}\t#{vals[i]}"
273
-
274
- end
275
- end
116
+ ret[0..15]
276
117
  end
277
118
  end
@@ -0,0 +1,159 @@
1
+ require 'kyle'
2
+
3
+ # Command line access to Kyle
4
+ class KyleCommands
5
+ attr_accessor :args
6
+
7
+ def initialize(args = [])
8
+ @args = args
9
+ end
10
+
11
+ def run
12
+ puts 'Kyle - A password manager for paranoids. ( 0.0.5 )'
13
+ puts ''
14
+
15
+ batch_generate if batch?
16
+ single_generate_choose if single_by_choose?
17
+ single_generate if !batch? && !single_by_choose?
18
+ end
19
+
20
+ def ask_for_key
21
+ return ask('Key:') { |q| q.echo = false } unless check?
22
+
23
+ key = 'a'
24
+ key_check = 'b'
25
+
26
+ while key != key_check
27
+ key = ask('Key:') { |q| q.echo = false }
28
+ key_check = ask('Key (again):') { |q| q.echo = false }
29
+
30
+ puts 'Keys do not match!' unless key == key_check
31
+ end
32
+
33
+ key
34
+ end
35
+
36
+ def batch_generate
37
+ text = File.open(file).read
38
+
39
+ text.gsub!(/\r\n?/, "\n")
40
+
41
+ text.each_line do |line|
42
+ hostname, account, port = line.split(';')
43
+
44
+ port.gsub!(/\n/, '')
45
+
46
+ passwords = make_passwords(hostname, account, port, key)
47
+
48
+ passwords.select { |a, _| animals.include? a }.each do |a, p|
49
+ puts "#{hostname}:#{account}:#{port} (#{a}) = #{p}"
50
+ end
51
+ end
52
+ end
53
+
54
+ def kyle_r_path
55
+ File.join(Dir.home, '.kyle')
56
+ end
57
+
58
+ def record
59
+ line_to_add = "#{hostname};#{account};#{port}"
60
+
61
+ File.open(kyle_r_path, 'a') do |file|
62
+ file.puts line_to_add
63
+ end
64
+ end
65
+
66
+ def saved_records
67
+ recs = []
68
+ i_a = 0
69
+ File.open(kyle_r_path).each do |line|
70
+ recs << line.rstrip!
71
+ puts "#{i_a} - #{line}"
72
+ i_a += 1
73
+ end
74
+
75
+ recs
76
+ end
77
+
78
+ def single_generate_choose
79
+ recs = saved_records
80
+
81
+ puts('')
82
+ idx = ask('Selection:')
83
+
84
+ r = recs[idx.to_i].split(';')
85
+
86
+ @hostname = r[0]
87
+ @account = r[1]
88
+ @port = r[2]
89
+
90
+ single_generate
91
+ end
92
+
93
+ def single_generate
94
+ record if record?
95
+
96
+ passwords = make_passwords(hostname, account, port, key)
97
+
98
+ if animals.length > 1
99
+ Constants::ANIMALS.each { |a| puts "#{a}\t#{passwords[a]}" }
100
+ else
101
+ puts passwords[animals[0]]
102
+ end
103
+ end
104
+
105
+ def record?
106
+ args.include? '-r'
107
+ end
108
+
109
+ def check?
110
+ (args.include? '-c') || (record?)
111
+ end
112
+
113
+ def batch?
114
+ args.include? '-b'
115
+ end
116
+
117
+ def single_by_choose?
118
+ args.include? '-a'
119
+ end
120
+
121
+ def main_args
122
+ args.reject { |arg| arg[0] == '-' }
123
+ end
124
+
125
+ def hostname
126
+ @hostname ||= main_args[0] || ask('Hostname:')
127
+ end
128
+
129
+ def account
130
+ @account ||= main_args[1] || ask('Account:')
131
+ end
132
+
133
+ def port
134
+ @port ||= main_args[2] || ask('Port:')
135
+ end
136
+
137
+ def animals
138
+ animal = batch? ? main_args[1] : main_args[3]
139
+
140
+ return Constants::ANIMALS if animal.nil?
141
+ Constants::ANIMALS.select { |a| a.downcase == animal.downcase }
142
+ end
143
+
144
+ def make_passwords(hostname, account, port, key)
145
+ puts 'Generating...'
146
+ puts ''
147
+
148
+ Kyle.new(hostname, account, port, key).passwords
149
+ end
150
+
151
+ def file
152
+ fail 'File only for batch operations' unless batch?
153
+ main_args[0]
154
+ end
155
+
156
+ def key
157
+ @key ||= ask_for_key
158
+ end
159
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe KyleCommands do
4
+ subject(:cmds) { described_class.new(args) }
5
+
6
+ context 'in batch mode' do
7
+ let(:args) { %w(-b filename.txt whale) }
8
+
9
+ it 'is in batch mode' do
10
+ expect(cmds.batch?).to eq(true)
11
+ end
12
+
13
+ it 'runs #batch_generate' do
14
+ expect(cmds).to receive(:batch_generate)
15
+ cmds.run
16
+ end
17
+ end
18
+
19
+ context 'in single mode' do
20
+ let(:args) { %w(microsoft.com evilcommander 8080 panda) }
21
+
22
+ it 'is in single mode' do
23
+ expect(cmds.batch?).to eq(false)
24
+ end
25
+
26
+ it 'has details set' do
27
+ expect(cmds.hostname).to eq('microsoft.com')
28
+ expect(cmds.account).to eq('evilcommander')
29
+ expect(cmds.port).to eq('8080')
30
+ expect(cmds.animals).to eq(['Panda'])
31
+ end
32
+ end
33
+ end
data/spec/kyle_spec.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Kyle do
4
+ let!(:passwords) { Kyle.new(hostname, account, port, key).passwords }
5
+
6
+ context "Bill Gates' passwords" do
7
+ let(:hostname) { 'microsoft.com' }
8
+ let(:account) { 'bill.gates' }
9
+ let(:port) { '666' }
10
+ let(:key) { 'iKnowWhatYouDidToIBMLastSummer' }
11
+
12
+ it 'has the correct passwords' do
13
+ expect(passwords).to eq(
14
+ 'Ape' => 'WW0nQIY.0Rn6D8d2',
15
+ 'Bat' => 'nXzU19faM7*gv7,I',
16
+ 'Bear' => 'cgu0q7*DuT65r3rY',
17
+ 'Whale' => 'ILZ,5vZLl/wRxf9y',
18
+ 'Crow' => 'Od..eF2k6_l3XHxe',
19
+ 'Dog' => 'sedWPnJsSb4DEJw-',
20
+ 'Cat' => 'JEr_SzZBoofgI7Tb',
21
+ 'Wasp' => 'xbbg@ebdz3FA.n6S',
22
+ 'Fox' => '5EMS!XZP7WfPLKpO',
23
+ 'Gull' => 'LcwDHUu0/ynzdSWE',
24
+ 'Jackal' => '5+fDOoY.yrE+ESbj',
25
+ 'Lion' => 'VWKqetfVKZtT,FI9',
26
+ 'Panda' => 'EDe7XvMZ%8tt2vsT',
27
+ 'Rat' => 'vks.HPeDVkklS_qb',
28
+ 'Shark' => 'hcVznOxvT5YvxIlU',
29
+ 'Spider' => 'iBTr-I42uz7h7XnA',
30
+ 'Turtle' => 'fLV,g6%@1G7xpQil',
31
+ 'Wolf' => 'toMFvN@Zd,b*KBC%',
32
+ 'Zebra' => 'FYbi/6Udx_4mO3D0'
33
+ )
34
+ end
35
+ end
36
+
37
+ context 'with crazy inputs' do
38
+ let(:hostname) { Constants::PASSWORD_CHARS.join }
39
+ let(:account) { Constants::PASSWORD_CHARS.join }
40
+ let(:port) { Constants::PASSWORD_CHARS.join }
41
+ let(:key) { Constants::PASSWORD_CHARS.join }
42
+
43
+ it 'has correct passwords' do
44
+ expect(passwords).to eq(
45
+ 'Ape' => 'cuoTJm!UuIYCcQxs',
46
+ 'Bat' => '3HrQ3s/j53A+Rssm',
47
+ 'Bear' => 'KK+IV7QE9Imd65hi',
48
+ 'Whale' => 'M@FH%uduAIvn/0Fg',
49
+ 'Crow' => 'C@ffelLPbsh!ps68',
50
+ 'Dog' => 'mF%j06cgTaD63v5C',
51
+ 'Cat' => '5pRiaZDk%SY6quet',
52
+ 'Wasp' => 'd56XIGF8PhHu!TfI',
53
+ 'Fox' => '71UES8Six9G48hsc',
54
+ 'Gull' => 'kmtu%gr1.k%T!tPy',
55
+ 'Jackal' => 'zE8*qE+uU.PsOkYY',
56
+ 'Lion' => '77Rbxcaiwp4Fwm.M',
57
+ 'Panda' => 'qWT0K%tFP8w7_H0S',
58
+ 'Rat' => '2uGyZI.SzAOujmkw',
59
+ 'Shark' => '.QhaGPzV_jnnRj@F',
60
+ 'Spider' => '4FsOh0GfaM4MVUUH',
61
+ 'Turtle' => '_3r0DzAdYvEp@dlA',
62
+ 'Wolf' => 'qcWgE@nt9SgUEsjP',
63
+ 'Zebra' => '8F1BJ.OlV5Kj!wmM'
64
+ )
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ require 'kyle'
2
+ require 'kyle_commands'
3
+
4
+ RSpec.configure do |_|
5
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kyle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harun Esur
8
+ - Isaac Seymour
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-07-26 00:00:00.000000000 Z
12
+ date: 2014-09-17 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: highline
@@ -30,6 +31,34 @@ dependencies:
30
31
  - - ">="
31
32
  - !ruby/object:Gem::Version
32
33
  version: 1.6.20
34
+ - !ruby/object:Gem::Dependency
35
+ name: rubocop
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.26'
41
+ type: :development
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.26'
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
33
62
  description: A password manager for paranoids.
34
63
  email: harun.esur@sceptive.com
35
64
  executables:
@@ -37,8 +66,19 @@ executables:
37
66
  extensions: []
38
67
  extra_rdoc_files: []
39
68
  files:
40
- - lib/kyle.rb
69
+ - ".gitignore"
70
+ - Gemfile
71
+ - Gemfile.lock
72
+ - LICENSE
73
+ - README.md
41
74
  - bin/kyle
75
+ - kyle.gemspec
76
+ - lib/constants.rb
77
+ - lib/kyle.rb
78
+ - lib/kyle_commands.rb
79
+ - spec/kyle_commands_spec.rb
80
+ - spec/kyle_spec.rb
81
+ - spec/spec_helper.rb
42
82
  homepage: http://sceptive.com
43
83
  licenses:
44
84
  - MIT