

# Hash

Hashing is a one way method of converting arbitrary data into a fixed size format. Unlike ciphers, data that is hashed cannot be retrieved from the resulting digest. Hashes can be used to create keys, file identifiers, or store credentials.

> Hash function diagram from Wikipedia.

Warning

Avoid storing password hashes if possible. If you must, please make sure to research the state of the art before continuing.

## Make

To hash a string, use the `hash` property on `Droplet`.

    let digest = try drop.hash.make("vapor")
    print(digest.makeString())

### Checking

Some hashing algorithms create different hash digests for the same message. Because of this, it is necessary to check your hashes using the `check` method.

    let matches = try drop.hash.check("vapor", matchesHash: digest)

## CryptoHasher

By default, Vapor uses a SHA-256 hasher. You can change this in the configuration files or by giving the `Droplet` a different hasher.

### Configuration

`Config/droplet.json`

    {
        ...,
        "hash": "crypto",
        ...
    }

`Config/crypto.json`

    {
        "hash": {
            "method": "sha256",
            "encoding": "hex",
            "key": "password"
        },
        ...
    }

#### Encoding

The CryptoHasher supports three methods of encoding.

- `hex`
- `base64`
- `plain`

#### Key

Supplying a key will cause the hasher to produce keyed hashes using HMAC. Some hashers require a key.

#### Supported

Name | Method | Requires Key
--- | --- | ---
SHA-1 | sha1 | no
SHA-224 | sha224 | no
SHA-256 | sha256 | no
SHA-384 | sha384 | no
SHA-512 | sha512 | no
MD4 | md4 | no
MD5 | md5 | no
RIPEMD-160 | ripemd160 | no
Whirlpool | whirlpool | yes
Streebog-256 | streebog256 | yes
Streebog-512 | streebog512 | yes
GostR341194 | gostr341194 | yes

### Manual

Hashers can be swapped without the use of configuration files.

#### Hash

    let hash = CryptoHasher(
        hash: .sha256,
        encoding: .hex
    )

    let drop = try Droplet(hash: hash)

#### HMAC

    let hash = CryptoHasher(
        hmac: .sha256,
        encoding: .hex,
        key: "password".makeBytes()
    )

    let drop = try Droplet(hash: hash)

## BCryptHasher

BCrypt is a password hashing function that automatically incorporates salts and offers a configurable cost. The cost can be used to increase the computation required to generate a hash.

Seealso

Learn more about key stretching on Wikipedia.

### Configuration

To use the BCryptHasher change the `"hash"` key in the `droplet.json` configuration file.

`Config/droplet.json`

    {
        ...,
        "hash": "bcrypt",
        ...
    }

To configure the cost, add a `bcrypt.json` file.

`Config/bcrypt.json`

    {
        "cost": 8
    }

Tip

You can use different BCrypt costs for production and development modes to keep password hashing fast while working on a project.

### Manual

You can manually assign a `BCryptHasher` to `drop.hash`.

    let hash = BCryptHasher(cost: 8)

    let drop = try Droplet(hash: hash)

## Advanced

### Custom

You can also create your own hasher. You just need to conform to the `Hash` protocol.

    /// Creates hash digests
    public protocol HashProtocol {
        /// Given a message, this method
        /// returns a hashed digest of that message.
        func make(_ message: Bytes) throws -> Bytes

        /// Checks whether a given digest was created
        /// by the supplied message.
        ///
        /// Returns true if the digest was created
        /// by the supplied message, false otherwise.
        func check(_ message: Bytes, matchesHash: Bytes) throws -> Bool
    }