class CryptCheckpass
Mother of all KDF classes.
Subclasses of this are expected to implement the following 4 class methods:
-
`subclass.provide?(id)`
-
`subclass.newhash(pass, id: id, …)`
-
`subclass.understand?(hash)`
-
`subclass.checkpass?(pass, hash)`
If a subclass's `provide?` returns `true` for an id, then that class is responsible for generating new hash of that id. Likewise if `understand?` returns `true` for a hash, that should be able to checkpass.
Caveats:
-
You don't have to provide all of those methods. It is completely reasonable to have a hash that is unable to generate new one, but still able to check existing ones.
Public Class Methods
Checks if the given password matches the hash.
@param pass [String] a password to test. @param hash [String] a good hash digest string. @return [true] they are identical. @return [false] they are distinct. @raise [NotImplementedError] don't know how to parse hash.
# File lib/crypt_checkpass/api.rb, line 107 def checkpass? pass, hash return false # default false end
(see ::#crypt_checkpass?)
# File lib/crypt_checkpass/api.rb, line 54 def crypt_checkpass? pass, hash kdf = find_kdf_by_string hash return kdf.checkpass? pass, hash end
(see ::#crypt_newhash)
# File lib/crypt_checkpass/api.rb, line 60 def crypt_newhash password, pref = nil, id: nil, **kwargs raise ArgumentError, <<-"end".strip if pref && id wrong number of arguments (given 2, expected 1) end raise ArgumentError, <<-"end".strip, kwargs.keys if pref &&! kwargs.empty? unknown key: %p end if pref then require_relative 'bcrypt' return CryptCheckpass::Bcrypt.new_with_openbsd_pref password, pref else kdf = find_kdf_by_id id return kdf.newhash password, id: id, **kwargs end end
Generate a new password hash string.
@note There is no way to specify salt. That's a bad idea. @return [String] hashed digest string of password.
# File lib/crypt_checkpass/api.rb, line 115 def newhash *; raise 'NOTREACHED' end
Checks if the given ID can be handled by this class. A class is free to handle several IDs, like 'argon2i', 'argon2d', …
@param id [String] hash function ID. @return [true] it does. @return [false] it desn't.
# File lib/crypt_checkpass/api.rb, line 87 def provide? id return false # default false end
Checks if the given hash string can be handled by this class.
@param str [String] a good hashed string. @return [true] it does. @return [false] it desn't.
# File lib/crypt_checkpass/api.rb, line 96 def understand? str return false # default false end
Private Class Methods
# File lib/crypt_checkpass/api.rb, line 212 def find_kdf_by_id id kdf = @kdfs.find {|i| i.provide? id } return kdf if kdf raise ArgumentError, <<-"end".strip, id don't know how to generate %s hash. end end
# File lib/crypt_checkpass/api.rb, line 220 def find_kdf_by_string str kdf = @kdfs.find {|i| i.understand? str } return kdf if kdf raise ArgumentError, <<-"end".strip, str don't know how to parse %p, maybe clobbered? end end
@!endgroup
# File lib/crypt_checkpass/api.rb, line 207 def inherited klass super @kdfs.push klass end
Fallback routine counterpart. @param re [Regexp] the language to accept. @param str [String] target string to test. @return [true] accepted. @return [false] otherwise.
# File lib/crypt_checkpass/api.rb, line 175 def match? str, re return re.match? str end
# File lib/crypt_checkpass/api.rb, line 200 def phcdecode str require 'phc_string_format' return PhcStringFormat::Formatter.parse str end
@!group PhcStringFormat wrappers
# File lib/crypt_checkpass/api.rb, line 194 def phcencode id, params, salt, csum require 'phc_string_format' return PhcStringFormat::Formatter.format \ id: id, params: params, salt: salt, hash: csum end
Utility raise + printf function. It is quite hard to think of exceptions that only concern fixed strings. @shyouhei really doesn't understand why this is not a canon.
@overload raise(klass, fmt, *va_args)
@param klass [Class] exception class. @param fmt [String] printf-format string. @param va_args [Array] anything. @raise [klass] always raises a klass instance.
@overload raise(fmt, *va_args)
@param fmt [String] printf-format string. @param va_args [Array] anything. @raise [RuntimeError] always raises a RuntimeError.
# File lib/crypt_checkpass/api.rb, line 139 def raise class_or_string, *argv case class_or_string when Class, Exception then klass = class_or_string string = sprintf(*argv) when String then klass = RuntimeError string = class_or_string % argv else # recursion raise TypeError, <<-"end".strip wrong argument type %p (%p expected) end end return super klass, string, caller end
Utility gem + require function. It is often the case a library is a gem and calling gem before require is desirable.@shyouhei really doesn't understand why this is not a canon.
@return [void] @param gem [String] gem name. @param lib [String] library name. @raise [Gem::LoadError] gem not found. @raise [LoadError] lib not found.
# File lib/crypt_checkpass/api.rb, line 164 def require gem, lib = gem Kernel.gem gem Kernel.require lib end