Provides Unix crypt_checkpass(3)-compatible routines.
What's good with this API?
- It supports vast majority of hash verifications, including those which are not generated by us (see below). This enables smooth migration of password algorithm; you can mix multiple algorithms to verify. This is practically very important because from time to time, current best practice moves from one thing to another.
- Generates a variety of hash strings using current-best-practice hash functions.
Tell me the usage?
Verification:
require 'crypt_checkpass'
actual = 'p455w0rd'
expected = '$5$$D1W6NDlv302WsleruXoUN279B87yf6dFN4ZZhFqV6DD'
crypt_checkpass(actual, expected) or raise 'NG'
Generation:
require 'crypt_checkpass'
crypt_newhash('p455w0rd',
id: 'argon2i',
m_cost: 4096,
t_cost: 3) # => "$argon2i$v=19$m=4096,t=3,p=1$cXdlc..."
Or, if you are a real OpenBSD fan, you can also do this:
require 'crypt_checkpass'
crypt_newhash('p455w0rd', 'bcrypt,12') # => "$2b$12$gCDJbfcg..."
Which hash function is supported?
prefix | id | supported | depends |
---|---|---|---|
(none) | DES(traditional) | NO | (1) |
_ |
DES(BSDi extended) | NO | (2) |
$1$ |
MD5 | NO | (2) |
$2 |
bcrypt | YES | bcrypt gem |
$3$ |
BSD NThash | NO | (2) |
$5$ |
SHA256 | YES | unix-crypt gem |
$6$ |
SHA512 | YES | unix-crypt gem |
$argon2 |
argon2 | YES | argon2 gem |
$pbkdf2 |
PBKFD2 | YES | openssl gem |
(3) | scrypt | YES | scrypt gem |
- note (1): instead of falling back to traditional mode which is considered absolutely insecure, this library prohibits this kind of input and renders errors.
- note (2): These formats are considered archaic.
- note (3): scypt gem generates password string that is not prefixed.
Too many functions are there! What is the current best practice?
If in doubt use argon2. It was designed to establish "standard to fulfill the needs of modern applications and to best protect against attackers". As of writing there are no known flaws.
What's wrong with the stdlib String#crypt
?
Please never use String#crypt
any longer. It is legacy; provided
only for backward compatibility with ruby scripts in earlier days. It
is bad to use in contemporary programs for several reasons:
- Behaviour of C's
crypt(3)
, which is under the hood ofString#crypt
, depends on the OS it is run. The generated digest lacks data portability. - On some OSes such as Mac OS, this function never fails (i.e. silently ends up in unexpected results).
- On some OSes such as Mac OS, It is not thread safe.
- So-called "traditional" usage of
crypt(3)
is very very very weak. According to its manpage, Linux's traditionalcrypt(3)
output only has 2**56 variations; too easy to blute force today. And this is the default behaviour. In order to make things robust some OSes implement so-called "modular" usage. To go through, you have to do a complex build-up of the parameter(salt), by hand. Failure in generation of a proper salt string tends not to yield any errors; for instance typo in parameters are normally not detectable.
- For instance, in the following example, second invokation of
String#crypt
is wrong; it has typo in "round=" (lacks "s"). However the call does not fail and something unexpected is generated.
"foo".crypt("$5$rounds=1000$salt$") # OK, proper usage "foo".crypt("$5$round=1000$salt$") # Typo not detected
- For instance, in the following example, second invokation of
Even in the "modular" mode, some hash functions are considered archaic and no longer recommended at all; for instance module
$1$
is officially abondoned by its author: http://phk.freebsd.dk/sagas/md5crypt_eol.html, for another instance module$3$
is consodered completely broken: see the manpage of FreeBSD.On some OS such as Mac OS, there is no modular mode. Yet, as written above,
String#crypt
on Mac OS never fails. This means even if you build up a proper salt string it generates a traditional DES hash anyways, and there is no way for you to be aware of.
"foo".crypt("$5$rounds=1000$salt$") # => "$5fNPQMxC5j6."
The API this library provides is better. Use ours instead.