]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
krb5
authorIlya Dryomov <idryomov@gmail.com>
Mon, 22 Dec 2025 19:41:27 +0000 (20:41 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Tue, 30 Dec 2025 12:38:29 +0000 (13:38 +0100)
include/linux/ceph/ceph_fs.h
net/ceph/Kconfig
net/ceph/auth_x.c
net/ceph/auth_x_protocol.h
net/ceph/crypto.c
net/ceph/crypto.h

index c7f2c63b3bc3fb3c6a1ec0d114fcaf9cd7489de3..4e81dea14b7bc8d32ff5eb38b435eef849af7cc8 100644 (file)
@@ -83,8 +83,9 @@ struct ceph_dir_layout {
 } __attribute__ ((packed));
 
 /* crypto algorithms */
-#define CEPH_CRYPTO_NONE 0x0
-#define CEPH_CRYPTO_AES  0x1
+#define CEPH_CRYPTO_NONE       0x0
+#define CEPH_CRYPTO_AES        0x1
+#define CEPH_CRYPTO_AES256KRB5 0x2 /* AES256-CTS-HMAC384-192 */
 
 #define CEPH_AES_IV "cephsageyudagreg"
 
index ea60e3ef08343af0124fa7ade4795d3382dc1a82..7e2528cde4b943669bf3d8b6a203be39135ad7fa 100644 (file)
@@ -6,6 +6,7 @@ config CEPH_LIB
        select CRYPTO_AES
        select CRYPTO_CBC
        select CRYPTO_GCM
+       select CRYPTO_KRB5
        select CRYPTO_LIB_SHA256
        select CRYPTO
        select KEYS
index abdd35be263a2d548e835061b189ee131eafac31..2114ead11dcaf9c34ee1a7fbf4c1d83758851ca9 100644 (file)
 #include "auth_x.h"
 #include "auth_x_protocol.h"
 
+static const u32 ticket_key_usages[] = {
+       CEPHX_KEY_USAGE_TICKET_SESSION_KEY,
+       CEPHX_KEY_USAGE_TICKET_BLOB,
+       CEPHX_KEY_USAGE_SESSION_CONNECTION_SECRET
+};
+
+static const u32 authorizer_key_usages[] = {
+       CEPHX_KEY_USAGE_AUTHORIZE,
+       CEPHX_KEY_USAGE_AUTHORIZE_CHALLENGE,
+       CEPHX_KEY_USAGE_AUTHORIZE_REPLY
+};
+
+static const u32 client_key_usages[] = {
+       CEPHX_KEY_USAGE_TICKET_SESSION_KEY
+};
+
 static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
 
 static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
@@ -57,6 +73,7 @@ static int ceph_x_encrypt_offset(const struct ceph_crypto_key *key)
 
 /*
  * AES: ciphertext_len | hdr | data... | padding
+ * AES256KRB5: ciphertext_len | confounder | hdr | data... | hmac
  */
 static int ceph_x_encrypt_buflen(const struct ceph_crypto_key *key,
                                 int data_len)
@@ -65,19 +82,19 @@ static int ceph_x_encrypt_buflen(const struct ceph_crypto_key *key,
        return sizeof(u32) + ceph_crypt_buflen(key, encrypt_len);
 }
 
-static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf,
-                         int buf_len, int plaintext_len)
+static int ceph_x_encrypt(const struct ceph_crypto_key *key, int usage_slot,
+                         void *buf, int buf_len, int plaintext_len)
 {
        struct ceph_x_encrypt_header *hdr;
        int ciphertext_len;
        int ret;
 
-       hdr = buf + sizeof(u32) + ceph_crypt_data_offset(secret);
+       hdr = buf + sizeof(u32) + ceph_crypt_data_offset(key);
        hdr->struct_v = 1;
        hdr->magic = cpu_to_le64(CEPHX_ENC_MAGIC);
 
-       ret = ceph_crypt(secret, true, buf + sizeof(u32), buf_len - sizeof(u32),
-                        plaintext_len + sizeof(struct ceph_x_encrypt_header),
+       ret = ceph_crypt(key, usage_slot, true, buf + sizeof(u32),
+                        buf_len - sizeof(u32), plaintext_len + sizeof(*hdr),
                         &ciphertext_len);
        if (ret)
                return ret;
@@ -86,19 +103,19 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf,
        return sizeof(u32) + ciphertext_len;
 }
 
-static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,
-                           int ciphertext_len)
+static int __ceph_x_decrypt(const struct ceph_crypto_key *key, int usage_slot,
+                           void *p, int ciphertext_len)
 {
        struct ceph_x_encrypt_header *hdr;
        int plaintext_len;
        int ret;
 
-       ret = ceph_crypt(secret, false, p, ciphertext_len, ciphertext_len,
-                        &plaintext_len);
+       ret = ceph_crypt(key, usage_slot, false, p, ciphertext_len,
+                        ciphertext_len, &plaintext_len);
        if (ret)
                return ret;
 
-       hdr = p + ceph_crypt_data_offset(secret);
+       hdr = p + ceph_crypt_data_offset(key);
        if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
                pr_err("%s bad magic\n", __func__);
                return -EINVAL;
@@ -107,7 +124,8 @@ static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,
        return plaintext_len - sizeof(*hdr);
 }
 
-static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end)
+static int ceph_x_decrypt(const struct ceph_crypto_key *key, int usage_slot,
+                         void **p, void *end)
 {
        int ciphertext_len;
        int ret;
@@ -115,7 +133,7 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end)
        ceph_decode_32_safe(p, end, ciphertext_len, e_inval);
        ceph_decode_need(p, end, ciphertext_len, e_inval);
 
-       ret = __ceph_x_decrypt(secret, *p, ciphertext_len);
+       ret = __ceph_x_decrypt(key, usage_slot, *p, ciphertext_len);
        if (ret < 0)
                return ret;
 
@@ -207,7 +225,9 @@ static int process_one_ticket(struct ceph_auth_client *ac,
 
        /* blob for me */
        dp = *p + ceph_x_encrypt_offset(secret);
-       ret = ceph_x_decrypt(secret, p, end);
+       ret = ceph_x_decrypt(secret,
+                            0 /* CEPHX_KEY_USAGE_TICKET_SESSION_KEY */,
+                            p, end);
        if (ret < 0)
                goto out;
        dout(" decrypted %d bytes\n", ret);
@@ -221,7 +241,8 @@ static int process_one_ticket(struct ceph_auth_client *ac,
        if (ret)
                goto out;
 
-       ret = ceph_crypto_key_prepare(&new_session_key);
+       ret = ceph_crypto_key_prepare(&new_session_key, ticket_key_usages,
+                                     ARRAY_SIZE(ticket_key_usages));
        if (ret)
                goto out;
 
@@ -238,7 +259,9 @@ static int process_one_ticket(struct ceph_auth_client *ac,
        if (is_enc) {
                /* encrypted */
                tp = *p + ceph_x_encrypt_offset(&th->session_key);
-               ret = ceph_x_decrypt(&th->session_key, p, end);
+               ret = ceph_x_decrypt(&th->session_key,
+                                    1 /* CEPHX_KEY_USAGE_TICKET_BLOB */,
+                                    p, end);
                if (ret < 0)
                        goto out;
                dout(" encrypted ticket, decrypted %d bytes\n", ret);
@@ -341,7 +364,9 @@ static int encrypt_authorizer(struct ceph_x_authorizer *au,
                msg_b->server_challenge_plus_one = 0;
        }
 
-       ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
+       ret = ceph_x_encrypt(&au->session_key,
+                            0 /* CEPHX_KEY_USAGE_AUTHORIZE */,
+                            p, end - p, sizeof(*msg_b));
        if (ret < 0)
                return ret;
 
@@ -384,7 +409,8 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
        if (ret)
                goto out_au;
 
-       ret = ceph_crypto_key_prepare(&au->session_key);
+       ret = ceph_crypto_key_prepare(&au->session_key, authorizer_key_usages,
+                                     ARRAY_SIZE(authorizer_key_usages));
        if (ret)
                goto out_au;
 
@@ -542,7 +568,8 @@ static int ceph_x_build_request(struct ceph_auth_client *ac,
                get_random_bytes(&auth->client_challenge, sizeof(u64));
                blob->client_challenge = auth->client_challenge;
                blob->server_challenge = cpu_to_le64(xi->server_challenge);
-               ret = ceph_x_encrypt(&xi->secret, enc_buf, CEPHX_AU_ENC_BUF_LEN,
+               ret = ceph_x_encrypt(&xi->secret, 0 /* dummy */,
+                                    enc_buf, CEPHX_AU_ENC_BUF_LEN,
                                     sizeof(*blob));
                if (ret < 0)
                        return ret;
@@ -656,7 +683,9 @@ static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id,
        dout("%s connection secret blob len %d\n", __func__, len);
        if (len > 0) {
                dp = *p + ceph_x_encrypt_offset(&th->session_key);
-               ret = ceph_x_decrypt(&th->session_key, p, *p + len);
+               ret = ceph_x_decrypt(&th->session_key,
+                                    2 /* CEPHX_KEY_USAGE_SESSION_CONNECTION_SECRET */,
+                                    p, *p + len);
                if (ret < 0)
                        return ret;
 
@@ -820,7 +849,9 @@ static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret,
        int ret;
 
        /* no leading len */
-       ret = __ceph_x_decrypt(secret, challenge, challenge_len);
+       ret = __ceph_x_decrypt(secret,
+                              1 /* CEPHX_KEY_USAGE_AUTHORIZE_CHALLENGE */,
+                              challenge, challenge_len);
        if (ret < 0)
                return ret;
 
@@ -873,7 +904,8 @@ static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
        int ret;
 
        dp = *p + ceph_x_encrypt_offset(secret);
-       ret = ceph_x_decrypt(secret, p, end);
+       ret = ceph_x_decrypt(secret, 2 /* CEPHX_KEY_USAGE_AUTHORIZE_REPLY */,
+                            p, end);
        if (ret < 0)
                return ret;
 
@@ -1004,8 +1036,9 @@ static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
                sigblock->middle_crc = msg->footer.middle_crc;
                sigblock->data_crc =  msg->footer.data_crc;
 
-               ret = ceph_x_encrypt(&au->session_key, enc_buf,
-                                    CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock));
+               ret = ceph_x_encrypt(&au->session_key, 0 /* dummy */,
+                                    enc_buf, CEPHX_AU_ENC_BUF_LEN,
+                                    sizeof(*sigblock));
                if (ret < 0)
                        return ret;
 
@@ -1036,9 +1069,9 @@ static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
                sigblock->seq_lower_word = *(__le32 *)&msg->hdr.seq;
 
                /* no leading len, no ceph_x_encrypt_header */
-               ret = ceph_crypt(&au->session_key, true, enc_buf,
-                                CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock),
-                                &ciphertext_len);
+               ret = ceph_crypt(&au->session_key, 0 /* dummy */,
+                                true, enc_buf, CEPHX_AU_ENC_BUF_LEN,
+                                sizeof(*sigblock), &ciphertext_len);
                if (ret)
                        return ret;
 
@@ -1130,7 +1163,8 @@ int ceph_x_init(struct ceph_auth_client *ac)
                goto err_xi;
        }
 
-       ret = ceph_crypto_key_prepare(&xi->secret);
+       ret = ceph_crypto_key_prepare(&xi->secret, client_key_usages,
+                                     ARRAY_SIZE(client_key_usages));
        if (ret) {
                pr_err("cannot prepare key: %d\n", ret);
                goto err_secret;
index 9c60feeb1bcb6140f84b4609be4d40a0bc9f255e..a8c94873692de3cc8b9818dccb7704c2e4dfb037 100644 (file)
@@ -6,6 +6,30 @@
 #define CEPHX_GET_PRINCIPAL_SESSION_KEY 0x0200
 #define CEPHX_GET_ROTATING_KEY          0x0400
 
+/* Principal <-> AuthMonitor */
+/* The session's connection secret: encrypted with AUTH ticket service_key (aka auth_service_key) */
+#define CEPHX_KEY_USAGE_SESSION_CONNECTION_SECRET  0x03
+/* The ticket's CephxServiceTicket containing the session key: uses principal's key */
+#define CEPHX_KEY_USAGE_TICKET_SESSION_KEY         0x04
+/* The ticket's CephxTicketBlob: uses old auth session key (if presented) */
+#define CEPHX_KEY_USAGE_TICKET_BLOB                0x05
+
+/* Principal <-> Service */
+/* Client Authorization Request: using ticket session_key */
+#define CEPHX_KEY_USAGE_AUTHORIZE             0x10
+/* Service's Challenge: using ticket session_key */
+#define CEPHX_KEY_USAGE_AUTHORIZE_CHALLENGE   0x11
+/* Service's final reply: using ticket session key */
+#define CEPHX_KEY_USAGE_AUTHORIZE_REPLY       0x12
+
+/* Service Daemon <-> AuthMonitor */
+/* Rotating Secret Fetch by Services: service daemon's principal key */
+#define CEPHX_KEY_USAGE_ROTATING_SECRET       0x20
+
+/* Service Tickets */
+/* CephxServiceTicketInfo: rotating service key */
+#define CEPHX_KEY_USAGE_TICKET_INFO           0x30
+
 /* common bits */
 struct ceph_x_ticket_blob {
        __u8 struct_v;
index ef1b42c2876411727c374f054c8e0bdaf286dd82..212781f5f4839ec5f5f7fc3746081b9a1d71cdd0 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <crypto/aes.h>
+#include <crypto/krb5.h>
 #include <crypto/skcipher.h>
 #include <linux/key-type.h>
 #include <linux/sched/mm.h>
@@ -22,28 +23,68 @@ static int set_aes_tfm(struct ceph_crypto_key *key)
        int ret;
 
        noio_flag = memalloc_noio_save();
-       key->tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
+       key->aes_tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
        memalloc_noio_restore(noio_flag);
-       if (IS_ERR(key->tfm)) {
-               ret = PTR_ERR(key->tfm);
-               key->tfm = NULL;
+       if (IS_ERR(key->aes_tfm)) {
+               ret = PTR_ERR(key->aes_tfm);
+               key->aes_tfm = NULL;
                return ret;
        }
 
-       ret = crypto_sync_skcipher_setkey(key->tfm, key->key, key->len);
+       ret = crypto_sync_skcipher_setkey(key->aes_tfm, key->key, key->len);
        if (ret)
                return ret;
 
        return 0;
 }
 
-int ceph_crypto_key_prepare(struct ceph_crypto_key *key)
+static int set_krb5_tfms(struct ceph_crypto_key *key, const u32 *key_usages,
+                        int key_usage_cnt)
+{
+       struct krb5_buffer TK = { .len = key->len, .data = key->key };
+       unsigned int noio_flag;
+       int ret = 0;
+       int i;
+
+       if (WARN_ON_ONCE(key_usage_cnt > ARRAY_SIZE(key->krb5_tfms)))
+               return -EINVAL;
+
+       key->krb5_type = crypto_krb5_find_enctype(
+                            KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192);
+       if (!key->krb5_type)
+               return -ENOPKG;
+
+       /*
+        * Despite crypto_krb5_prepare_encryption() taking a gfp mask,
+        * crypto_alloc_aead() inside of it allocates with GFP_KERNEL.
+        */
+       noio_flag = memalloc_noio_save();
+       for (i = 0; i < key_usage_cnt; i++) {
+               key->krb5_tfms[i] = crypto_krb5_prepare_encryption(
+                                       key->krb5_type, &TK, key_usages[i],
+                                       GFP_NOIO);
+               if (IS_ERR(key->krb5_tfms[i])) {
+                       ret = PTR_ERR(key->krb5_tfms[i]);
+                       key->krb5_tfms[i] = NULL;
+                       goto out_flag;
+               }
+       }
+
+out_flag:
+       memalloc_noio_restore(noio_flag);
+       return ret;
+}
+
+int ceph_crypto_key_prepare(struct ceph_crypto_key *key,
+                           const u32 *key_usages, int key_usage_cnt)
 {
        switch (key->type) {
        case CEPH_CRYPTO_NONE:
                return 0; /* nothing to do */
        case CEPH_CRYPTO_AES:
                return set_aes_tfm(key);
+       case CEPH_CRYPTO_AES256KRB5:
+               return set_krb5_tfms(key, key_usages, key_usage_cnt);
        default:
                return -ENOTSUPP;
        }
@@ -117,12 +158,25 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
 
 void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
 {
-       if (key) {
-               kfree_sensitive(key->key);
-               key->key = NULL;
-               if (key->tfm) {
-                       crypto_free_sync_skcipher(key->tfm);
-                       key->tfm = NULL;
+       int i;
+
+       if (!key)
+               return;
+
+       kfree_sensitive(key->key);
+       key->key = NULL;
+
+       if (key->type == CEPH_CRYPTO_AES) {
+               if (key->aes_tfm) {
+                       crypto_free_sync_skcipher(key->aes_tfm);
+                       key->aes_tfm = NULL;
+               }
+       } else if (key->type == CEPH_CRYPTO_AES256KRB5) {
+               for (i = 0; i < ARRAY_SIZE(key->krb5_tfms); i++) {
+                       if (key->krb5_tfms[i]) {
+                               crypto_free_aead(key->krb5_tfms[i]);
+                               key->krb5_tfms[i] = NULL;
+                       }
                }
        }
 }
@@ -202,7 +256,7 @@ static void teardown_sgtable(struct sg_table *sgt)
 static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
                          void *buf, int buf_len, int in_len, int *pout_len)
 {
-       SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm);
+       SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->aes_tfm);
        struct sg_table sgt;
        struct scatterlist prealloc_sg;
        char iv[AES_BLOCK_SIZE] __aligned(8);
@@ -218,7 +272,7 @@ static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
                return ret;
 
        memcpy(iv, aes_iv, AES_BLOCK_SIZE);
-       skcipher_request_set_sync_tfm(req, key->tfm);
+       skcipher_request_set_sync_tfm(req, key->aes_tfm);
        skcipher_request_set_callback(req, 0, NULL, NULL);
        skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv);
 
@@ -263,7 +317,68 @@ out_sgt:
        return ret;
 }
 
-int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
+static int ceph_krb5_encrypt(const struct ceph_crypto_key *key, int usage_slot,
+                            void *buf, int buf_len, int in_len, int *pout_len)
+{
+       struct sg_table sgt;
+       struct scatterlist prealloc_sg;
+       int ret;
+
+       if (WARN_ON_ONCE(usage_slot >= ARRAY_SIZE(key->krb5_tfms)))
+               return -EINVAL;
+
+       ret = setup_sgtable(&sgt, &prealloc_sg, buf, buf_len);
+       if (ret)
+               return ret;
+
+       ret = crypto_krb5_encrypt(key->krb5_type, key->krb5_tfms[usage_slot],
+                                 sgt.sgl, sgt.nents, buf_len, AES_BLOCK_SIZE,
+                                 in_len, false);
+       if (ret < 0) {
+               pr_err("%s encrypt failed: %d\n", __func__, ret);
+               goto out_sgt;
+       }
+
+       *pout_len = ret;
+       ret = 0;
+
+out_sgt:
+       teardown_sgtable(&sgt);
+       return ret;
+}
+
+static int ceph_krb5_decrypt(const struct ceph_crypto_key *key, int usage_slot,
+                            void *buf, int buf_len, int in_len, int *pout_len)
+{
+       struct sg_table sgt;
+       struct scatterlist prealloc_sg;
+       size_t data_off = 0;
+       size_t data_len = in_len;
+       int ret;
+
+       if (WARN_ON_ONCE(usage_slot >= ARRAY_SIZE(key->krb5_tfms)))
+               return -EINVAL;
+
+       ret = setup_sgtable(&sgt, &prealloc_sg, buf, in_len);
+       if (ret)
+               return ret;
+
+       ret = crypto_krb5_decrypt(key->krb5_type, key->krb5_tfms[usage_slot],
+                                 sgt.sgl, sgt.nents, &data_off, &data_len);
+       if (ret) {
+               pr_err("%s decrypt failed: %d\n", __func__, ret);
+               goto out_sgt;
+       }
+
+       WARN_ON(data_off != AES_BLOCK_SIZE);
+       *pout_len = data_len;
+
+out_sgt:
+       teardown_sgtable(&sgt);
+       return ret;
+}
+
+int ceph_crypt(const struct ceph_crypto_key *key, int usage_slot, bool encrypt,
               void *buf, int buf_len, int in_len, int *pout_len)
 {
        switch (key->type) {
@@ -273,6 +388,12 @@ int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
        case CEPH_CRYPTO_AES:
                return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len,
                                      pout_len);
+       case CEPH_CRYPTO_AES256KRB5:
+               return encrypt ?
+                   ceph_krb5_encrypt(key, usage_slot, buf, buf_len, in_len,
+                                     pout_len) :
+                   ceph_krb5_decrypt(key, usage_slot, buf, buf_len, in_len,
+                                     pout_len);
        default:
                return -ENOTSUPP;
        }
@@ -284,6 +405,9 @@ int ceph_crypt_data_offset(const struct ceph_crypto_key *key)
        case CEPH_CRYPTO_NONE:
        case CEPH_CRYPTO_AES:
                return 0;
+       case CEPH_CRYPTO_AES256KRB5:
+               /* confounder */
+               return AES_BLOCK_SIZE;
        default:
                BUG();
        }
@@ -298,6 +422,9 @@ int ceph_crypt_buflen(const struct ceph_crypto_key *key, int data_len)
                /* PKCS#7 padding at the end */
                return data_len + AES_BLOCK_SIZE -
                       (data_len & (AES_BLOCK_SIZE - 1));
+       case CEPH_CRYPTO_AES256KRB5:
+               /* confounder at the beginning and 192-bit HMAC at the end */
+               return AES_BLOCK_SIZE + data_len + 24;
        default:
                BUG();
        }
index 2b8f8f68ff7a8c5461e6bd4b485fb7cd59e4a38f..2c37c54d0f5603fc46e5c4d79e3a73605e7738f7 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/ceph/types.h>
 #include <linux/ceph/buffer.h>
 
-#define CEPH_MAX_KEY_LEN               16
+#define CEPH_MAX_KEY_LEN               32
 #define CEPH_MAX_CON_SECRET_LEN                64
 
 /*
@@ -16,10 +16,18 @@ struct ceph_crypto_key {
        struct ceph_timespec created;
        int len;
        void *key;
-       struct crypto_sync_skcipher *tfm;
+
+       union {
+               struct crypto_sync_skcipher *aes_tfm;
+               struct {
+                       const struct krb5_enctype *krb5_type;
+                       struct crypto_aead *krb5_tfms[3];
+               };
+       };
 };
 
-int ceph_crypto_key_prepare(struct ceph_crypto_key *key);
+int ceph_crypto_key_prepare(struct ceph_crypto_key *key,
+                           const u32 *key_usages, int key_usage_cnt);
 int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
                          const struct ceph_crypto_key *src);
 int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end);
@@ -27,7 +35,7 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *in);
 void ceph_crypto_key_destroy(struct ceph_crypto_key *key);
 
 /* crypto.c */
-int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
+int ceph_crypt(const struct ceph_crypto_key *key, int usage_slot, bool encrypt,
               void *buf, int buf_len, int in_len, int *pout_len);
 int ceph_crypt_data_offset(const struct ceph_crypto_key *key);
 int ceph_crypt_buflen(const struct ceph_crypto_key *key, int data_len);