The Pepperpot Protocol

A computer security protocol designed to make web application password handling more secure.

Copyright Millstream Software 2012. All rights reserved.

[Updated 2012/09/24]

The Pepperpot Protocol

The Pepperpot Protocol is a computer security protocol designed to 
make web application password handling more secure. It allows the 
application administrator to password protect the end-user password 
information in the database. With a sufficiently strong administrator 
password the protocol can prevent an application database compromise 
revealing any end-user passwords, even low entropy end-user passwords. 
The administrator password is held in a different process, called 
the pepperpot, which can be on a different computer. The pepperpot 
rate-limits login attempts independently of the application.


Good practice for the storage of web application passwords is to salt 
and hash the password using a cryptographic hash function that has a 
significant work factor. The hash is usually stored in the application 
database. This scheme has various problems: 

- Off-line password guessing after a database compromise is only 
  limited by the hash work factor. Low entropy passwords are 

- The commodity hardware, on which web applications are often run, 
  may have orders of magnitude less computational resources than a 
  multi-processor system used for off-line password guessing. 

- Mistakes in the application code can make it vulnerable to online 
  password guessing.

- As hardware becomes more powerful the stored hashes become vulnerable 
  to off-line guessing unless the they are periodically upgraded to 
  increase the hash work factor. 

An extra password, called the pepper, can be put in the application 
source code, or stored in a file other than the database, and used in 
addition to the salt to reduce some of these weaknesses. But a server 
compromise could reveal this password too. Specialist cryptographic 
hardware can also solve these problems, but web applications often run 
on commodity hardware for portability and cost reasons. 


The Pepperpot Protocol introduces a separate process, the pepperpot, 
to hold the pepper without ever revealing it to the application. 
The pepperpot can be run on commodity hardware and if necessary on 
a separate computer. If the application database is compromised the 
end-user passwords cannot be guessed without also compromising the 
pepperpot or guessing the pepper password. The pepperpot is only given 
a combined hash of the salt and password, never the salt or password 
being hashed, so a pepperpot compromise will not reveal any end-user 
passwords. The pepperpot also rate-limits online password guessing. 
Because of these features the pepperpot protocol effectively eliminates 
the weaknesses listed above.


# The administrator has to input parameters to start the application 
# and the pepperpot. The parameters are a rate-limit for end-user 
# password attempts and a list of peppers. A pepper contains a 
# pepper-password and the hash algorithms to use with it. The peppers 
# are numbered. The first pepper created is pepper-number 1, the next 
# is 2 etc. The administrator will add a new pepper to the list to 
# change the current pepper-password or hash algorithms. Having a list 
# of peppers allows the pepper-password to be updated automatically 
# for an end-user when they login. With only a single pepper it would 
# not be possible to change the pepper-password without forcing a 
# password reset on all the end-users. Every successful end-user login 
# updates the user's password hash to incorporate the latest pepper and 
# this pepper-number is stored in the database. An old pepper has to 
# remain in the list until all the end-users who used it during their 
# last successful login complete a new login with a new pepper. 

# This pseudo-code uses the abbreviations 'a' = application, 
# 'p' = pepperpot, '1' = old version, '2' = new version.


# Administrator inputs the parameters.
administrator -> 
    delay-application-milliseconds Da 

    list-of-peppers LP:
        pepper-number N
        hash-fast-application Hfa
        hash-slow-application Hsa

# Find the newest pepper in the list.
# This current pepper will have the highest pepper-number. They are 
# numbered sequentially when created, but the numbers may not be 
# sequential now because some unused peppers may have been deleted. 
iN2a = index of maximum N in LP
N2a = N[iN2a]


                                   administrator -> 
                                       delay-pepperpot-milliseconds Dp

                                       maximum-queue-length MQ

                                       list-of-peppers LP:
                                           pepper-number N
                                           pepper-password P
                                           hash-fast-pepperpot Hfp
                                           hash-slow-pepperpot Hsp

                                   # Hash the pepper passwords using 
                                   # the slow hash.
                                   for each pepper
                                       Ph[i] = Hsp[i](P[i], N[i])
                                       delete P[i], Hsp[i]

                                   # Find the current pepper.
                                   iN2p = index of maximum N in LP
                                   N2p = N[iN2p]

                                   queue-length = 0


# The application receives a login request.
# The username must not be logged or displayed in an error report before 
# it is found in the database in case it is a mistyped password. The 
# password must not be logged or error reported at any point.
user -> username, password

# The pepperpot and the application responses must be returned in a 
# constant time to prevent timing attacks. So we record the start time.
Ta = current time on the application server

lookup username in database -> 
    salt S1 
    pepper-number N1
    hash H1

if username not found
    wait until time > Ta + Da
    "username or password incorrect" -> user

# Find the old pepper.
iN1a = index of N1 in LP
if N1 not found in LP
    wait until time > Ta + Da
    "try again later" -> user
    "pepper not found" + details -> admin

N1a = N[iN1a]

# Generate a new salt. 
# The salt is replaced after every successful login. This limits 
# precomputation attacks and can, in some configurations, prevent login 
# statistics being collected by a compromised pepperpot. 
S2 = generate a new cryptographic random salt

# The old and new salts are hashed with the password.
S1Ph = Hfa[iN1a](S1, password)
S2Ph = Hfa[iN2a](S2, password)
delete password

# The hashes are hashed again before being sent to the pepperpot. This 
# prevents a compromised pepperpot performing any useful precomputation 
# of the application slow hash below prior to a compromise of the 
# application database.
S1Phh = Hfa[iN1a](S1Ph)
S2Phh = Hfa[iN2a](S2Ph)

Application                        Pepperpot
-----------                        ---------

# Send the hashes and their pepper-numbers to the pepperpot.

S1Phh, N1a, S2Phh, N2a  ---------> 
                                   Tp = current time on the pepperpot

                                   # Check we agree on current pepper. 
                                   if N2a <> N2p
                                       wait until time > Tp + Dp
                   <-------------      hash-fail current-pepper-mismatch

                                   # Find the old pepper.
                                   iN1p = index of N1a in LP
                                   if N1a not found in LP
                                       wait until time > Tp + Dp
                   <-------------      hash-fail old-pepper-missing

                                   # Check the rate-limit. 
                                   if queue-length >= MQ
                                       wait until time > Tp + Dp
                   <-------------      hash-fail rate-limit-exceeded

                                   increment queue-length

                                   # Old hash.
                                   H1p = Hfp[iN1p](S1Phh, Ph[iN1p])

                                   # New hash.
                                   H2p = Hfp[iN2p](S2Phh, Ph[iN2p])

                                   wait until time > Tp + Dp
                                   decrement queue-length

                   <-------------  hash-successful H1p, H2p


if hash-fail
    wait until time > Ta + Da
    "try again later" -> user
    "pepperpot failed" + details -> admin

H1a = Hsa[iN1a](H1p, S1Ph)
if H1a <> H1
    wait until time > Ta + Da
    "username or password incorrect" -> user

# The password is correct. Store the new salt, pepper-number and hash.
H2 = Hsa[iN2a](H2p, S2Ph)
update database for username <- S2, N2a, H2

wait until time > Ta + Da
"you are now logged in" -> user


There are 4 cryptographic hash algorithms. The slow hash pepperpot 
(Hsp) can and should have a significant work factor because it is only 
run once for each pepper password when the pepperpot is initialized. 
It is never run during end-user login attempts. The work factor of Hsp 
will rate-limit pepper-password guessing if the application database 
is compromised. The work factor of the slow hash application (Hsa) will 
rate-limit end-user password guessing if both the pepperpot and the 
application database are compromised. 

The two fast hash algorithms can have a lower work factor. The fast 
hash used by the application (Hfa) and fast hash used by the pepperpot 
(Hfp) protect the salted intermediate hashes. The salt should have 
sufficient entropy and the intermediate hashes sufficient length that 
it is computationally infeasible to find them from knowing their hash.

If the pepperpot is running on the same computer as the application 
there is little reason to run multiple pepperpots. But if the 
application relies on a single pepperpot hosted on a separate computer 
and that computer fails it will cause outage of the application login. 
This risk can be reduced by using multiple pepperpots. The ability 
of a compromised pepperpot to perform a denial of service against an 
application can also be reduced in a multiple pepperpot system by 
testing login failures against other pepperpots.

A single compromised pepperpot could deduce user login patterns for 
the application by chaining the hashes provided during login attempts. 
The protocol changes the salt with every successful login to increase 
the difficulty of obtaining this information in a multiple pepperpot 
system. A single compromised pepperpot in a multiple pepperpot system 
would have the sequence of hashes for a username broken whenever a 
subsequent login for the user was conducted via another pepperpot. 
All the pepperpots in a multiple pepperpot system would have to be 
simultaneously compromised to obtain the pattern of user logins. 

Version History

First version published 2012/06/25.

Updated version published 2012/09/06 to strengthen against a 
simultaneous compromise of the database and pepperpot.

Updated version published 2012/09/24 to strengthen against a
simultaneous compromise of the database and the ability to query the