keychain 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README +34 -0
  2. data/bin/keychain +237 -0
  3. metadata +64 -0
data/README ADDED
@@ -0,0 +1,34 @@
1
+ keychain is a very simple command line tool for managing passwords
2
+
3
+ Features include:
4
+
5
+ - passwords are stored in the blowfish encrypted file $HOME/.keychain
6
+ - search for entries using regular expressions
7
+ - automatically generates more or less pronouncable random passwords
8
+
9
+ Usage is very simple, you either start keychain without any arguments
10
+ to enter an interactive mode or directly supply the command on the
11
+ command line. Commands are:
12
+
13
+ help - print this help
14
+ print [pattern] - print entries matching pattern (patterin is full
15
+ regular expression. In particular '.*' matches
16
+ everything, not '*'
17
+ store id user key - add an entry. If key == ?, generates random password
18
+ delete id - delete entry
19
+ rename id_new id_old - rename an entry
20
+ password - change master password
21
+
22
+ Now, although I'm using this script for managing my own passwords you
23
+ should carefully read the following disclaimer:
24
+
25
+ THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY GUARANTEES TO ITS
26
+ SUITEDNESS FOR ANY PARTICULAR USE. IN PARTICULAR, I CANNOT GUARANTEE
27
+ THAT THIS SCRIPT WILL NOT ACCIDENTALLY FORGETS YOUR PASSWORDS, OR THAT
28
+ THE DATA IS ENCRYPTED IN A FASHION WHICH CANNOT BE CRACKED. THEREFORE,
29
+ KEEP YOUR $HOME/.keychain PRIVATE, AND REGULARY MAKE SURE TO STORE
30
+ YOUR PASSWORDS SOMEWHERE ELSE. ALSO MAKE SURE THAT YOU DO NOT FORGET
31
+ YOUR MASTER PASSWORD!
32
+
33
+ On the other hand, if you have ideas how to improve the security and
34
+ the cryptologic strength of the encoding, I'd be happy to know!
data/bin/keychain ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+
4
+ # A simple keychain manager written in ruby
5
+ #
6
+ # Requires the crypt and highline gem
7
+ #
8
+ # Written by Mikio L. Braun, 2008
9
+
10
+ require 'yaml'
11
+ require 'rubygems'
12
+ require 'crypt/blowfish'
13
+ require 'highline/import'
14
+
15
+ class KeyChain
16
+ FILENAME = File.join(ENV['HOME'], '.keychain')
17
+
18
+ def initialize
19
+ @keychain = {}
20
+ end
21
+
22
+ def load
23
+ if test ?f, FILENAME
24
+ @crypt = get_crypt
25
+ s = File.open(FILENAME) do |f|
26
+ @crypt.decrypt_string(f.read)
27
+ end
28
+ begin
29
+ @keychain = YAML::load(s)
30
+ raise 'ups' unless Hash === @keychain
31
+ rescue
32
+ puts "Wrong password."
33
+ exit
34
+ end
35
+ else
36
+ puts "Couldn't find keychain. Enter initial password!"
37
+ @crypt = get_new_crypt
38
+ save
39
+ File.chmod 0600, FILENAME
40
+ end
41
+ end
42
+
43
+ def save
44
+ s = YAML::dump(@keychain)
45
+ File.open(FILENAME, 'w') do |f|
46
+ f.write(@crypt.encrypt_string(s))
47
+ end
48
+ end
49
+
50
+ def store(id, user, passwd)
51
+ if @keychain.member? id
52
+ if ask("overwriting \"#{id}\"? ") != 'y'
53
+ puts "Did not overwrite"
54
+ return
55
+ end
56
+ end
57
+ @keychain[id] = [user, passwd]
58
+ end
59
+
60
+ def print(pat=nil)
61
+ puts "id | login | password"
62
+ puts "---------------------+---------------------------+----------------------"
63
+ pat ||= /.*/
64
+ @keychain.keys.grep(pat).sort.each do |id|
65
+ printf "%-20s | %-25s | %-15s\n", id, @keychain[id][0], @keychain[id][1]
66
+ end
67
+ end
68
+
69
+ def rename(id_old, id_new)
70
+ unless @keychain.member? id_old
71
+ puts "Cannot find key \"#{id_old}\""
72
+ return
73
+ end
74
+
75
+ if @keychain.member? id_new
76
+ puts "New id \"#{id_new}\" already exists!"
77
+ return
78
+ end
79
+
80
+ @keychain[id_new] = @keychain[id_old]
81
+ @keychain.delete id_old
82
+ end
83
+
84
+ def delete(id)
85
+ unless @keychain.member? id_old
86
+ puts "Cannot find key \"#{id_old}\""
87
+ return
88
+ end
89
+
90
+ @keychain.delete id
91
+ end
92
+
93
+ def password
94
+ @crypt = get_new_crypt
95
+ save
96
+ end
97
+
98
+ # generate a random password using a markov chain on
99
+ # vowels and consonants to produce pronouncable passwords.
100
+ def generate_password(l)
101
+ vow = %w(a e i o u)
102
+ con = %w(b c d f g h j k l m n p q r s t v x y z)
103
+
104
+ pw = ''
105
+ state = if rand < 0.8 then :c else :v end
106
+ for i in 0..l
107
+ case state
108
+ when :v
109
+ pw << vow[rand(vow.size)]
110
+ state = :c if rand > 0.4
111
+ when :c
112
+ pw << con[rand(con.size)]
113
+ state = :v if rand > 0.1
114
+ end
115
+ end
116
+ return pw
117
+ end
118
+ private
119
+ def get_new_crypt
120
+ password = ask('new password> ') {|q| q.echo = false}
121
+ retyped = ask('retype password> ') {|q| q.echo = false}
122
+ if password != retyped
123
+ puts "Passwords did not match."
124
+ exit
125
+ end
126
+ Crypt::Blowfish.new password
127
+ end
128
+
129
+ def get_crypt
130
+ password = ask('password> ') {|q| q.echo = false}
131
+ Crypt::Blowfish.new password
132
+ end
133
+ end
134
+
135
+ Help = <<EOS
136
+ Usage: keychain command [args]
137
+
138
+ Commands:
139
+
140
+ help - print this help
141
+ print [pattern] - print entries matching pattern (patterin is full
142
+ regular expression. In particular '.*' matches
143
+ everything, not '*'
144
+ store id user key - add an entry. If key == ?, generates random password
145
+ delete id - delete entry
146
+ rename id_new id_old - rename an entry
147
+ password - change master password
148
+
149
+ Version 0.2.1 - August 8, 2008
150
+ EOS
151
+
152
+ if ARGV.size == 0
153
+ ARGV << 'interactive'
154
+ end
155
+
156
+ def cmd(kc, args)
157
+ case args[0]
158
+ when 'print'
159
+ if args.size == 2
160
+ kc.print(Regexp.new(args[1]))
161
+ else
162
+ kc.print
163
+ end
164
+ when 'store'
165
+ if args.size < 4
166
+ puts "Format is \"add id user key\""
167
+ return
168
+ end
169
+ if args[3] == '?'
170
+ l = ask('password length? ').to_i
171
+ if l > 0
172
+ ok = false
173
+ pw = nil
174
+ until ok
175
+ pw = kc.generate_password(l)
176
+ puts "Generated password: #{pw}"
177
+ case ask('okay (ynq)? ')
178
+ when 'y'
179
+ ok = true
180
+ when 'q'
181
+ pw = nil
182
+ break
183
+ end
184
+ end
185
+ return unless pw
186
+ kc.store(args[1], args[2], pw)
187
+ end
188
+ else
189
+ kc.store(args[1], args[2], args[3])
190
+ end
191
+ kc.save
192
+ when 'delete'
193
+ if args.size < 1
194
+ puts "Which id do you want to delete?"
195
+ end
196
+ kc.delete(args[1])
197
+ kc.save
198
+ when 'rename'
199
+ if args.size < 2
200
+ puts "Format is \"rename id_old id_new\""
201
+ end
202
+ kc.rename(args[1], args[2])
203
+ kc.save
204
+ when 'help'
205
+ puts Help
206
+ when 'password'
207
+ kc.password
208
+ when 'gen'
209
+ puts kc.generate_password(args[1].to_i)
210
+ else
211
+ puts "Didn't understand command"
212
+ return
213
+ end
214
+ end
215
+
216
+ kc = KeyChain.new
217
+ if ARGV[0] == 'interactive'
218
+ puts "Entering interactive mode. Enter password. Then type 'exit' or an empty line to quite."
219
+ kc.load
220
+ while true
221
+ begin
222
+ s = ask('keychain> ')
223
+ if s == 'exit' or s == ''
224
+ exit
225
+ end
226
+ cmd(kc, s.split(' '))
227
+ rescue EOFError
228
+ puts "quitting..."
229
+ exit
230
+ rescue
231
+ raise
232
+ end
233
+ end
234
+ else
235
+ kc.load unless ARGV[0] == 'help' or ARGV[0] == 'gen'
236
+ cmd(kc, ARGV)
237
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: keychain
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.2.1
7
+ date: 2008-08-08 00:00:00 +02:00
8
+ summary: A simple shell tool for managing passwords
9
+ require_paths:
10
+ - lib
11
+ email: mikiobraun@gmail.com
12
+ homepage: http://ml.cs.tu-berlin.de/~mikio
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Mikio L. Braun
31
+ files:
32
+ - bin/keychain
33
+ - README
34
+ test_files: []
35
+
36
+ rdoc_options: []
37
+
38
+ extra_rdoc_files:
39
+ - README
40
+ executables:
41
+ - keychain
42
+ extensions: []
43
+
44
+ requirements: []
45
+
46
+ dependencies:
47
+ - !ruby/object:Gem::Dependency
48
+ name: crypt
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Version::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.4
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: highline
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Version::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.4.0
64
+ version: