initial commit
This commit is contained in:
commit
f843df2d7a
3 files changed
+225
No files matched your search
@@ -0,0 +1,39 @@
|
||||
About Passy
|
||||
===========
|
||||
passy solves the problem of managing secure, unique passwords.
|
||||
|
||||
passy does NOT store anything to any disk. This means if your disk crashes
|
||||
you will not lose ANY of your passwords.
|
||||
|
||||
passy requires you to keep one, private, secret passkey. All of your unique
|
||||
passwords are generated from this one passkey.
|
||||
|
||||
Actual passwords are generated by HMAC-SHA1. For example, to calculate your
|
||||
password for a certain website, passy uses something similar to:
|
||||
|
||||
hmac_sha1('your secret key','slashdot.org')
|
||||
|
||||
passy provides four passwords for each 'site'. This way, if your password
|
||||
is ever expired, as some systems stupidly do, you can rotate to the next.
|
||||
|
||||
The 'site' doesn't have to be an actual web site, of course, it could be
|
||||
anything you want, like "bank password", "work login", etc.
|
||||
|
||||
NOTE: The list of Sites is currently stored directly in the script!
|
||||
|
||||
|
||||
Ideas for Improvement
|
||||
=====================
|
||||
* make variant passwords use more features (mixes in case, etc.).
|
||||
* use optionparser (or similar) to clean up the CLI
|
||||
* add ability to ask for a specific site
|
||||
* add ability to cache master key
|
||||
* use termios (or similar) to clean up the tty - but retain Windows compat
|
||||
* gemify it (and gemify my simple hmac separately?)
|
||||
* have passy look for ~/.passysites for the list of sites
|
||||
* wrap in a multi-platform GUI so idiots can use it too (wxRuby, RubyQT, FX, etc.)
|
||||
* add a "change master password" mode that will prompt for two passwords, and
|
||||
provide the results for both [after which the user much change their password
|
||||
at every site, etc.]
|
||||
* store state as to which variant is current at each site
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
#
|
||||
# Copyright (c) 2008 Stephen Waits <steve@waits.net>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
require 'digest/md5'
|
||||
require 'digest/rmd160'
|
||||
require 'digest/sha1'
|
||||
require 'digest/sha2'
|
||||
|
||||
# helper to make a 'length' long string filled with 'byte'
|
||||
def byte_string(byte, length)
|
||||
([byte]*length).pack('C*')
|
||||
end
|
||||
|
||||
# hmac algorithm - returns text version of hmac
|
||||
def hmac(key, data, digest_object, blocksize)
|
||||
# if key is too long, hash it
|
||||
key = digest_object.digest(key) if key.size > blocksize
|
||||
|
||||
# pad key out to blocksize
|
||||
key += byte_string(0,blocksize - key.size) if key.size < blocksize
|
||||
|
||||
# create pads
|
||||
ipad = byte_string(0x36,blocksize)
|
||||
opad = byte_string(0x5c,blocksize)
|
||||
blocksize.times { |i| ipad[i] ^= key[i]; opad[i] ^= key[i] }
|
||||
|
||||
# do the HMAC and return
|
||||
digest_object.hexdigest( opad + digest_object.digest( ipad + data ) )
|
||||
end
|
||||
|
||||
# hmac-md5
|
||||
def hmac_md5(key, data)
|
||||
hmac(key, data, Digest::MD5, 64)
|
||||
end
|
||||
|
||||
# hmac-rmd160
|
||||
def hmac_rmd160(key, data)
|
||||
hmac(key, data, Digest::RMD160, 64)
|
||||
end
|
||||
|
||||
# hmac-sha1
|
||||
def hmac_sha1(key, data)
|
||||
hmac(key, data, Digest::SHA1, 64)
|
||||
end
|
||||
|
||||
# hmac-sha256
|
||||
def hmac_sha256(key, data)
|
||||
hmac(key, data, Digest::SHA256, 64)
|
||||
end
|
||||
|
||||
# hmac-sha384
|
||||
def hmac_sha384(key, data)
|
||||
hmac(key, data, Digest::SHA384, 64)
|
||||
end
|
||||
|
||||
# hmac-sha512
|
||||
def hmac_sha512(key, data)
|
||||
hmac(key, data, Digest::SHA512, 128)
|
||||
end
|
||||
|
||||
# test vectors courtesy of RFC2202
|
||||
TestVectorsHMACMD5 = [
|
||||
[ byte_string(0xb,16),'Hi There','9294727a3638bb1c13f48ef8158bfc9d' ],
|
||||
[ 'Jefe','what do ya want for nothing?','750c783e6ab0b503eaa86e310a5db738' ],
|
||||
[ byte_string(0xaa,16),byte_string(0xdd,50),'56be34521d144c88dbb8c733f0e8b3f6' ],
|
||||
[ [1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19].pack('C*'),byte_string(0xcd,50),'697eaf0aca3a3aea3a75164746ffaa79' ],
|
||||
[ byte_string(0xc,16),'Test With Truncation','56461ef2342edc00f9bab995690efd4c' ],
|
||||
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key - Hash Key First','6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd' ],
|
||||
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data','6f630fad67cda0ee1fb1f562db3aa53e' ],
|
||||
]
|
||||
TestVectorsHMACSHA1 = [
|
||||
[ byte_string(0xb,20),'Hi There','b617318655057264e28bc0b6fb378c8ef146be00' ],
|
||||
[ 'Jefe','what do ya want for nothing?', 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79' ],
|
||||
[ byte_string(0xaa,20),byte_string(0xdd,50), '125d7342b9ac11cd91a39af48aa17b4f63f175d3' ],
|
||||
[ [1,2,3,4,5,6,7,8,9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19].pack('C*'),byte_string(0xcd,50),'4c9007f4026250c6bc8414f9bf50c86c2d7235da' ],
|
||||
[ byte_string(0xc,20),'Test With Truncation','4c1a03424b55e07fe7f27be1d58bb9324a9a5a04' ],
|
||||
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key - Hash Key First','aa4ae5e15272d00e95705637ce8a3b55ed402112' ],
|
||||
[ byte_string(0xaa,80),'Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data','e8e99d0f45237d786d6bbaa7965c7808bbff1a91' ],
|
||||
]
|
||||
|
||||
# test all of the above vectors
|
||||
def hmac_test
|
||||
TestVectorsHMACMD5.each do |t|
|
||||
key,data,result = t
|
||||
return false if hmac_md5(key,data) != result
|
||||
end
|
||||
TestVectorsHMACSHA1.each do |t|
|
||||
key,data,result = t
|
||||
return false if hmac_sha1(key,data) != result
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
#
|
||||
# Copyright (c) 2008 Stephen Waits <steve@waits.net>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
require 'hmac'
|
||||
|
||||
# list of sites we visit
|
||||
Sites = %w(
|
||||
paypal.com
|
||||
boardgamegeek.com
|
||||
google.com
|
||||
mahaenergy.com
|
||||
ma.gnolia.com
|
||||
)
|
||||
|
||||
# make sure our hmac is working properly
|
||||
if !hmac_test
|
||||
puts 'ERROR: HMAC test failed!'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# make sure no arguments specified (as these will mess up 'gets' below)
|
||||
if ARGV.size > 0
|
||||
puts 'ERROR: Do not specify any arguments.'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# prompt for password
|
||||
print ' Enter Password: '
|
||||
Key = gets.chomp
|
||||
print 'Verity Password: '
|
||||
if Key != gets.chomp
|
||||
puts 'Error: passwords do not match.'
|
||||
exit 1
|
||||
end
|
||||
|
||||
# helper to split an HMAC-SHA1 into four 10-character keys
|
||||
def make_passwords(key,site)
|
||||
hmac_sha1(key,site.downcase).unpack('A10A10A10A10')
|
||||
end
|
||||
|
||||
# output report
|
||||
puts
|
||||
Format = '%-30s %10s %10s %10s %10s'
|
||||
puts Format % [ 'Site', 'Password 1', 'Password 2', 'Password 3', 'Password 4' ]
|
||||
puts Format % [ '-'*30, '----------', '----------', '----------', '----------' ]
|
||||
Sites.sort.each do |s|
|
||||
p = make_passwords(Key,s)
|
||||
puts Format % [ s, p[0], p[1], p[2], p[3] ]
|
||||
end
|
||||
|
||||
|
||||
Reference in new issue
Block a user