If one is going to use an HMAC, I.E: http://php.net/manual/en/function.hash-hmac.php, where exactly are they storing the key?

Without some sort of secure storage (i.e not in a local file or code), I feel like one is fooling oneself when using a HMAC (as with the above function). I missing something related to the storage of keys?

  • $\begingroup$ What is your scenario? You may store it in RAM only. You may also store it inside an HSM. $\endgroup$
    – SEJPM
    Commented Oct 14, 2015 at 19:43
  • $\begingroup$ I don't have a scenario. I keep seeing posts about using HMAC, no real discussion about real world handling of the key. Sure RAM is nice but servers reboot. I imagine an "HSM" is assumed. $\endgroup$
    – james626
    Commented Oct 14, 2015 at 20:09
  • $\begingroup$ Usually you only use HMAC with something like TLS, where you'd just renegotiate a new key after each boot, so no need to store here... BTW: HSM and usually people don't assume those because they tend to be expensive. $\endgroup$
    – SEJPM
    Commented Oct 14, 2015 at 20:12
  • $\begingroup$ Appreciated. I am really wondering based on the article here benlog.com/2008/06/19/dont-hash-secrets - the Author used HMAC to store passwords, but if they are on the file system/ in code somewhere, the secret doesn't seem very secured. $\endgroup$
    – james626
    Commented Oct 14, 2015 at 20:24
  • 2
    $\begingroup$ It would be more like on_hsm_hash_hmac as keys on a HSM should stay on a HSM for the HSM to be useful. Key management is a topic all on its own; it depends on the use case and threat model where you should store your keys. A HMAC in code could e.g. be strong enough, if you consider the code to be more secure than the input of the HMAC function. So there's no generic answer here. $\endgroup$
    – Maarten Bodewes
    Commented Oct 15, 2015 at 15:50

3 Answers 3


Before we get into the key storage and management issues, I wanted to clarify the scheme that is proposed in the linked article, to make sure it is clear what we are talking about.
Let's assume we get pw for authentication from the user and retrieve salt and tag from the database and we get sk from the storage method (see below) being a secret key. We then only accept the password pw if and only if tag=hmac(sk,salt||pw||salt) holds. The prototype of hmac looks as follows: MessageAuthenticationCode = hmac(SecretKey,Message), where the input SecretKey is implicit for trusted devices which provide a parameter for designating a specific secret key stored inside the device.

I really only see three options you have for storing the key if you want to use to do the password verification on a server that reboots:

  • Use a trusted device connected to the server. This includes smart cards (they may be too slow), trusted platform modules (TPMs; which may also be too slow) and hardware security modules (HSMs; which may be too expensive)
  • Store the encrypted key and hold the clear one in RAM and require user interaction for unlock. This may work by sending the server a secret password that allows for decryption of the HMAC key if it's at rest or may use this protocol (with EC-ElGamal) for smart card / TPM / HSM based / software based remote unlock.
  • Store the encrypted key temporarily, hold the clear one in RAM and use a trusted device. This means you let the server generate the secret HMAC key which is only held in RAM until a reboot happens and use a trusted device on reboot only. You may combine this with the second approach.

Now for the details and trade-offs of each method.

Trusted Devices

You can get yourself a smart card and install it in the server. You then send the password to be checked to the card, which holds the key, and receive the corresponding password hash which you compare to the stored value. This may not be suitable for mass-authentication as smart cards tend to be slow but is the (second) cheapest option among the trusted devices.

You can get a server mainboard featuring a trusted platform module (TPM) and use it like the smart card in the above paragraph. However the TPM suffers from the same problems: While it tends to be cheap it usually is rather slow and not suited for a larger service (handling more than ~10 requests per second).

The "best" solution from this category is the hardware security module(HSM). It would be used just like the other two. Whatsoever those modules tend to be very fast and would very-well be capable of handling many requests in very short times. Furthermore HSMs tend to also have better security certifications then smart cards and TPMs. The downside of course is that HSMs are very expensive, with the cheap ones starting at several hundred dollars and the better ones going up to several ten-thousand dollars, whereas smart cards are within the price range of a few dollars to a hundred dollars per piece.

TL;DR: So overall, while they provide the most security, I don't think trusted devices would solve your situation, because of API, speed and price restrictions.

User Interaction

Here there are basically four different options. A combination of in-place or remote password-based or public-key based key unlock. I'll quickly describe each.

But first I need to describe the overall concept of this approach. You let the server generate the HMAC key in RAM and store an encrypted copy on the hard drives. Every time the server reboots, the HMAC key gets wiped from the RAM and the encrypted copy needs to be unlocked in order to verify passwords. This is where the user interaction comes into play.

The first version of this would to simply enter the password while being directly and physically connected to the server. This is arguably the most secure solution of those requiring user interaction but on the other hand also the most time-intensive solution, as you have to plug-in a monitor and a keyboard, every time your server restarts, so you won't want to do this.

The second version is nearly identical to the first, but this time you'd connect a smart card reader (with a pinpad) to the server, enter the PIN and let the card (asymmetrically) decrypt the stored HMAC key. While this is even more secure than the first approach it suffers from the same problems and thereby usually isn't an option.

The third version improves upon the first, by establishing a TLS (or otherwise) secured channel to the server and handing the password over this way. While this is obviously less secure than the first version as there's the risk of intercaption and man-in-the-middle attacks it is also a lot more scalable.

The fourth version improves upon the second. You'd establish a secured channel (TLS, IPSec, local network, whatever) to the server and then run this protocol on it. This will allow you to decrypt the stored key without the key (or the ciphertext) ever having to leave the server. Yet only the correct smart card / private key can unlock the HMAC key. This is the most secure and most scalable solution among the remote-solutions that require user interaction at boot.

TL;DR: This may be an appraoch that is suitable for your needs, but may require too much user interaction to scale well. And of course the security of a fully hardware based solution can't be reached which may be acceptable as the API, speed and price can be met.

Trusted devices on Reboot

Full disclosure: I didn't invent this approach, but observed it first at Jetico's BestCrypt VolumeEncryption.

You can let the server generate the key in RAM. Now you let the key stay there until a scheduled reboot happens where the TPM will encrypt the HMAC-key and store it onto the drive. Now the server reboots and after the reboot the TPM will unlock the key and afterwards delete it. This allows for unattended reboots but has the problem that if an unexpected reboot happens the key will be lost and no passwords can be verified. The positive side is of course that this will scale extremely well and will allow for fast software based verification while using powerful hardware protection when necessary.

TL;DR: While this solution will scale quite well, it has the issue of key-backup in case the server shuts-down without a warning. And of course the security of a fully hardware based solution can't be reached which may be acceptable as the API, speed and price can be met.

The optimal solution (?)

This approach will work the same as the previous one with the small exception that one makes an encrypted backup of the HMAC-key to the drives. Most of the time the server will operate as in the above approach (using software-based HMAC for verification), but in the case of reboots the TPM will kick in and temporarily make the back-up copy for the reboot. Now the weakness of the "old" approaches was that there's no backup for the case of unexpected reboots. In such cases the user interaction appraoch could kick in and allow for decryption of the back-up key. This would even fix the problems of the "blind-decryption" protocol as the user now would very rarely use this method and only in cases where it was sure what happened, allowing for stronger key protection (like a smart card in a vault) and where the user can directly see the result (successful unlock). Furthermore the backup copy of the HMAC-key could be moved to a physically secure location (like a CD inside a vault) which was one of the problems of the stand-alone protocol.

TL;DR: This approach fixes the issues with the previous one, so there's a solid back-up, allowing for unexpected reboots and for unattended planned reboots. And of course the security of a fully hardware based solution can't be reached which may be acceptable as the API, speed and price can be met.

Note: Drives may be directly attached to the processor / mainboard or may be at a physically different location.


A simple algorithm for secure HMAC implementation

Client Registration

  1. Generate random clientid, clientsecret (32-bytes), hmacKey (64-bytes)
  2. Encrypt hmackey using AES256 with clientsecret as the key to get enc_hmacKey
  3. Server stores clientid and enc_hmacKey
  4. Client will be provided with clientid,clientsecret and hmacKey

Client Request

  1. HMAC will be computed for a request req_hmac=HMAC (reqBody, hmacKey)
  2. Client sends the following in the request header: clientid, clientsecret and req_hmac

Request Verification at Server

  1. AES256 Decrypt enc_hmackey using clientsecret to get hmacKey
  2. Compute HMAC computed_hmac = HMAC (reqBody, hmacKey)
  3. If req_hmac = computed_hmac, then HMAC verification is successful


  • Client secret is never stored on the server
  • Scheme is not compromised even if both the client secret and client id are compromised

Most applications store their private keys for TLS in a cleartext file protected with filesystem permissions.

  • On UNIX-ish systems this location is typically in /etc/ssl/private/mykey.key readable only by root.
  • Windows-based systems store private keys in a special secured portion of the system registry database, which only the SYSTEM account (equivalent to root) or key owner if a regular user can access via OS permissions.

The idea of this approach is that if an attacker can get root permissions, the game is basically over, as they could pluck any unencrypted keys directly from RAM with a debugger, or do just about anything else.

So, if you're storing your TLS private keys in this common "protected configuration file" fashion, storing your HMAC keys in a similarly-protected configuration file would make sense.

The other platform-specific and more costly option is to use a HSM of some sort. This requires platform- and sometimes device-specific support in the application. Windows systems can use an HSM as an alternate private key store location with appropriate drivers; on UNIX-like systems OpenSSL has support for various HSMs.

Note that while many laptops and even some servers come with a TPM chip, this chip is not generally useful as an HSM in a server scenario due to its low performance. It is really designed to protect the boot sequence and full-disk encryption keys, not handle the hundreds-to-thousands of operations per second a server would require.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.