Projects/AEAD encryption API
The Microsoft SSPI provides an interface for in-place encryption of messages. This interface also permits additional data to be included in the checksum generated to protect integrity. Such a facility is called authenticated encryption with additional data (AEAD). The SSPI works at the GSS-API layer, rather than the raw Kerberos layer.
This project proposes to extend the raw Kerberos cryptographic API (krb5_c_*) in order to make it possible to implement these SSPI facilities in an extension to the GSS-API. The ultimate consumer of these applications is typically DCE-style RPC, although the facilities could be used by other applications.
Contents
Functional Requirements
- Support a scatter-gather interface. Encryption APIs take a series of regions to operate on, rather than a single krb5_data.
- Support in-place encryption of data: the same buffer is used for input and output. (Why do we want this?)
- Support plaintext chunks that are signed but not encrypted.
- Coordinate with Heimdal to avoid introducing unnecessary incompatibilities with their API.
Basic approach
A new structure is defined: krb5_crypto_iov to describe a region of text to be encrypted or decrypted.
typedef struct _krb5_crypto_iov {
krb5_cryptotype flags; krb5_data data;
} krb5_crypto_iov;
The flags member describes the type of the iov. The data member points to the memory that will be manipulated. All iov APIs take a pointer to an array of krb5_crypto_iovs along with the size of that array. Buffer contents are manipulated in-place; data is overwritten. Callers must allocate the right number of krb5_crypto_iov structures before calling into an iov API.
Several types of krb5_crypto_iov are supported:
- define KRB5_CRYPTO_TYPE_EMPTY 0 /* [in] ignored */
- define KRB5_CRYPTO_TYPE_HEADER 1 /* [out] header */
- define KRB5_CRYPTO_TYPE_DATA 2 /* [in, out] plaintext */
- define KRB5_CRYPTO_TYPE_SIGN_ONLY 3 /* [in] associated data */
- define KRB5_CRYPTO_TYPE_PADDING 4 /* [out] padding */
- define KRB5_CRYPTO_TYPE_TRAILER 5 /* [out] checksum for encrypt */
- define KRB5_CRYPTO_TYPE_CHECKSUM 6 /* [out] checksum for MIC */
Typically the iov array would contain the following on a call to encryption functions:
- A header buffer of the appropriate length
- One or more data buffers
- Zero or more sign_only buffers
- A padding buffer of the appropriate length
- A trailer buffer of the appropriate length
On encryption, the data and sign-only buffers would be populated; other buffers would point to allocated but empty memory. When an encryption function returns success all buffers would be populated and filled.
Design questions
Supporting multiple data chunks that are not block-size aligned is tricky . Is it actually needed?
The API exposes padding separate from trailers. However RFC 3961 has neither concept. Is this the right balance?
With the existing crypto systems, the order between data chunks and sign_only chunks matters. That is, (data|sign_only|data) will produce a different checksum than (sign_only|data|data). Do we want callers to depend on this, or will doing so create a problem if we have a crypto system based on RFc 5116? I suspect that we want to say that a crypto system may treat the sign_only chunks as one ordered sequence and the data chunks as another ordered sequence but not require that the relative ordering between data chunks and sign_only chunks affect the cipher text.
The API design assumes fixed-length headers, padding and trailers.
I'm not sure how padding is supposed to work. Does the API reduce padding size?
Implementation notes
While the API supports in-place encryption the implementation does not significantly reduce the number of copies.
The implementation is parallel to the existing implementation. In particular, the existing APIs are not implemented in terms of the new APIs. New code is required (with significant copying) from the generic API layer down to the enc_provider layer, although of course raw crypto primitives are used.
Currently sanity checking buffers--for example making sure there is a trailer chunk--is left to the enc_provider implementations.
Public APIs
The following APIs are introduced by this project:
krb5_error_code KRB5_CALLCONV
krb5_c_make_checksum_iov (krb5_context context, krb5_cksumtype cksumtype, const krb5_keyblock *key, krb5_keyusage usage, krb5_crypto_iov *data, size_t num_data);
krb5_error_code KRB5_CALLCONV
krb5_c_verify_checksum_iov (krb5_context context, krb5_cksumtype cksumtype, const krb5_keyblock *key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_boolean *valid);
krb5_error_code KRB5_CALLCONV
krb5_c_encrypt_iov (krb5_context context, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *cipher_state, krb5_crypto_iov *data, size_t num_data);
krb5_error_code KRB5_CALLCONV
krb5_c_decrypt_iov (krb5_context context, const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *cipher_state, krb5_crypto_iov *data, size_t num_data);
krb5_error_code KRB5_CALLCONV
krb5_c_crypto_length (krb5_context context, krb5_enctype enctype, krb5_cryptotype type, unsigned int *size);