skeletonkey 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7248579cc226d9cb384f36a30a94f438036140cc
4
+ data.tar.gz: 9fdc1c0cc5aa4d1e3de85487788bf2f149e4ee9a
5
+ SHA512:
6
+ metadata.gz: 32e54091eb0e1d65fab248cb73bf61d4dd4ed7ec0af279e5ad83b9592add31138463fa74729a2a5e70b6ffc1c912e5da781bf597054e98ccc9a1871a820500b0
7
+ data.tar.gz: 1cca1778429025ca6309fbdb25b8d30f66b3bfc3cec47bd053f1446ef4f05d317e0a614d0b393c86bd515a3c9a6cfdd64c16113f1872dc99068c458ba6e0264e
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.dirname(File.realpath(__FILE__)) + '/../lib')
4
+
5
+ require 'skeletonkey/cli'
6
+
7
+ Lockbox::Cli.start(ARGV)
@@ -0,0 +1,54 @@
1
+ require 'thor'
2
+ require 'clipboard'
3
+ require 'io/console'
4
+ require 'skeletonkey/safe'
5
+ require 'skeletonkey/password'
6
+
7
+ module Lockbox
8
+ class Cli < Thor
9
+ def initialize(*args)
10
+ super(*args)
11
+
12
+ @safe ||= Safe.new
13
+ end
14
+
15
+ desc "add KEY", "add a new password for KEY"
16
+ def add(key)
17
+ STDIN.noecho do |io|
18
+ puts "Please Enter a Password for #{key}: "
19
+ first_attempt = io.gets.chomp
20
+
21
+ puts "Please confirm your password: "
22
+ second_attempt = io.gets.chomp
23
+
24
+ on_invalid = ->(message){ puts message }
25
+
26
+ if Password.valid?(first_attempt, second_attempt, &on_invalid)
27
+ @safe.add(key, Password.fromString(first_attempt))
28
+ end
29
+ end
30
+ end
31
+
32
+ desc "remove KEY", "remove a password for KEY"
33
+ def remove(key)
34
+ @safe.remove(key)
35
+ end
36
+
37
+ desc "get KEY", "retrieve a password for KEY"
38
+ option :copy, :type => :boolean
39
+ def get(key)
40
+ password = @safe.get(key).to_str
41
+
42
+ if options[:copy]
43
+ Clipboard.copy(password)
44
+ else
45
+ puts password
46
+ end
47
+ end
48
+
49
+ desc "list", "list all KEYs"
50
+ def list
51
+ puts @safe.list
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Lockbox
2
+ class KeyPair
3
+ class << self
4
+ def generate
5
+ return if File.exists?(private_key_path) && File.exists?(public_key_path)
6
+
7
+ key = OpenSSL::PKey::RSA.new 2048
8
+
9
+ File.open(private_key_path, 'w', 0600) do |file|
10
+ file.write(key.to_pem)
11
+ end
12
+
13
+ File.open(public_key_path, 'w', 0600) do |file|
14
+ file.write(key.public_key.to_pem)
15
+ end
16
+ end
17
+
18
+ def public_encrypt(data)
19
+ generate
20
+ key = OpenSSL::PKey::RSA.new(File.read(public_key_path))
21
+ key.public_encrypt(data)
22
+ end
23
+
24
+ def private_decrypt(data)
25
+ generate
26
+ key = OpenSSL::PKey::RSA.new(File.read(private_key_path))
27
+ key.private_decrypt(data)
28
+ end
29
+
30
+ private
31
+
32
+ def private_key_path
33
+ File.join(Lockbox::DIRECTORY, "private_key.pem")
34
+ end
35
+
36
+ def public_key_path
37
+ File.join(Lockbox::DIRECTORY, "public_key.pem")
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ require 'openssl'
2
+ require 'skeletonkey/key_pair'
3
+
4
+ module Lockbox
5
+ class Password
6
+ attr_accessor :contents, :encrypted_contents, :iv, :key
7
+
8
+ class << self
9
+ def valid?(password, confirmed_password, &on_invalid)
10
+ valid = true
11
+
12
+ if password != confirmed_password
13
+ on_invalid.call("Your passwords do not match! Please try again")
14
+ valid = false
15
+ elsif password === ''
16
+ on_invalid.call("Your password cannot be empty! Please try again")
17
+ valid = false
18
+ end
19
+
20
+ valid
21
+ end
22
+
23
+ def fromHash(password_hash)
24
+ password = new
25
+ password.encrypted_contents = password_hash[:encrypted_contents]
26
+ password.key = password_hash[:key]
27
+ password.iv = password_hash[:iv]
28
+
29
+ password.decrypt
30
+ password
31
+ end
32
+
33
+ def fromString(password_str)
34
+ password = new
35
+ password.contents = password_str
36
+
37
+ password.encrypt
38
+ password
39
+ end
40
+ end
41
+
42
+ def to_str
43
+ @contents
44
+ end
45
+
46
+ def to_hash
47
+ {
48
+ :encrypted_contents => @encrypted_contents,
49
+ :iv => @iv,
50
+ :key => @key
51
+ }
52
+ end
53
+
54
+ def encrypt
55
+ cipher.encrypt
56
+
57
+ # set random key/iv on cipher, return for public encryption
58
+ # and store encrypted key/iv in instance variables
59
+ @key = KeyPair.public_encrypt(cipher.random_key)
60
+ @iv = KeyPair.public_encrypt(cipher.random_iv)
61
+
62
+ @encrypted_contents = cipher.update(@contents) + cipher.final
63
+ end
64
+
65
+ def decrypt
66
+ decipher = cipher
67
+ decipher.decrypt
68
+
69
+ decipher.key = KeyPair.private_decrypt(@key)
70
+ decipher.iv = KeyPair.private_decrypt(@iv)
71
+
72
+ @contents = decipher.update(@encrypted_contents) + decipher.final
73
+ end
74
+
75
+ def cipher
76
+ @cipher ||= OpenSSL::Cipher.new('AES-256-CBC')
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,50 @@
1
+ module Lockbox
2
+ DIRECTORY = File.join(Dir.home, ".lockbox")
3
+
4
+ class Safe
5
+ def initialize()
6
+ Dir.mkdir(Lockbox::DIRECTORY) unless Dir.exists?(Lockbox::DIRECTORY)
7
+
8
+ @file = File.join(Lockbox::DIRECTORY, "safe")
9
+ @storage = {}
10
+
11
+ reload
12
+ end
13
+
14
+ def add(key, password)
15
+ @storage[key] = password.to_hash
16
+ update
17
+ end
18
+
19
+ def get(key)
20
+ Password.fromHash(@storage[key])
21
+ end
22
+
23
+ def remove(key)
24
+ @storage.delete(key)
25
+ update
26
+ end
27
+
28
+ def list
29
+ @storage.keys * "\n"
30
+ end
31
+
32
+ private
33
+
34
+ def reload
35
+ @storage = {}
36
+
37
+ return if !File.exists?(@file)
38
+
39
+ File.open(@file, 'r') do |file|
40
+ @storage = Marshal.load(file)
41
+ end
42
+ end
43
+
44
+ def update
45
+ File.open(@file, 'w', 0600) do |file|
46
+ file << Marshal.dump(@storage)
47
+ end
48
+ end
49
+ end
50
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skeletonkey
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dennis Heckman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simple password storage and retrieval
14
+ email: denheck@gmail.com
15
+ executables:
16
+ - skeletonkey
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/skeletonkey
21
+ - lib/skeletonkey/cli.rb
22
+ - lib/skeletonkey/key_pair.rb
23
+ - lib/skeletonkey/password.rb
24
+ - lib/skeletonkey/safe.rb
25
+ homepage: http://rubygems.org/gems/skeletonkey
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Password Protection
49
+ test_files: []