• Stars
    star
    856
  • Rank 53,268 (Top 2 %)
  • Language
    PHP
  • License
    BSD 2-Clause "Sim...
  • Created over 11 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Password hashing code.

Secure Password Storage v2.0

Build Status

This repository contains peer-reviewed libraries for password storage in PHP, C#, Ruby, and Java. Passwords are "hashed" with PBKDF2 (64,000 iterations of SHA1 by default) using a cryptographically-random salt. The implementations are compatible with each other, so you can, for instance, create a hash in PHP and then verify it in C#.

Should you use this code?

This code uses the PBKDF2 algorithm to protect passwords. Better technologies for protecting passwords exist today, like bcrypt, scrypt, or Argon2. Before using this code, you should try to find a well-reviewed and carefully-made implementation of one of those algorithms for the language that you are using. These algorithms are "memory hard," meaning that they don't just need a lot of CPU power to compute, they also require a lot of memory (unlike PBKDF2). By using a memory hard algorithm, your passwords will be better protected.

One thing you could do would be to use libsodium to hash your passwords with scrypt. It has bindings available for many languages. For PHP apps, a great option is to use the built-in password_hash() and password_verify() functions.

Since there are better options, this code is now in "maintenance mode." Only bugs will be fixed, no new features will be added. It is currently safe to use, but using libsodium would be better.

Usage

You should not store users' passwords in plain text on your servers. Nor should you even store them in encrypted form. The correct way to store a password is to store something created from the password, which we'll call a "hash." Hashes don't allow you to recover the password, they only let you check if a password is the same as the one that created the hash.

There are a lot of subtle details about password hashing that this library hides from you. You don't need to worry about things like "salt" with this library. It takes care of all of that for you.

To implement a user login system, you need two parts: creating new accounts, and logging in to existing accounts. When you create a new account, your code will create a hash of the new account's password and save it somewhere. When you log in to an account, your code will use the hash to check if the login password is correct.

To create a hash, when a new account is added to your system, you call the CreateHash() method provided by this library. To verify a password, you call VerifyPassword() method provided by this library.

Here is more specific documentation for both functions. The behavior should be the same for all of the implementations (although the method names differ slightly). If one implementation behaves differently than another, that is a bug, and should be filed in the GitHub issue tracker.

CreateHash(password)

Preconditions:

  • You're intending to create a new account, or the password to an existing account is being changed.
  • password is the password for the new account, or the new password for an existing account.

Postconditions:

  • CreateHash() gives you a string which can be used with VerifyPassword() to check, in the future, if a password is the same as the password given to this call.

Obligations:

  • Store the string CreateHash() returns to you in a safe place. If an attacker can modify your hashes, they will be able to change them to, for instance, the hash of "1234", and then log in to any account. If an attacker can view your hashes, they can begin cracking them (by trying to guess-and-check passwords).

Exceptions:

  • CannotPerformOperationException: If this exception is thrown, it means something is wrong with the platform your code is running on, and it's not safe to create a hash. For example, if your system's random number generator doesn't work properly, this kind of exception will be thrown.

VerifyPassword(password, correctHash)

Preconditions:

  • Someone is logging in to a user account which has been created in the past.
  • password is the password provided by the person trying to log in.
  • correctHash is the hash of the account's correct password, made with CreateHash() when the account was created or when its password was last changed. Make sure you are providing the hash for the correct user account!
  • correctHash hasn't been seen by or changed by an attacker since it was created.

Postconditions:

  • True is returned if the password provided by the person logging in is correct. False is returned if not.

Obligations:

  • Make sure the correctHash you're giving is for the right account. If you give a hash for the wrong account, it would let someone log into Alice's account using Bob's password!

Exceptions:

  • CannotPerformOperationException: If this exception is thrown, it means something is wrong with the platform your code is running on, and for some reason it's not safe to verify a password on it.
  • InvalidHashException: The correctHash you gave was somehow corrupted. Note that some ways of corrupting a hash are impossible to detect, and their only symptom will be that VerifyPassword() will return false even though the correct password was given. So InvalidHashException is not guaranteed to be thrown if a hash has been changed, but if it is thrown then you can be sure that the hash was changed.

Customization

Each implementation provides several constants that can be changed. Only change these if you know what you are doing, and have help from an expert:

  • PBKDF2_HASH_ALGORITHM: The hash function PBKDF2 uses. By default, it is SHA1 for compatibility across implementations, but you may change it to SHA256 if you don't care about compatibility. Although SHA1 has been cryptographically broken as a collision-resistant function, it is still perfectly safe for password storage with PBKDF2.

  • PBKDF2_ITERATIONS: The number of PBKDF2 iterations. By default, it is 32,000. To provide greater protection of passwords, at the expense of needing more processing power to validate passwords, increase the number of iterations. The number of iterations should not be decreased.

  • PBKDF2_SALT_BYTES: The number of bytes of salt. By default, 24 bytes, which is 192 bits. This is more than enough. This constant should not be changed.

  • PBKDF2_HASH_BYTES: The number of PBKDF2 output bytes. By default, 18 bytes, which is 144 bits. While it may seem useful to increase the number of output bytes, doing so can actually give an advantage to the attacker, as it introduces unnecessary (avoidable) slowness to the PBKDF2 computation. 144 bits was chosen because it is (1) Less than SHA1's 160-bit output (to avoid unnecessary PBKDF2 overhead), and (2) A multiple of 6 bits, so that the base64 encoding is optimal.

Note that these constants are encoded into the hash string when it is created with CreateHash so that they can be changed without breaking existing hashes. The new (changed) values will apply only to newly-created hashes.

Hash Format

The hash format is five fields separated by the colon (':') character.

algorithm:iterations:hashSize:salt:hash

Where:

  • algorithm is the name of the cryptographic hash function ("sha1").
  • iterations is the number of PBKDF2 iterations ("64000").
  • hashSize is the length, in bytes, of the hash field (after decoding).
  • salt is the salt, base64 encoded.
  • hash is the PBKDF2 output, base64 encoded. It must encode hashSize bytes.

Here are some example hashes (all of the password "foobar"):

sha1:64000:18:B6oWbvtHvu8qCgoE75wxmvpidRnGzGFt:R1gkPOuVjqIoTulWP1TABS0H
sha1:64000:18:/GO9XQOPexBFVzRjC9mcOkVEi7ZHQc0/:0mY83V5PvmkkHRR41R1iIhx/
sha1:64000:18:rxGkJ9fMTNU7ezyWWqS7QBOeYKNUcVYL:tn+Zr/xo99LI+kSwLOUav72X
sha1:64000:18:lFtd+Qf93yfMyP6chCxJP5nkOxri6Zbh:B0awZ9cDJCTdfxUVwVqO+Mb5

The hash length in bytes is included to prevent an accident where the hash gets truncated. For instance, if the hash were stored in a database column that wasn't big enough, and the database was configured to truncate it, the result when the hash gets read back would be an easy-to-break hash, since the PBKDF2 output is right at the end. Therefore, the length of the hash should not be determined solely from the length of the last field; it must be compared against the stored length.

More Information

For more information on secure password storage, see Crackstation's page on Password Hashing Security.

More Repositories

1

php-encryption

Simple Encryption in PHP.
PHP
3,784
star
2

swatd

Run a script when one or more sensors fail.
C
869
star
3

crackstation-hashdb

CrackStation.net's Lookup Table Implementation.
PHP
365
star
4

sockstress

Sockstress (TCP DoS) implementation.
C
205
star
5

flush-reload-attacks

Ruby
180
star
6

crackstation

Source code for my crackstation.net website.
Hack
132
star
7

passgen

A password generator.
C++
78
star
8

defuse.ca

The source code to my defuse.ca website.
HTML
67
star
9

phpcount

A unique hit counter that respects users' privacy.
PHP
62
star
10

email-spoofing

Ruby script for spoofing SMTP emails.
Ruby
43
star
11

php-passgen

Generating passwords in PHP.
PHP
38
star
12

gas-obfuscation

Extremely simple but inefficient x86-64 assembly obfuscation.
Ruby
34
star
13

dnsfs

Host files with DNS
Ruby
32
star
14

yescrypt

Non-C Implementations of the yescrypt KDF.
C
29
star
15

helloworld-cms

A simple content display system in PHP.
PHP
27
star
16

DAWr

The start of a library for building a DAW and/or sound experiments in Rust
Rust
26
star
17

airgap

Design for an economical and simple air-gapped system.
25
star
18

WinPassGen

A Windows Password Generator.
C
24
star
19

pastebin

The defuse.ca pastebin.
PHP
23
star
20

phphashcrack

A PHP hash cracker.
PHP
22
star
21

encutil

Example of how to build a command-line file encryption utility with defuse/php-encryption.
PHP
20
star
22

synergy-crack

Synergy 1.4.12 cracking tool.
Ruby
17
star
23

cuda-md5

Old NVIDIA CUDA implementation of salted MD5 brute-force
C++
17
star
24

ictm

A user-first approach to threat modeling.
14
star
25

x86rc4

A tiny x86 implementation of RC4
Assembly
13
star
26

php-newsgroups

Newsgroup-style PHP forum.
PHP
12
star
27

elfplayer

Visualize an ELF's execution
JavaScript
10
star
28

backup-verify

Tool for verifying backups and comparing directories.
Ruby
9
star
29

passgenr

A library for generating cryptographically-secure passwords in Rust.
Rust
8
star
30

canvas

Practice HTML5 Canvas.
JavaScript
6
star
31

textractor

Extract strings from files to make wordlists.
C#
6
star
32

vim

My GVim Configuration
Vim Script
6
star
33

image-passwords

HTML5 Canvas: Generating keys from memorable image sequences.
JavaScript
5
star
34

truecrypt-archive

Archive of all TrueCrypt 7.1a files
Standard ML
4
star
35

defuse_failover

(Old) How I used to do implement failover for defuse.ca.
Shell
4
star
36

gnutls-psk

Example TLS PSK client/server.
C
4
star
37

gadgetrie

A simple gadget finder for Return Oriented Programming
C
4
star
38

js-encryption

SJCL (JavaScript) encryption example.
JavaScript
3
star
39

vst_plugin

Example VST2 plugin in Rust.
Rust
2
star
40

eotp

https://defuse.ca/eotp.htm
Java
2
star
41

nova-extractor

WIP implementation of the extractor in Nova's security proof
Rust
2
star
42

passwordtrainer

A script for memorizing/practicing passwords.
Ruby
2
star
43

php-login

A (half-finished) PHP login system.
PHP
2
star
44

stemviz

JavaScript
2
star
45

https-mockups

Negative feedback for insecure web connections.
2
star
46

afl-demo

C
2
star
47

vimhl

Syntax highlighting in PHP with Vim.
PHP
2
star
48

sudoku-solver

A simple sudoku solver in Ruby
Ruby
2
star
49

pfs-experiments

Testing perfect forward secrecy in the short term.
Ruby
1
star
50

tix

A command-line ticket system in Ruby.
Ruby
1
star
51

bqp

Source code for my bqp.io website.
HTML
1
star
52

juggler-pow

A memory-but-not-time asymmetric proof-of-work function.
C
1
star
53

hypothetico-web

Hypothetico e-zine website
PHP
1
star
54

popularaccess

popularaccess.org
1
star
55

upload

File transfer upload script.
Shell
1
star
56

wavetool

A tool for processing/analyzing Serum wavetables.
Rust
1
star
57

nsa-letter

A letter to Canadian MPs about the NSA
1
star
58

qcircuitgen

Easily draw quantum circuits for LaTeX's picture environment
Ruby
1
star
59

codefiles

A Ruby on Rails blog.
Ruby
1
star