Class: CryptCheckpass::Scrypt
- Inherits:
-
CryptCheckpass
- Object
- CryptCheckpass
- CryptCheckpass::Scrypt
- Extended by:
- PHCStringFormat
- Defined in:
- lib/crypt_checkpass/scrypt.rb
Overview
This class is to support RFC7914-related hash variants.
Format:
Life gets extremely hard here because Ruby's scrypt
gem does not follow the
Modular Crypt Format. You cannot tell if a string is scrypt-generated or not
by looking at its beginning.
%r{
(?<N> [0-9a-f]+ ){0}
(?<r> [0-9a-f]+ ){0}
(?<p> [0-9a-f]+ ){0}
(?<salt> [0-9a-f]+ ){0}
(?<csum> [0-9a-f]+ ){0}
\A \g<N>
[$] \g<r>
[$] \g<p>
[$] \g<salt>
[$] \g<csum>
\z
}x
N
is the CPU/Memory cost parameter N ("costParameter").r
is the block size parameter r ("blockSize").p
is the parallelization parameter p ("parallelizationParameter").salt
is the salt string.csum
is the checksum strgng.
All of above fields are represented as hexadecimal numbers.
This is too different from other password hashs. To ease the situation we also follow extra format that is compatible with Python's Passlib and npm's @phc/scrypt generates.
%r{
(?<id> scrypt ){0}
(?<ln> ln=[1-9][0-9]* ){0}
(?<r> r=[1-9][0-9]* ){0}
(?<p> p=[1-9][0-9]* ){0}
(?<salt> [a-zA-Z0-9+/]* ){0}
(?<csum> [a-zA-Z0-9+/]* ){0}
\A [$] \g<id>
[$] \g<ln>
[,] \g<r>
[,] \g<p>
[$] \g<salt>
[$] \g<csum>
\z
}x
This is a strict PHC string format. See also PHCStringFormat
Parameters are
ln
,r
, andp
whereln
deontes log2(N).
Other formats:
Seems there are no such thing like a standard way to encode scrypt-generated passwords. Lots of wild formats are seen. We could support them if they have actual usage and to be migrated to another format.
variant
$7$
: seem in http://mail.tarsnap.com/scrypt/msg00063.html. Not sure if it has actual applications.variant
$s1$
: https://github.com/technion/libscrypt generates this.variant
$$scrypt-mcf$
: the default output of https://libpasta.github.ioRecent OpenSSL (1.1.0+) does have EVP_PBE_scrypt() implemented, but generates pure-binary raw checksums without any formats.
Class Method Summary collapse
-
.checkpass?(pass, hash) ⇒ true, false
Checks if the given password matches the hash.
-
.newhash(pass, id: 'scrypt', ln: 8, r: 8, p: 1) ⇒ String
Generate a new password hash string.
-
.provide?(id) ⇒ true, false
Checks if the given ID can be handled by this class.
-
.understand?(str) ⇒ true, false
Checks if the given hash string can be handled by this class.
Methods inherited from CryptCheckpass
crypt_checkpass?, crypt_newhash
Class Method Details
.checkpass?(pass, hash) ⇒ true, false
Checks if the given password matches the hash.
128 129 130 131 132 133 134 135 |
# File 'lib/crypt_checkpass/scrypt.rb', line 128 def self.checkpass? pass, hash require 'scrypt' case hash when /\A\$scrypt\$/ then return checkpass_phc pass, hash else return checkpass_gem pass, hash end end |
.newhash(pass, id: 'scrypt', ln: 8, r: 8, p: 1) ⇒ String
There is no way to specify salt. That's a bad idea.
Generate a new password hash string.
149 150 151 152 153 154 155 156 |
# File 'lib/crypt_checkpass/scrypt.rb', line 149 def self.newhash pass, id: 'scrypt', ln: 8, r: 8, p: 1 require 'scrypt' salt = SecureRandom.random_bytes ::SCrypt::Engine::DEFAULTS[:salt_size] klen = ::SCrypt::Engine::DEFAULTS[:key_len] csum = ::SCrypt::Engine.scrypt pass, salt, 2 ** ln, r, p, klen return phcencode 'scrypt', { ln: ln, r: r, p: p }, salt, csum end |
.provide?(id) ⇒ true, false
Checks if the given ID can be handled by this class. A class is free to handle several IDs, like 'argon2i', 'argon2d', ...
138 139 140 |
# File 'lib/crypt_checkpass/scrypt.rb', line 138 def self.provide? id return id == 'scrypt' end |
.understand?(str) ⇒ true, false
Checks if the given hash string can be handled by this class.
123 124 125 |
# File 'lib/crypt_checkpass/scrypt.rb', line 123 def self.understand? str return match? str, understander end |