wikk_password 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 01e1a95e77b30e4ca4435718e0a186724e5ac834
4
+ data.tar.gz: 72607fb401d8d0b150878c430348be5712a7b3b2
5
+ SHA512:
6
+ metadata.gz: f06e56560d9d71f61b6e1a115939049d68ceccd7742c3494985c5bb42a6bdfbe16d022df43f50b33f0c890038286b183056295353ec797c3e6a11fd92fafcf96
7
+ data.tar.gz: 466f382cbbb6a74af37be700ceb140c6c1bafcf999c80edcc90807dad571efa76af9cb765e365935ba584c323b57ebff3e9f9a62f74e31582afc3952e333b862
data/History.txt ADDED
@@ -0,0 +1,2 @@
1
+ robertburrowes Wed Jun 22 21:16:24 2016 +1200
2
+ first commit
data/Manifest.txt ADDED
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/wikk_password.rb
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # wikk_password
2
+
3
+ * http://wikarekare.github.com/wikk_password/
4
+ * Source https://github.com/wikarekare/wikk_password
5
+ * Gem https://rubygems.org/gems/wikk_password
6
+
7
+ ## DESCRIPTION:
8
+
9
+ Reads/writes password file entries of format user:password and provides tests for password validity.
10
+ Works with standard unix password types, clear text for testing, and decryptable AES_256_CBC.
11
+
12
+ ## FEATURES/PROBLEMS:
13
+
14
+ *Should have locking around the changes to the password file, but haven't gotten around to the Lockfile gem yet.
15
+
16
+ ## SYNOPSIS:
17
+
18
+ conf = WIKK::Configuration.new('test.js')
19
+ ```
20
+ require 'wikk_password'
21
+ require 'wikk_configuration
22
+
23
+ rachel = WIKK::Password.new('rachel', conf)
24
+ ```
25
+ ###Sample password file entry
26
+ ```
27
+ rob:$aes256$cxpzz9BMCOvyqfyngashHA==$Z9qOyqgMa4V7ffnI0NOjIhPv+ObAfhC0vyNPXoR5bbw=
28
+ ```
29
+ ###Sample Configuration file (or equivalent Ruby hash or any class with attr_reader :passwordFile, :encryption, :key )
30
+ ```
31
+ {
32
+ "passwordFile": "passwd",
33
+ "encryption": "aes256", //"none"
34
+ "key": "kzyE95G6OTkvteywPkhvP0Y9RhM8tZxQMnCOTH7LXrA="
35
+ }
36
+ ```
37
+
38
+ ## REQUIREMENTS:
39
+
40
+ ###Gem requires
41
+ * require 'unix_crypt'
42
+ * require 'wikk_aes_256'
43
+
44
+ ## INSTALL:
45
+
46
+ * sudo gem install unix_crypt wikk_aes_256 wikk_password
47
+
48
+ ## LICENSE:
49
+
50
+ (The MIT License)
51
+
52
+ Conversion of original wikarekare library to gem
53
+
54
+ Copyright (c) 2004-2016
55
+
56
+ Permission is hereby granted, free of charge, to any person obtaining
57
+ a copy of this software and associated documentation files (the
58
+ 'Software'), to deal in the Software without restriction, including
59
+ without limitation the rights to use, copy, modify, merge, publish,
60
+ distribute, sublicense, and/or sell copies of the Software, and to
61
+ permit persons to whom the Software is furnished to do so, subject to
62
+ the following conditions:
63
+
64
+ The above copyright notice and this permission notice shall be
65
+ included in all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
68
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
69
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
70
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
71
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
72
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
73
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ Hoe.plugin :yard
6
+
7
+ Hoe.spec 'wikk_password' do
8
+ self.readme_file = "README.md"
9
+ self.developer( "Rob Burrowes","r.burrowes@auckland.ac.nz")
10
+ remote_rdoc_dir = '' # Release to root
11
+
12
+ self.yard_title = 'wikk_password'
13
+ self.yard_options = ['--markup', 'markdown', '--protected']
14
+
15
+ self.dependency "unix_crypt", [">= 1.3.0"]
16
+ self.dependency "wikk_aes_256", [">= 0.1.4"]
17
+ end
18
+
19
+
20
+ #Validate manfest.txt
21
+ #rake check_manifest
22
+
23
+ #Local checking. Creates pkg/
24
+ #rake gem
25
+
26
+ #create doc/
27
+ #rake docs
28
+
29
+ #Copy up to rubygem.org
30
+ #rake release VERSION=1.0.1
@@ -0,0 +1,167 @@
1
+ module WIKK
2
+ require 'wikk_aes_256'
3
+ require 'digest/sha2'
4
+ require 'unix_crypt'
5
+ require 'base64'
6
+
7
+ #READS/WRITES our private password file entries.
8
+ # @attr_reader [String] user the decrypted text
9
+ # @attr_reader [String] password the encrypted password, in form $type$initial_vector$encrypted_text
10
+ class Password
11
+ VERSION = '0.1.0'
12
+
13
+ attr_reader :user, :password
14
+
15
+ #New. Fetches a user entry from the password file, or creates a new user (call via Passwd::add_user)
16
+ # @param user [String] User name to fetch from password file, or to create, if new_user == true
17
+ # @param config [WIKK:Configuration] or hash or class with attr_readers :passwordFile, :encryption, :key
18
+ # @param new_user [Boolean] If true, then the user shouldn't be in password file.
19
+ # @return [WIKK::Password]
20
+ # @raise [IndexError] if the user entry exists.
21
+ def initialize(user, config, new_user=false)
22
+ if config.class == Hash
23
+ sym = config.each_with_object({}) { |(k,v),h| h[k.to_sym] = v }
24
+ @config = Struct.new(*(k = sym.keys)).new(*sym.values_at(*k))
25
+ else
26
+ @config = config
27
+ end
28
+ raise IndexError, "User \"#{user}\" not found" if getpwnam(user) == false && !new_user
29
+ end
30
+
31
+ #Sets the user password, but does not save this. You must call save().
32
+ # @param password [String] the clear text password to encypt
33
+ # @return [String] the password file password entry.
34
+ def set_password(password)
35
+ @password = encrypt(password, @config.encryption)
36
+ end
37
+
38
+ #Compare an SHA256 hashed password + challenge with this users password
39
+ # @param challenge [String] a random string, sent to the remote client, added to the password, and SHA256 hashed
40
+ # @param response [String] the remote clients hex_SHA256(password + challenge)
41
+ # @return [Boolean] True if the users password matches the one that created the response.
42
+ # @note The password entry must be decryptable, not a UNIX style hash.
43
+ # @raise [ArgumentError] if the encryption method is unknown.
44
+ def valid_sha256_response?(challenge, response)
45
+ return response == Digest::SHA256.digest(decrypt + challenge).unpack('H*')[0]
46
+ end
47
+
48
+ #Compares the password with the user's password by encrypting the password passed in
49
+ # @param password [String] The clear text password
50
+ # @return [Boolean] True if the passwords match
51
+ # @raise [ArgumentError] if the encryption method is unknown.
52
+ def valid?(ct_password)
53
+ ignore,encryption,iv,password = @password.split('$')
54
+ encryption = DES if ignore != '' #No $'s in DES password, so ignore has text.
55
+ case encryption
56
+ when 'ct'; return ct_password == @password
57
+ when 'aes256'; return encrypt(ct_password, encryption, iv) == @password
58
+ when 'DES'; return UnixCrypt.valid?(ct_password, @password)
59
+ when 'MD5','1','SHA256','5','SHA512','6'; return UnixCrypt.valid?(ct_password, @password)
60
+ else raise ArgumentError, "Unsupported encryption algorithm $#{encryption}"
61
+ end
62
+ end
63
+
64
+ #Adds a user to the password file
65
+ # @param user [String] New user name. Raises an error if the user exists
66
+ # @param password [String] Clear text password. Raises an error if this is nil or ''
67
+ # @note Modifies the password file.
68
+ # @raise [IndexError] if the user entry exists.
69
+ # @raise [ArgumentError] if the password is nil or empty.
70
+ def self.add_user(user,password,config)
71
+ user_record = self.new(user, config, true)
72
+ raise IndexError, "User \"#{user}\" is already present" if user_record.password != nil
73
+ raise ArgumentError, "Password can't be empty" if password == nil || password == ''
74
+ user_record.set_password(password)
75
+ user_record.save
76
+ end
77
+
78
+ #Saves changes or a new user entry into the password file
79
+ def save
80
+ loadfile
81
+ @pwent[@user] = @password
82
+ writefile
83
+ end
84
+
85
+ #Outputs password file entry as a string
86
+ # @return [String] password file entry.
87
+ def to_s
88
+ "#{@user}:#{@password}"
89
+ end
90
+
91
+ private
92
+
93
+ #Fetch a password file entry by user's name
94
+ # @param user [String] user name
95
+ # @return [Boolean] True if user entry exists
96
+ def getpwnam(user)
97
+ loadfile
98
+ @user = user
99
+ @password = @pwent[@user]
100
+ return @password != nil #i.e. Found a user entry
101
+ end
102
+
103
+ #Read the password file into the @pwent hash
104
+ def loadfile
105
+ @pwent = {}
106
+ File.open(@config.passwordFile, "r") do |fd|
107
+ fd.each do |line|
108
+ tokens = line.chomp.split(/:/)
109
+ @pwent[tokens[0]] = tokens[1] if tokens[0] != ''
110
+ end
111
+ end
112
+ end
113
+
114
+ #Overwrite the password file from the @pwent hash
115
+ def writefile
116
+ File.open(@config.passwordFile, "w+") do |fd|
117
+ @pwent.each do |k,v|
118
+ fd.puts "#{k}:#{v}"
119
+ end
120
+ end
121
+ end
122
+
123
+ #Encrypts a clear text password
124
+ # @param password [String] The clear text password
125
+ # @param challenge [String] Norm
126
+ # @raise [ArgumentError] if the encryption algorithm isn't known.
127
+ def encrypt(password, algorithm = "aes256", pwd_iv = nil)
128
+ case algorithm
129
+ when "aes256"
130
+ password,key,iv = WIKK::AES_256.cipher_to_s(password, @config.key, pwd_iv)
131
+ return "$aes256$#{iv}$#{password}"
132
+ when "DES"
133
+ return UnixCrypt::DES.build(password)
134
+ when "MD5","1" #Unix passward digest, which is multiple hashes
135
+ return UnixCrypt::MD5.build(password)
136
+ when "SHA256","5" #Unix passward digest, which is multiple hashes
137
+ return UnixCrypt::SHA256.build(password)
138
+ when "SHA512","6" #Unix passward digest, which is multiple hashes
139
+ return UnixCrypt::SHA512.build(password)
140
+ when 'ct' #ct == clear text
141
+ return "$ct$$#{password}"
142
+ else
143
+ raise ArgumentError, "Unsupported Encryption algorithm #{@config.encryption}"
144
+ end
145
+ end
146
+
147
+ #Decrypts @password, if this is possible
148
+ # @return [String] the clear text password
149
+ # @raise [ArgumentError] if the encryption type can't be decrypted.
150
+ def decrypt
151
+ ignore,encryption,iv,password = @password.split('$')
152
+ case encryption
153
+ when 'ct' ; password
154
+ when 'aes256'
155
+ ct_password, ct_key, ct_iv = WIKK::AES_256.decrypt(password, true, @config.key, iv)
156
+ return ct_password
157
+ else
158
+ raise ArgumentError, "Unsupported decryption algorithm #{@config.encryption}"
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+
165
+
166
+
167
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wikk_password
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Burrowes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: unix_crypt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: wikk_aes_256
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: hoe-yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: hoe
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.15'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.15'
69
+ description: |-
70
+ Reads/writes password file entries of format user:password and provides tests for password validity.
71
+ Works with standard unix password types, clear text for testing, and decryptable AES_256_CBC.
72
+ email:
73
+ - r.burrowes@auckland.ac.nz
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files:
77
+ - History.txt
78
+ - Manifest.txt
79
+ - README.md
80
+ files:
81
+ - History.txt
82
+ - Manifest.txt
83
+ - README.md
84
+ - Rakefile
85
+ - lib/wikk_password.rb
86
+ homepage: http://wikarekare.github.com/wikk_password/
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options:
92
+ - "--markup"
93
+ - markdown
94
+ - "--protected"
95
+ - "--title"
96
+ - wikk_password
97
+ - "--quiet"
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.5.1
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Reads/writes password file entries of format user:password and provides tests
116
+ for password validity
117
+ test_files: []