crypt#
One-way passwd(5)-style hashing of a plaintext string with a salt.
crypt is a thin wrapper over the system C library’s crypt(3)
function. It turns PLAINTEXT and SALT into a short string — a
digest — and returns it. The same PLAINTEXT and SALT always
produce the same digest; small changes in either produce a completely
different digest. There is no inverse function: you cannot recover
PLAINTEXT from a digest.
Warning
crypt is not a general-purpose encryption function, despite the
name. It cannot be undone. It is also not a modern password hash
on most traditional configurations — the historical Unix scheme
considers only the first eight bytes of PLAINTEXT and produces a
13-byte digest over a 12-bit salt, which is unsuitable for protecting
passwords against contemporary attackers. What crypt is good for is
verifying a user-supplied string against an already-stored digest
produced by the same system’s crypt. For anything else — encryption,
key derivation, or hashing large data — use a real cryptographic
library. See See also below.
Synopsis#
crypt PLAINTEXT, SALT
Both arguments are strings. The return value is a string digest.
What you get back#
A string whose exact shape depends on the host’s crypt(3)
implementation. Traditionally it is 13 bytes: two bytes of salt
followed by 11 bytes from the set [./0-9A-Za-z]. Modern glibc,
musl, and BSD libcs accept extended salts that select stronger
schemes (MD5, SHA-256, SHA-512, bcrypt, yescrypt) and return longer
digests in the $id$salt$hash passwd-file format.
Treat the digest as opaque. Do not parse it, do not assume a
length, and do not assume which bytes of SALT the implementation
consumed. The correct way to verify a plaintext against an existing
digest is to pass the digest itself back in as the salt:
if (crypt($plain, $digest) eq $digest) { ... }
The salt used to create the digest is embedded in the digest, so this
re-runs the same scheme with the same parameters on the candidate
plaintext. Code written this way works with the classical DES scheme
and with every modern extension a given crypt(3) exposes, without
having to know which one produced the stored digest.
Global state it touches#
crypt does not read or write any Perl special variable. On
Unicode input it may emit a fatal Wide character in crypt error
(see Edge cases).
Examples#
Verify a password against a stored passwd-style digest:
my $stored = (getpwuid($<))[1]; # encrypted field from passwd
print "Password: ";
chomp(my $word = <STDIN>);
if (crypt($word, $stored) eq $stored) {
print "ok\n";
} else {
die "Sorry...\n";
}
Create a fresh digest for a new password using a random two-character
salt from the classical alphabet. The set is only a recommendation;
the exact characters accepted in a salt are whatever the host
crypt(3) allows, and Perl imposes no restriction of its own:
my @chars = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
my $salt = $chars[rand 64] . $chars[rand 64];
my $hash = crypt($plaintext, $salt);
Request a specific modern scheme by using an extended salt (glibc
and compatible libcs). The $id$ prefix selects the algorithm —
$1$ is MD5-crypt, $5$ is SHA-256-crypt, $6$ is SHA-512-crypt,
$2b$ is bcrypt where supported:
my $hash = crypt($plaintext, '$6$rounds=100000$' . $random_salt);
Re-verify using the stored digest as the salt — scheme-agnostic:
my $candidate = crypt($plaintext, $stored_digest);
my $match = $candidate eq $stored_digest;
Constant-time comparison of the two digests is still the caller’s
responsibility; plain eq leaks timing information. If the threat
model cares, compare byte-by-byte with a loop that does not
short-circuit, or use a comparison routine from a crypto module.
Edge cases#
First-8-byte truncation on classical DES. On traditional Unix
crypt(3), only the first eight bytes ofPLAINTEXTaffect the digest:crypt("password123", $s)andcrypt("password456", $s)collide. Extended schemes ($1$,$5$,$6$,$2b$, …) do not have this limit, but the classical scheme is what you get from an unprefixed two-byte salt.Salt-length assumptions are wrong. Do not assume
substr($digest,0,2)is the salt. Extended digests carry the salt in a different position and length. Re-use the full digest as the salt argument (crypt($plain, $digest)) and letcrypt(3)parse it.Unicode input. If
PLAINTEXTorSALTcontains characters above codepoint 255, Perl attempts to downgrade a copy of the string to bytes before callingcrypt(3). If every character fits in a byte, the downgrade succeeds silently. If any character does not,cryptdies withWide character in crypt. Encode explicitly (e.g.Encode::encode_utf8) if your plaintext might contain wide characters.Unsupported scheme returns failure. Passing a
$id$prefix the hostcrypt(3)does not understand typically returnsundefor a short string starting with*0or*1. Always check the return shape before using it.crypt(3)may be absent or restricted. On a small number of hosts the library function has been removed or replaced with a stub for export-control reasons.cryptin Perl is only as capable as the underlying libc call; if the libc call is a stub, so is this.Not suitable for hashing large data.
cryptignores most of its input on the classical scheme and is slow per call on the stretched schemes. It is the wrong tool for checksumming files or building content-addressable storage.
Differences from upstream#
Fully compatible with upstream Perl 5.42. pperl dispatches to the
host crypt(3) the same way perl5 does, so the accepted salt
formats and the exact digest shape match whatever the system
library produces — including the availability of $1$/$5$/$6$/
$2b$ extended schemes.
See also#
Digest::MD5— MD5-128 over arbitrary byte strings; use for fingerprinting data, not for password storageDigest::SHA— SHA-1/2 family digests; use for integrity checks and as a building block for HMAC and key derivationCrypt::Bcrypt,Crypt::Argon2,Crypt::Passphrase— CPAN modules for modern password hashing; prefer these overcryptfor any new password-verification codeCrypt::Eksblowfish,Crypt::ScryptKDF— CPAN modules for bcrypt and scrypt-based key derivationgetpwuid— fetch the encrypted-password field from the localpasswddatabase; its seventh field is the digest you pass asSALTwhen verifyingchomp— remove the trailing newline from a password read with<STDIN>before passing it tocrypt