Class: CryptCheckpass::Scrypt

Inherits:
CryptCheckpass show all
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, and p where ln 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.

Examples:

crypt_newhash 'password', id: 'scrypt'
# => "$scrypt$ln=8,r=8,p=1$aL2uvFKrfoVkxAgy1j/Y4OAJ8D0p1yP/uqFg3UU8t64$/xZGQyALLQrKzaBRGwzGCw+FGgRqFwyCfZddC5qvZYA"
crypt_checkpass? 'password', '$scrypt$ln=8,r=8,p=1$aL2uvFKrfoVkxAgy1j/Y4OAJ8D0p1yP/uqFg3UU8t64$/xZGQyALLQrKzaBRGwzGCw+FGgRqFwyCfZddC5qvZYA'
# => true

See Also:

Class Method Summary collapse

Methods inherited from CryptCheckpass

crypt_checkpass?, crypt_newhash

Class Method Details

.checkpass?(pass, hash) ⇒ true, false

Checks if the given password matches the hash.

Parameters:

  • pass (String)

    a password to test.

  • hash (String)

    a good hash digest string.

Returns:

  • (true)

    they are identical.

  • (false)

    they are distinct.

Raises:

  • (NotImplementedError)

    don't know how to parse 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

Note:

There is no way to specify salt. That's a bad idea.

Generate a new password hash string.

Parameters:

  • pass (String)

    raw binary password string.

  • id (String) (defaults to: 'scrypt')

    name of the algorithm (ignored)

  • ln (Integer) (defaults to: 8)

    cost parameter in log2.

  • r (Integer) (defaults to: 8)

    block size.

  • p (Integer) (defaults to: 1)

    parallelism parameter.

Returns:

  • (String)

    hashed digest string of password.



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', ...

Parameters:

  • id (String)

    hash function ID.

Returns:

  • (true)

    it does.

  • (false)

    it desn't.



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.

Parameters:

  • str (String)

    a good hashed string.

Returns:

  • (true)

    it does.

  • (false)

    it desn't.



123
124
125
# File 'lib/crypt_checkpass/scrypt.rb', line 123

def self.understand? str
  return match? str, understander
end