Class: Passlib::SCrypt
Overview
Handles scrypt password hashing via the scrypt gem.
Two hash formats are accepted on load:
-
Passlib MCF: $scrypt$ln=<ln>,r=<r>,p=<p>$<salt>$<checksum>
-
SCrypt gem: the native hex format produced by the scrypt gem (normalized to MCF on load)
New hashes are always produced in the passlib MCF format.
Constant Summary
Constants included from Internal::DSL
Instance Attribute Summary
Attributes inherited from Password
Class Method Summary collapse
-
.create(secret, **options) ⇒ SCrypt
Creates a new scrypt hash.
Instance Method Summary collapse
-
#create_comparable(secret) ⇒ SCrypt
A new instance hashed with the same salt and parameters.
- #upgrade? ⇒ Boolean
Methods inherited from Password
available?, #initialize, #inspect, load, #pretty_print, #verify
Methods included from Internal::DSL
Constructor Details
This class inherits a constructor from Passlib::Password
Class Method Details
.create(secret, **options) ⇒ SCrypt
Creates a new scrypt hash.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/passlib/scrypt.rb', line 30 class SCrypt < Password MCF_PATTERN = /\A\$scrypt\$ln=(\d+),r=(\d+),p=(\d+)\$(.+)\$(.+)\z/ RUBY_PATTERN = /\A([0-9a-f]+)\$([0-9a-f]+)\$([0-9a-f]+)\$([0-9a-f]{16,64})\$([0-9a-f]{32,1024})\Z/ private_constant :MCF_PATTERN, :RUBY_PATTERN external "scrypt", "~> 3.1" :ln, :n, :r, :p, :salt, :key_len register mcf: "scrypt", pattern: RUBY_PATTERN # @param secret [String] the plaintext password to re-hash # @return [SCrypt] a new instance hashed with the same salt and parameters def create_comparable(secret) self.class.create(secret, salt: @salt, ln: @ln, r: @r, p: @p, key_len: @key_len) end def upgrade? target_ln = config.n ? Math.log2(config.n).to_i : (config.ln || 16) @ln != target_ln end private def create(secret) @ln ||= config.n ? Math.log2(config.n).to_i : config.ln || 16 @r ||= config.r || 8 @p ||= config.p || 1 @salt ||= config.salt || Internal.random_bytes(16) @key_len ||= config.key_len || 32 @checksum ||= ::SCrypt::Engine.scrypt(secret, @salt, 2 ** @ln, @r, @p, @key_len) "$scrypt$ln=#{@ln},r=#{@r},p=#{@p}$#{Internal.encode64(@salt)}$#{Internal.encode64(@checksum)}" end def load(string) case string when MCF_PATTERN # passlib format match = Regexp.last_match @ln = match[1].to_i @r = match[2].to_i @p = match[3].to_i @salt = Internal.decode64(match[4]) @checksum = Internal.decode64(match[5]) @key_len = @checksum.length string when RUBY_PATTERN # scrypt gem format match = Regexp.last_match @ln = Math.log2(match[1].to_i(16)).to_i @r = match[2].to_i(16) @p = match[3].to_i(16) @salt = [match[4].sub(/^(00)+/, '')].pack('H*') @checksum = [match[5].sub(/^(00)+/, '')].pack('H*') @key_len = @checksum.length create(nil) else raise UnknownHashFormat, "invalid scrypt hash format" end end end |
Instance Method Details
#create_comparable(secret) ⇒ SCrypt
Returns a new instance hashed with the same salt and parameters.
41 42 43 |
# File 'lib/passlib/scrypt.rb', line 41 def create_comparable(secret) self.class.create(secret, salt: @salt, ln: @ln, r: @r, p: @p, key_len: @key_len) end |
#upgrade? ⇒ Boolean
45 46 47 48 |
# File 'lib/passlib/scrypt.rb', line 45 def upgrade? target_ln = config.n ? Math.log2(config.n).to_i : (config.ln || 16) @ln != target_ln end |