Class: WIKK::Password

Inherits:
Object
  • Object
show all
Defined in:
lib/wikk_password.rb

Overview

READS/WRITES our private password file entries.

Constant Summary collapse

VERSION =
'0.1.2'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user, config, new_user = false) ⇒ Password

New. Fetches a user entry from the password file, or creates a new user (call via Passwd::add_user)

@param user [String] User name to fetch from password file, or to create, if new_user == true
@param config [WIKK:Configuration] or hash or class with attr_readers :passwordFile, :encryption, :key
@param new_user [Boolean] If true, then the user shouldn't be in password file.
@return [WIKK::Password]
@raise [IndexError] if the user entry exists.

Raises:

  • (IndexError)


21
22
23
24
25
26
27
28
29
# File 'lib/wikk_password.rb', line 21

def initialize(user, config, new_user=false)
   if config.class == Hash
     sym = config.each_with_object({}) { |(k,v),h| h[k.to_sym] = v }
     @config = Struct.new(*(k = sym.keys)).new(*sym.values_at(*k))
   else
 	  @config = config
   end
  raise IndexError, "User \"#{user}\" not found" if getpwnam(user) == false && !new_user
end

Instance Attribute Details

#passwordString (readonly)

the encrypted password, in form $type$initial_vector$encrypted_text

Returns:

  • (String)

    the current value of password



10
11
12
# File 'lib/wikk_password.rb', line 10

def password
  @password
end

#userString (readonly)

the decrypted text

Returns:

  • (String)

    the current value of user



10
11
12
# File 'lib/wikk_password.rb', line 10

def user
  @user
end

Class Method Details

.add_user(user, password, config) ⇒ Object

Adds a user to the password file

@param user [String] New user name. Raises an error if the user exists
@param password [String] Clear text password. Raises an error if this is nil or ''
@note Modifies the password file.
@raise [IndexError] if the user entry exists.
@raise [ArgumentError] if the password is nil or empty.

Raises:

  • (IndexError)


82
83
84
85
86
87
88
# File 'lib/wikk_password.rb', line 82

def self.add_user(user,password,config)
  user_record = self.new(user, config, true)
  raise IndexError, "User \"#{user}\" is already present"  if user_record.password != nil
  raise ArgumentError, "Password can't be empty" if password == nil || password == ''
  user_record.set_password(password)
  user_record.save
end

.valid_sha256_response?(user, config, challenge, response) ⇒ Boolean

Compare an SHA256 hashed password + challenge with this users password

@param user [String] User name to fetch from password file, or to create, if new_user == true
@param config [WIKK:Configuration] or hash or class with attr_readers :passwordFile, :encryption, :key
@param challenge [String] a random string, sent to the remote client, added to the password, and SHA256 hashed
@param response [String] the remote clients hex_SHA256(password + challenge)
@return [Boolean] True if the users password matches the one that created the response.
@note The password entry must be decryptable, not a UNIX style hash.
@raise [ArgumentError] if the encryption method is unknown.

Returns:

  • (Boolean)


56
57
58
# File 'lib/wikk_password.rb', line 56

def self.valid_sha256_response?(user, config, challenge, response)
  self.new(user, config).valid_sha256_response?(challenge, response)
end

Instance Method Details

#saveObject

Saves changes or a new user entry into the password file



91
92
93
94
95
# File 'lib/wikk_password.rb', line 91

def save
  loadfile
  @pwent[@user] = @password
  writefile
end

#set_password(password) ⇒ Object

Sets the user password, but does not save this. You must call save().

@param password [String] the clear text password to encypt
@return [String] the password file password entry.


34
35
36
# File 'lib/wikk_password.rb', line 34

def set_password(password) 
  @password = encrypt(password, @config.encryption)
end

#to_sObject

Outputs password file entry as a string

@return [String] password file entry.


99
100
101
# File 'lib/wikk_password.rb', line 99

def to_s
  "#{@user}:#{@password}"
end

#valid?(ct_password) ⇒ Boolean

Compares the password with the user’s password by encrypting the password passed in

@param password [String] The clear text password
@return [Boolean] True if the passwords match
@raise [ArgumentError] if the encryption method is unknown.

Returns:

  • (Boolean)


64
65
66
67
68
69
70
71
72
73
74
# File 'lib/wikk_password.rb', line 64

def valid?(ct_password)
  ignore,encryption,iv,password = @password.split('$')
  encryption = 'DES' if ignore != '' #No $'s in DES password, so ignore has text.
  case encryption
  when 'ct'; return ct_password == @password
  when 'aes256'; return encrypt(ct_password, encryption, iv) == @password
  when 'DES'; return UnixCrypt.valid?(ct_password, @password) 
  when 'MD5','1','SHA256','5','SHA512','6'; return UnixCrypt.valid?(ct_password, @password)
  else raise ArgumentError, "Unsupported encryption algorithm $#{encryption}"
  end
end

#valid_sha256_response?(challenge, response) ⇒ Boolean

Compare an SHA256 hashed password + challenge with this users password

@param challenge [String] a random string, sent to the remote client, added to the password, and SHA256 hashed
@param response [String] the remote clients hex_SHA256(password + challenge)
@return [Boolean] True if the users password matches the one that created the response.
@note The password entry must be decryptable, not a UNIX style hash.
@raise [ArgumentError] if the encryption method is unknown.

Returns:

  • (Boolean)


44
45
46
# File 'lib/wikk_password.rb', line 44

def valid_sha256_response?(challenge, response)
  return response == Digest::SHA256.digest(decrypt + challenge).unpack('H*')[0]
end