Short answer
No. See: Don't roll your own security.
Pedantic answer
You've mixed up several terms.
It's not an HMAC if the key is public
An HMAC requires a secret key (sometimes called a pepper) as opposed to a salt, which is public. Otherwise it is not an HMAC; it is just a hash.
A common use of an HMAC is to create a tamper-resistant fingerprint in order to provide message integrity. It is not used for password storage.
Don't think you're talking about a dictionary attack
The purpose of using a salted hash to store a password is not to mitigate dictionary attacks. The purpose is to thwart attacks that use a rainbow table. Salt does not affect a pure dictionary attack; the only mitigation is to use a password that is not in the dictionary, e.g. by requiring special characters or requiring longer passwords.
I think you are asking...
I think you might be asking "Is it OK to use an HMAC algorithm with a public key (instead of a proper password hashing function, like BCrypt) to store a password hash?" In that case, the answer is still NO. You should use password hashing algorithms, not other hashing algorithms, for password hashing, because they have features specific to the problem. For example, they are purposefully slow, and/or provide parameters that let you specify number of iterations required, which increases the computational power required for dictionary attacks and can render them much more difficult when compared to ordinary hashes that work with a single pass.
Is it OK to use the user ID as a salt?
Sorry, no. It causes a few issues:
- Creates a problem if the user ever changes his ID (hash would need to be recomputed)
- User ID may not be long enough to thwart attacks
- Same user ID might be used for different services, making it easy for the hacker to tell if the same password was used as well
- Hacker might compose a set of rainbow tables based on a list of common user IDs.
Also, see this decent article on the topic, which states:
A good rule of thumb is to use a salt that is the same size as the output of the hash function. For example, the output of SHA256 is 256 bits (32 bytes), so the salt should be at least 32 random bytes.