dpass 0.0.1.alpha07
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +57 -0
- data/Rakefile +7 -0
- data/TODO.md +64 -0
- data/bin/dpass +20 -0
- data/dpass.gemspec +22 -0
- data/lib/dpass.rb +120 -0
- data/lib/dpass/settings.rb +26 -0
- data/lib/dpass/version.rb +3 -0
- data/spec/dpass_spec.rb +53 -0
- data/spec/spec_helper.rb +1 -0
- metadata +129 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Info Access LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# WARNING!!! DO NOT USE! NEITHER COMPLETE OR WELL-TESTED!
|
2
|
+
Please check back soon a usable version...
|
3
|
+
|
4
|
+
# Dpass [![Build Status](https://secure.travis-ci.org/Spikels/dpass.png)](http://travis-ci.org/Spikels/dpass)
|
5
|
+
|
6
|
+
Application specific passwords derived from your secret master password using [PBKDF2](http://en.wikipedia.org/wiki/PBKDF2) from OpenSSL already installed on your computer.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Dpass currently requires Ruby 1.9.x but should soon work for all versions.
|
11
|
+
|
12
|
+
Install the gem:
|
13
|
+
|
14
|
+
$ gem install dpass --pre
|
15
|
+
|
16
|
+
You need a personal dpass salt file in your home directory (~/.dpass). The SAME salt file must be installed in the home directory on each machine you want to run dpass or else you will get different derived passwords. So if you already have one you use, copy any perviously created salt file to your home directory.
|
17
|
+
|
18
|
+
If this is the first time you are using dpass, go ahead and create a new personal salt file:
|
19
|
+
|
20
|
+
$ dpass -new_salt
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
$ dpass <application_1>[...<application_N>]
|
25
|
+
|
26
|
+
For example to generate a password for Gmail and Yahoo
|
27
|
+
|
28
|
+
$ dpass gmail yahoo
|
29
|
+
|
30
|
+
You will be asked for your master password then a password will be generated for each application specified.
|
31
|
+
|
32
|
+
## Background
|
33
|
+
|
34
|
+
The theft of passwords from internet sites seems to be an [increasingly](http://press.linkedin.com/node/1212) [common](http://ycorpblog.com/2012/07/13/yahoo-0713201/) [occurance](http://us.blizzard.com/en-us/securityupdate.html). Combined with the common practice of using either the same or related passwords across this is a serious security risk.
|
35
|
+
|
36
|
+
Clearly you should have a independent and strong password for every site you visit. I recently took Dan Boneh's excellent Cryptography class on [Coursera](https://www.coursera.org/course/crypto) and learned that this well known problem, known as "password based key derivation", has standard solutions.
|
37
|
+
|
38
|
+
Inspired by a [broken idea](http://news.ycombinator.com/item?id=4373909) on Hacker News and ignoring warnings to never even think about building your own crypto I made dpass.
|
39
|
+
|
40
|
+
## Other Password Managers
|
41
|
+
|
42
|
+
[LastPass](https://lastpass.com/), [KeePass](http://keepass.info/), [PwdHash](https://www.pwdhash.com/)
|
43
|
+
|
44
|
+
## References
|
45
|
+
|
46
|
+
* Dan Boneh - Key Derivation Lecture - http://www.youtube.com/watch?v=ZorKf6IaP0Q
|
47
|
+
* PKCS #5 RFC - http://tools.ietf.org/html/rfc2898
|
48
|
+
* PBKDF2 Test Vectors RFC - http://tools.ietf.org/html/rfc6070
|
49
|
+
* OpenSSL Gem PKCS5 - http://www.ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/PKCS5.html
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it
|
54
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
55
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
56
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
57
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/TODO.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
|
4
|
+
* General
|
5
|
+
* Make work under Ruby 1.8.x (must be using 1.9 syntax)
|
6
|
+
|
7
|
+
|
8
|
+
* Tests
|
9
|
+
* DONE-Add Travis CI
|
10
|
+
* Figure out how to mock the 2 file system tests
|
11
|
+
* Add tests to new code & test frist going forward!
|
12
|
+
* Test under Ruby 1.8.x (Travis)
|
13
|
+
* ??? - Test on Windows
|
14
|
+
|
15
|
+
|
16
|
+
* Command-line
|
17
|
+
* DONE-Allow multiple applications (i.e. dpass gmail yahoo)
|
18
|
+
* Add --init command (test install, new-salt & print basic instructions)
|
19
|
+
* Add --test command (check ruby version, openssl, ...)
|
20
|
+
|
21
|
+
|
22
|
+
* Create salt file (~/.dpass)
|
23
|
+
* DONE-Check if file already exists. If so abort with message to delete manually if you really want a NEW salt file.
|
24
|
+
* DONE-Generate 128-bit random salt (32 hex chars)
|
25
|
+
* DONE-Save to file ~/.dpass
|
26
|
+
* DONE-Set permission to 600
|
27
|
+
* Handle File.open errors
|
28
|
+
* Handle File.chown errors
|
29
|
+
* ???-Append new salts so old salts are not lost (w/ create date?)
|
30
|
+
|
31
|
+
|
32
|
+
* Validate salt file
|
33
|
+
* DONE - Warn if salt file permission is not 0600 (Is this OS specific?)
|
34
|
+
* Check salt is valid length
|
35
|
+
* Check salt is hex character set only
|
36
|
+
* ???-Check that salt seems random (how?)
|
37
|
+
|
38
|
+
* Read salt file (~/.dpass)
|
39
|
+
* DONE-Check that file exists. If not abort with message to copy existing salt or create new salt if you REALLY want to.
|
40
|
+
* DONE-Read salt file
|
41
|
+
* DONE-Warn if salt file permission is not 0600 (Is this OS specific?)
|
42
|
+
|
43
|
+
* Master password
|
44
|
+
* DONE-Remove highline dependency
|
45
|
+
* DONE-Clear from memory ASAP string.replace
|
46
|
+
* Allow delete/backspace when entering master password
|
47
|
+
|
48
|
+
* Settings
|
49
|
+
* Remove calculated settings from setting.rb (put in dpass.rb)
|
50
|
+
* Check HASH_ITER is reasonable before use
|
51
|
+
* Check PASS_LENGTH is reasonable before use
|
52
|
+
* Check SYMBOL_COUNT is reasonable before use
|
53
|
+
* Check SYMBOLS.length is reasonable before use
|
54
|
+
* Check SYMBOLS is reasonable before use
|
55
|
+
|
56
|
+
* Input validation
|
57
|
+
* DONE-Warn if master pass length < WARN_MASTER_PASS_LENGTH
|
58
|
+
* ???-Fail if master pass length < MIN_MASTER_PASS_LENGTH
|
59
|
+
|
60
|
+
* Output password
|
61
|
+
* DONE-Fixed length (PASS_LENGTH_SYMBOLS) - gen too long then truncate
|
62
|
+
* DONE-Copy password to clipboard (only for single passwords)
|
63
|
+
* DONE-Erase password from clipboard after WIPE_CLIPBOARD_DELAY seconds
|
64
|
+
* Guarantee specified bits of randomness (SYMBOL_COUNT, PASS_LENGTH)
|
data/bin/dpass
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'dpass'
|
3
|
+
require 'trollop'
|
4
|
+
|
5
|
+
opts = Trollop::options do
|
6
|
+
version Dpass::VERSION
|
7
|
+
banner <<-EOS
|
8
|
+
dpass derives application specific passwords from your master password
|
9
|
+
Usage: dpass [options] <app_name> [<app_name_2>...<app_name_N>]
|
10
|
+
where [options] are:
|
11
|
+
EOS
|
12
|
+
opt :new_salt, "Generate new salt file (~/.dpass)"
|
13
|
+
end
|
14
|
+
|
15
|
+
if opts[:new_salt]
|
16
|
+
Dpass.new_salt
|
17
|
+
else
|
18
|
+
Trollop::die "must supply at least one app_name" if ARGV.length == 0
|
19
|
+
Dpass.derive
|
20
|
+
end
|
data/dpass.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/dpass/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Spikels"]
|
6
|
+
gem.email = ["spikels@infoaccess.org"]
|
7
|
+
gem.description = %q{Derive application specific passwords from secret master password using PBKDF2 in OpenSSL}
|
8
|
+
gem.summary = %q{Derive application specific passwords}
|
9
|
+
gem.homepage = "https://github.com/Spikels/dpass"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = ['dpass']
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "dpass"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Dpass::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency('rspec')
|
19
|
+
gem.add_development_dependency('rake')
|
20
|
+
gem.add_dependency('trollop')
|
21
|
+
gem.add_dependency('clipboard')
|
22
|
+
end
|
data/lib/dpass.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'dpass/version'
|
2
|
+
require 'dpass/settings'
|
3
|
+
require 'openssl'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'clipboard'
|
6
|
+
|
7
|
+
SALT = Dpass::SALT_PATH
|
8
|
+
|
9
|
+
module Dpass
|
10
|
+
|
11
|
+
def self.derive
|
12
|
+
verify_settings()
|
13
|
+
salt = read_salt()
|
14
|
+
master_pass = get_password_masked()
|
15
|
+
ARGV.each do |app_name|
|
16
|
+
pass_bytes = Dpass.derive_raw_hex(master_pass,
|
17
|
+
salt+app_name,
|
18
|
+
Dpass::HASH_ITER,
|
19
|
+
Dpass::PASS_LENGTH_BYTES)
|
20
|
+
pass_syms = Dpass.rebase_bytes(pass_bytes, Dpass::SYMBOL_COUNT)
|
21
|
+
pass = pass_syms.map {|c| Dpass::SYMBOLS[c]}.join
|
22
|
+
pass = pass[0..(PASS_LENGTH_SYMBOLS-1)]
|
23
|
+
puts "#{app_name}: #{pass}"
|
24
|
+
Clipboard.copy pass
|
25
|
+
delay_wipe_clipboard()
|
26
|
+
end
|
27
|
+
# Overwrite master password in memory with random bytes
|
28
|
+
master_pass.replace SecureRandom.random_bytes(master_pass.length)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.rebase_bytes(hex_string, new_base)
|
32
|
+
num = hex_string.to_i(16)
|
33
|
+
result = []
|
34
|
+
while num > 0
|
35
|
+
result.unshift num % new_base
|
36
|
+
num /= new_base
|
37
|
+
end
|
38
|
+
result.shift #Remove biased-downward first digit (not always needed)
|
39
|
+
return result
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.get_password_masked(mask='*')
|
43
|
+
buffering = $stdout.sync
|
44
|
+
$stdout.sync = true
|
45
|
+
stty_settings = %x[stty -g]
|
46
|
+
begin
|
47
|
+
%x[stty -echo]
|
48
|
+
%x[stty -icanon]
|
49
|
+
print 'Enter Master Password: '
|
50
|
+
password = ""
|
51
|
+
while ( char = $stdin.getc ) != "\n" # break after [Enter]
|
52
|
+
putc mask
|
53
|
+
password << char
|
54
|
+
end
|
55
|
+
ensure
|
56
|
+
%x[stty #{stty_settings}]
|
57
|
+
$stdout.sync = buffering
|
58
|
+
puts
|
59
|
+
end
|
60
|
+
password.chomp
|
61
|
+
if password.length < WARN_MASTER_PASS_LENGTH
|
62
|
+
puts "WARNING: Your master password should be at least #{WARN_MASTER_PASS_LENGTH} characters long."
|
63
|
+
end
|
64
|
+
return password
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.derive_raw_hex(pass, salt, iter, keylen)
|
68
|
+
OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass,salt,iter,keylen).unpack('H*')[0]
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.generate_salt
|
72
|
+
SecureRandom.hex(Dpass::SALT_SIZE)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.read_salt
|
76
|
+
Dpass.verify_salt
|
77
|
+
File.open(SALT, 'rb') {|f| f.read.strip}
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.new_salt
|
81
|
+
if File.exists?(SALT)
|
82
|
+
raise StandardError, "ERROR: dpass salt file (#{SALT}) already exists. A NEW SALT FILE WILL BREAK ALL EXISTING DERIVED PASSWORDS! If you really want this, you must manually delete or move the existing salt file."
|
83
|
+
else
|
84
|
+
new_value = Dpass.generate_salt
|
85
|
+
File.open(SALT, 'wb', 0600) {|f| f.write new_value + "\n"}
|
86
|
+
# Verify salt file
|
87
|
+
Dpass.verify_salt(new_value)
|
88
|
+
puts "Generated new random salt: #{new_value}"
|
89
|
+
puts "Saved to #{SALT}, set permission (0600) and verfied"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.verify_salt(expected_value = nil)
|
94
|
+
if !File.exists?(SALT)
|
95
|
+
raise StandardError, "ERROR: salt file (#{SALT}) does not exist. Use 'dpass salt' command to create a new one"
|
96
|
+
end
|
97
|
+
currrent_salt = File.open(SALT, 'rb')
|
98
|
+
if expected_value && expected_value != currrent_salt
|
99
|
+
raise StandardError, "ERROR: salt in file does not match new salt just create"
|
100
|
+
end
|
101
|
+
# WARNING: PERMISSION BITS ARE PROBABLY OS SPECIFIC...
|
102
|
+
if (mode = File.stat(SALT).mode) != 33152 # 100600 in octal
|
103
|
+
puts "WARNING: salt file (#{SALT}) permission not strict enough (#{sprintf("%o",mode)[2..-1]}). Use 'chmod 0600 ~/.dpass' limit access only to user."
|
104
|
+
end
|
105
|
+
### Check length
|
106
|
+
### Check character set
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.verify_settings
|
110
|
+
# TODO-Check: HASH_ITER, PASS_LENGTH, SYMBOL_COUNT, SYMBOLS.length
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.delay_wipe_clipboard
|
114
|
+
job1 = fork do
|
115
|
+
sleep WIPE_CLIPBOARD_DELAY
|
116
|
+
Clipboard.clear
|
117
|
+
end
|
118
|
+
Process.detach(job1)
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Dpass
|
2
|
+
SYMBOL_SETS = {
|
3
|
+
'Printable'=>"!\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
|
4
|
+
'Selectable'=>"+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\\_abcdefghijklmnopqrstuvwxyz~",
|
5
|
+
'Alphanumeric'=>"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
6
|
+
'Alphabet'=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
7
|
+
'AlphanumericUppercase'=>"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
8
|
+
'AlphanumericLowercase'=>"0123456789abcdefghijklmnopqrstuvwxyz",
|
9
|
+
'AlphabetUppercase'=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
10
|
+
'AlphabetLowercase'=>"abcdefghijklmnopqrstuvwxyz",
|
11
|
+
'HexadecimalUppercase'=>"0123456789ABCDEF",
|
12
|
+
'HexadecimalLowercase'=>"0123456789abcdef",
|
13
|
+
'Numerals'=>"0123456789"}
|
14
|
+
SYMBOL_SET = 'Alphanumeric'
|
15
|
+
SYMBOLS = SYMBOL_SETS[SYMBOL_SET] # *** CALC - NOT SETTING! ***
|
16
|
+
SYMBOL_COUNT = SYMBOLS.length # *** CALC - NOT SETTING! ***
|
17
|
+
HASH_ITER = 4096
|
18
|
+
PASS_LENGTH_SYMBOLS = 14 # Base SYMBOL_COUNT
|
19
|
+
# NEED TO CALCULATE REQUIRED BYTE LENGTH (ROUNDING UP!)
|
20
|
+
PASS_LENGTH_BYTES = 12 # Base 256 *** CALC - NOT SETTING! ***
|
21
|
+
SALT_PATH = ENV['HOME']+'/.dpass'
|
22
|
+
SALT_SIZE = 16 # in bytes - hex is double this
|
23
|
+
MIN_MASTER_PASS_LENGTH = 8
|
24
|
+
WARN_MASTER_PASS_LENGTH = 10
|
25
|
+
WIPE_CLIPBOARD_DELAY = 30
|
26
|
+
end
|
data/spec/dpass_spec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
TEST_VECTORS = [
|
5
|
+
['password','salt',1,20,'0c60c80f961f0e71f3a9b524af6012062fe037a6'],
|
6
|
+
['password','salt',2,20,'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'],
|
7
|
+
['password','salt',4096,20,'4b007901b765489abead49d926f721d065a429c1'],
|
8
|
+
# ['password','salt',16777216,20,'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'],
|
9
|
+
['passwordPASSWORDpassword','saltSALTsaltSALTsaltSALTsaltSALTsalt',4096, 25,'3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'],
|
10
|
+
["pass\0word","sa\0lt",4096,16,'56fa6aa75548099dcc37d7f03425e0c3']
|
11
|
+
]
|
12
|
+
|
13
|
+
describe Dpass do
|
14
|
+
describe "Verify RFC 6070 test vectors" do
|
15
|
+
i = 0
|
16
|
+
TEST_VECTORS.each do |data|
|
17
|
+
i += 1
|
18
|
+
it "matches test vector #{i}" do
|
19
|
+
Dpass.derive_raw_hex(data[0],data[1],data[2],data[3]).should eq(data[4])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "Reading salt file" do
|
25
|
+
it "should raise error if file does not exist" do
|
26
|
+
File.stub!(:exists?).and_return(false)
|
27
|
+
expect{Dpass.read_salt}.to raise_error(StandardError)
|
28
|
+
end
|
29
|
+
# This only works with actual salt file. Need to figure out how to
|
30
|
+
# mock files...
|
31
|
+
# it "should have correct length" do
|
32
|
+
# Dpass.read_salt.length.should eq(32)
|
33
|
+
# end
|
34
|
+
# it "should contain only hexidecimal characters" do
|
35
|
+
# Dpass.read_salt.gsub(/[0-9a-f]/,'').length.should eq(0)
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "Generating new salt file" do
|
40
|
+
describe "generate a random salt string" do
|
41
|
+
it "should be non-nil" do
|
42
|
+
Dpass.generate_salt.length.should eq(32)
|
43
|
+
end
|
44
|
+
it "should contain only hexidecimal characters" do
|
45
|
+
Dpass.generate_salt.gsub(/[0-9a-f]/,'').length.should eq(0)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
it "should not change an existing salt file" do
|
49
|
+
File.stub!(:exists?).and_return(true)
|
50
|
+
expect{Dpass.new_salt}.to raise_error(StandardError)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'dpass'
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dpass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.alpha07
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Spikels
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: trollop
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: clipboard
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Derive application specific passwords from secret master password using
|
79
|
+
PBKDF2 in OpenSSL
|
80
|
+
email:
|
81
|
+
- spikels@infoaccess.org
|
82
|
+
executables:
|
83
|
+
- dpass
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- .rspec
|
89
|
+
- .travis.yml
|
90
|
+
- CHANGELOG.md
|
91
|
+
- Gemfile
|
92
|
+
- LICENSE
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- TODO.md
|
96
|
+
- bin/dpass
|
97
|
+
- dpass.gemspec
|
98
|
+
- lib/dpass.rb
|
99
|
+
- lib/dpass/settings.rb
|
100
|
+
- lib/dpass/version.rb
|
101
|
+
- spec/dpass_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
homepage: https://github.com/Spikels/dpass
|
104
|
+
licenses: []
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>'
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.3.1
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.8.24
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Derive application specific passwords
|
127
|
+
test_files:
|
128
|
+
- spec/dpass_spec.rb
|
129
|
+
- spec/spec_helper.rb
|