Elektra  0.8.19
Cryptographic Key Handling

Issue

The crypto plugin applies cryptographic operations to Keys and KeySets. In order to do that it needs keys and initialization vectors (IV). The problem is how to retrieve or derivate those keys in a safe way and how to pass them on to the underlying crypto libraries (OpenSSL and libgcrypt at the time of writing).

Constraints

The solution must be reasonable to the user (not just experimental setups).

The key handling should follow best practises when dealing with cryptographic operations, thus:

Assumptions

Considered Alternatives

We considered passing the key and IV in form of plugin configuration and metakeys, but this approach possibly exposes the key to other modules. Thus our constraints are violated.

Also we considered using the gpg-agent (or pcscd, which uses a similar protocol) for providing asymmetric cryptographic operations. The problem with gpg-agent is that it only provides operations which require the private part of the key-pair (i.e. signing and decrypting). We would still have to implement the counterpart operations (i.e. verifying and encrypting) on our own. Starting the gpg-agent and the whole interprocess communication is either tedious work (when implemented by oneself) or adds another dependency (when using libassuan). So we do not consider the gpg-agent to be a viable option.

Decision

General Approach

The introduction of a GPG interface enables the user to utilize her existing key-pairs for cryptographic operations in Elektra. The private key is used for encrypting a random sequence, which serves as seed for a key derivation function (KDF). This way we can safely derivate cryptographic keys for symmetric value encryption. Both OpenSSL and libgcrypt have built-in support for the PBKDF2 (see RFC 2898).

The PBKDF2 needs an iteration number and a salt in order to work. Those values will be stored per Key as MetaKey.

Implementation Details

During the mount phase a random master password r is being generated. r is sent to the gpg binary for encryption. The resulting encrypted master password m is stored in the plugin configuration at config/masterChallenge.

During the set phase the master password m is sent to the gpg binary for decryption in order to retrieve r. The following steps will be repeated for every Key k, that is supposed to be encrypted. A random salt s(k) is generated. By applying the PBKDF2 (mentioned earlier) with r and s(k), the cryptographic key e(k) and the initialization vector i(k) is being derived. The value of k will be encrypted using e(k) and i(k). The seed s(k) will be encoded as prefix into the encrypted value.

During the get phase the master password m is sent to the gpg binary for decryption in order to retrieve r. The following steps will be repeated for every Key k, that is supposed to be decrypted. The salt s(k) is read from the encrypted message. By applying the PBKDF2 with r and s(k) the values of e(k) and i(k) are restored. Then the encrypted message can be decrypted.

Argument

The solution is reasonable to all users who are in favor of GPG. Also the solution might lead to a decline in dependencies (i.e. all cryptographic operations could be handled by the gpg binary).

The constraints considering the key handling are met.

Implications

To manipulate the plugin configuration during the mount phase a hook is required within the BackendBuilder. See pull request #733 for full discussion.

Related decisions

Notes