For a variety of reasons, I need to use digest authentication for a REST server that I have created.
I have come up with an "improvement" that I believe strengthens the algorithm against MD5 attacks without being a burden on clients. What problems can you see with my algorithm?
Introduction
- Client is a custom application written in C#.
- Server is a JAX-RS-based REST Server written in Java and running on Tomcat.
- All traffic between the client and server is encrypted using SSL/TLS.
The database contains a user_table with the following columns:
- user_id: primary key
- password_hash: varchar not null
- salt: varchar not null
- iteration_count: integer
Digest Authentication (RFC2617)
Digest authentication uses the following calculations:
nonce: server-generated number used once
nonceCount: server-generated increasing value (prevents replay attacks)
cnonce: client-generated number used once
qop: quality of protection ("auth")
method: typically one of "GET", "POST", "PUT", etc.
HA1 = MD5(username:realm:password)
HA2 = MD5(method:digestURI)
response = MD5(HA1:nonce:nonceCount:cnonce:qop:HA2)
The HA1
value is stored in the database as the password hash value. During authentication, the client calculates the value of response
from the WWW-authenticate
http headers. The server also calculates the response
value using its stored version of HA1
and compares the value received from the client. If they are equal, the client is authenticated.
MD5 is no longer considered secure. Collisions can be found in a few hours using commodity hardware.
Using PBKDF2 to Strengthen Digest
- Client obtains the username and plaintext password from the user.
- Client requests the salt and iteration count for the user_id from the server. The server also sends the current default iteration count (which may be different than that used for this user).
- Client calculates a 128-bit secret key using PBKDF2(password, salt, user-specific iteration count). The secret key is encoded as a hexadecimal string.
- Client calculates
HA1
using the username, realm, and hexadecimal-encoded key. ThisHA1
value is used in a standard digest authentication. - Server obtains the password hash from the database. The password hash is the previously calculated
HA1
using the same PBKDF2-derived secret key. The server compares the calculatedresponse
to theresponse
value sent by the client (standard digest authentication). If the tworesponse
values are equal, the client is authenticated. - If the user-specific iteration count returned to the client is different than the default iteration count, the client calculates a new
HA1
using PBKDF2 and the new iteration count. The client calls aPUT
method on the REST Server to update the password hash column using the new value. This step allows the algorithm to be updated with larger iteration counts as hardware get faster.
The modified algorithm does not rely on the strength of MD5 to protect the password hash, since the difficulty of calculating the password hash is dependent on PBKDF2 (which can use a SHA-1 or SHA-256 hash).
Are there any obvious security flaws in this modified algorithm?