I am designing a basic KMS based on a simple HSM, I only have access to: AES256, SHA256, PBKDF2, HMAC (and combinations like AES256-HMAC-SHA256). The admin and the users of the system have a personal HSM where the keys are stored and it works like this:
- The administrator generates a key inside his HSM with PBKDF2 (random salt and random seed)
- The HSM of the administrator encrypts the new key using AES-256 with a different symmetric key for each user (the key used for key wrapping was established during the physical initialization of the HSM of the user) and sends it to every user that needs it along with key’s metadata. The whole payload (encrypted key value + key’s metadata) is encrypted another time with AES256 with another unique key for each user.
- The payload reaches the user that, thanks to the two symmetric keys previously shared with the admin (during the HSM physical initialization), is able to retrieve the requested key and metadata.
I was thinking about another possible approach that could be better but I am not really sure about it:
- The administrator establishes a shared secret common to every user of the system. This secret is stored in every HSM belonging to the users or to the administrator.
- When a key must be generated, the administrator computes it with PBKDF2 using the common secret and a random salt.
- When a key must be sent to any user, only the salt that was used by the administrator is actually sent to the user. The salt may be encrypted with a pre-shared symmetric key (like the example above) and it is used by every user along with the shared secret to generate again the key.
The first approach has the following problems: I need to send the actual key value, I have to perform two encryptions, the HSM must offer an API to retrieve from its internal flash memory the actual value of a key (as cleartext or ciphertext depending on the choice of the caller, the API can be called only if the administrator is logged in the HSM and it can’t be called if the user is logged).
The second approach has the following problems: the secret is common to all users so if an attacker finds the secret of a single user, he founds the secret of everyone. The HSM must offer an API to retrieve the secret as cleartext from its internal flash memory because the secret must be the same for every user, even for users that are added to the system weeks/months later (again this API is callable only if the administrator is logged in the HSM).
I suppose that the second approach, in principle, could be better because the keys are not actually sent from the administrator to the users. But the secret common to everybody is a problem, moreover I imagine that if an attacker finds out the value of a random salt, he may simply try to compute all possible keys given that salt using PBKDF2 and all possible seeds (because the implementation is open source so he knows that the secret is 32 bytes long and he also has access to the PBKDF2 code).
In conclusion I think that in the real world the first approach is more secure, provided that the login as administrator to the HSM is protected by a very complex PIN and possibly by a second factor (i.e. fingerprint). Do you agree? Any thoughts about other vulnerabilities in my approach?