Skip to content

Commit

Permalink
Merge pull request #18 from angryTom/feat/update-hashing
Browse files Browse the repository at this point in the history
Feat/update hashing - Add password hasher
  • Loading branch information
ivarb authored Oct 6, 2016
2 parents f0f3af2 + 62353d5 commit babfa56
Show file tree
Hide file tree
Showing 20 changed files with 1,988 additions and 519 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: php
php:
- 5.5
- 5.4
- 5.3
- 7.1
- 7.0
- 5.6

# Notifications
notifications:
Expand Down
120 changes: 120 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Changelog

## 2.0.0

### New Password Hasher

Version `2.0.0` comes with a new password hasher component: `AngryBytes\Hash\Hasher\Password`.
This hasher is intended to be used for hashing of passwords (and other secure tokens).

The hasher utilises PHP's native cryptographically strong password hashing functions:
`password_hash()` and `password_verify()`, see [Password Hashing](http://php.net/manual/en/book.password.php).

The password hasher has been setup to use PHP's default cost and algorithm.
The default cost can however be overwritten by providing a cost to the the constructor, like so:

```php
// Create a password hasher with n cost factor of 15 instead of the default (10).
$passwordHasher = new \AngryBytes\Hash\Hasher\Password(15);
```

#### Password Rehashing
The password hasher offers a method to check if an existing hash needs to be **rehashed**.
For example, this can be the case when the cost and/or algorithm of the password
hasher has changed. If this is the case, you **should** rehash the password
and update the stored hash with the rehashed value.

**Example**

In this example, we check whether an existing password is outdated and should be rehashed.

Note: in order to rehash the password, you will need access to its original plaintext value.
Therefore, it's probably a best practice to check for and update a stale hash
during login procedure, where the plaintext password is available after a login form
submit.

```php
// Create a password hasher
$hasher = new \AngryBytes\Hash\Hash(
new \AngryBytes\Hash\Hasher\Password
);

// Plaintext password received via form submit.
$password = '...';

// Persisted password hash for the User
$userPasswordHash = '...';

// Verify the password against the hash
if ($hasher->verify($password, $userPasswordHash)) {

// Check if the hash needs to be rehashed?
if ($hasher->needsRehash($userPasswordHash)) {
// Rehash password and update the user.
$user->hash = $hasher->hash($password);
$user->save();
}
}
```

### Refactored "AngryBytes\Hash\HasherInterface"

Added new verification method `AngryBytes\Hash\HasherInterface::verify()` hash
verification. This method accepts the following three arguments:

* `$data` - The data that needs to be hashed.
* `$hash` - The hash that needs to match the hashed value of `$data`.
* `$options` (optional) - An array with addition hasher options. What these options are depends on the active hasher.

### Refactored AngryBytes\Hash\Hash

`AngryBytes\Hash\Hash::construct()` second argument (`$salt`) has become optional
to accommodate for hashers that handle their own salt, like `AngryBytes\Hash\Hasher\Password`.

`AngryBytes\Hash\Hash::hash()` and `AngryBytes\Hash\Hash::shortHash()` no longer accept any number of arguments but
only following two:

* `$data` - The data that needs to be hashed. This data can be of any type, all non-scalar types will be
serialized before hashing.
* `$options` (optional) - An array with options that will be passed to the hasher. What these options are depends
on the active hasher.

`AngryBytes\Hash\Hash::verify()` is a new method that's available to validate a hash in a time-safe manner.
The method accepts the following arguments:

* `$data` - The data that needs to be hashed. This data can be of any type, all non-scalar types will be
serialized before hashing.
* `$hash` - The hash that needs to match the hashed value of `$data`.
* `$options` (optional) - An array with options that will be passed to the hasher. What these options are depends
on the active hasher.

`AngryBytes\Hash\Hash::matchesShortHash()` is replaced by `AngryBytes\Hash\Hash::verifyShortHash()` this methods
accepts three arguments (`$data`, `$hash` and `$options`) just like `AngryBytes\Hash\Hash::verify()`.

### Minor Changes

* Scalar values passed to `hash()` and `shortHash()` are no longer serialized.
* `AngryBytes\Hash::compare()` now uses PHP native (timing attack safe) `hash_equals()` function.
* Fixed namespace issues for `AngryBytes\Hash\HMAC`.
* `AngryBytes\Hash\Hash` now implements a `__call()` method that dynamically passes
methods to the active hasher. This allows you to perform calls such as `AngryBytes\Hash::hash($string, ['cost' => 15]);`
without having to call `AngryBytes\Hash::getHasher()` first.

### Upgrading

Please refer to the [upgrade notes](UPGRADING.md).

### Deprecated & Removed Components

* `AngryBytes\Hash\RandomString` has been removed. Better open-source random string generation
libraries are available to do this.

## 1.0.2
Valid Blowfish salts (22 char long composed of ./A-Za-z0-9 characters only) are now used as the salt as-is instead
of md5-ed and substring-ed.

## 1.0.1
Adding travis build status and scrutinizer code qual. img. to readme

## 1.0.0
Initial release
40 changes: 31 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,54 @@
# AngryBytes Hash

[![Author](http://img.shields.io/badge/author-@angrybytes-blue.svg?style=flat-square)](https://twitter.com/angrybytes)
[![Software License](https://img.shields.io/badge/license-proprietary-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Build Status](https://travis-ci.org/AngryBytes/hash.svg?branch=master)](https://travis-ci.org/AngryBytes/hash)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/AngryBytes/hash/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AngryBytes/hash/?branch=master)

A simple PHP library that simplifies cryptographical hashing. It provides an
object oriented interface to a variety of hashing methods.

## Contents
## Requirements

* PHP `5.6.0` or `PHP 7.0` (recommended)

## Installation

Installation is done via Composer: `composer require angrybytes/hash`.

## Components

### Hash

`AngryBytes\Hash\Hash` is the main hasher class. It uses one of the `Hashers` to do the work.
`AngryBytes\Hash\Hash` is the main hasher class and acts as a helper wrapper
around hashers (i.e. `AngryBytes\Hash\HasherInterface` implementations).

Some of the main features of this component:

Available hashers are:
* Hash strings and/or passwords.
* Create short hashes (e.g. used for identification).
* Compare strings/hashes using a time-safe method.
* Verify a string against a hash using the configured hasher.

### Hashers

This library comes with a set of hashers to be utilised by this hash component (or
to be used on their own):

* `AngryBytes\Hash\Hasher\BlowFish`
* `AngryBytes\Hash\Hasher\MD5`

In addition this class can compare strings/hashes using a time-safe method.
* `AngryBytes\Hash\Hasher\Password`

### HMAC

`AngryBytes\Hash\HMAC` can be used to generate
[HMAC's](http://en.wikipedia.org/wiki/Hash-based_message_authentication_code)
for string messages.

### Random Strings
## Contributing

Before contributing to this project, please read the [contributing notes](CONTRIBUTING.md).

## License

Also included is a basic random string generator in
`AngryBytes\Hash\RandomString`. It targets Unix systems with `/dev/urandom`
available for now.
Please refer to the [license file](LICENSE.md).
74 changes: 74 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Upgrade Notes

This document lists important upgrade nodes and BC breaks per version.

## 2.0.0

### Update Hashing Values

If you are hashing multiple values you will need to change the way their are passed
to the hasher. Instead of passing each variable separately you will need to pass
them as an array. Like so:

```php

// Create a new Password Hasher
$hasher = new \AngryBytes\Hash\Hash(
new \AngryBytes\Hash\Hasher\Password
);

// Old
$hash = $hasher->hash('foo', 'bar', ['foo', 'bar']);

// New
$hash = $hasher->hash([
'foo', 'bar', ['foo', 'bar']
]);
```

The same principle applies to `Hash::shortHash()`.

### Update Hash Validation

In the previous version hash validation would be done by creating a hash and comparing
it to the existing hash. Now, you can simple pass the value(s) to hash and the
existing hash to methods: `verify()` or `verfiyShortHash()`.

```php
// Create a new Password Hasher
$hasher = new \AngryBytes\Hash\Hash(
new \AngryBytes\Hash\Hasher\Password
);

// The origin and hashed values
$valueToHash = '...'
$existingHash = '...';

// Old
$isValid = \AngryBytes\Hash\Hash::compare(
$hasher->hash($valueToHash),
$existingHash
);

// New
$isValid = $hasher->verify($valueToHash, $existingHash)
```

And for short hash comparison:

```php
// Create a new Password Hasher
$hasher = new \AngryBytes\Hash\Hash(
new \AngryBytes\Hash\Hasher\Password
);

// Old
if (Hash::matchShortHash($hasher->shortHash($value), $existingShortHash)) {
// Hash is valid
}

// New
if ($hasher->verifyShortHash($value, $existingShortHash)) {
// Hash is valid
}
```
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
"AngryBytes\\Hash": "src"
}
},
"require": {
"php": "~5.6 || ~7.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.x"
"phpunit/phpunit" : "~5.4.0"
}
}
Loading

0 comments on commit babfa56

Please sign in to comment.