linux/net/ceph/crypto.c
<<
>>
Prefs
   1
   2#include <linux/ceph/ceph_debug.h>
   3
   4#include <linux/err.h>
   5#include <linux/scatterlist.h>
   6#include <linux/sched.h>
   7#include <linux/slab.h>
   8#include <crypto/aes.h>
   9#include <crypto/skcipher.h>
  10#include <linux/key-type.h>
  11
  12#include <keys/ceph-type.h>
  13#include <linux/ceph/decode.h>
  14#include "crypto.h"
  15
  16/*
  17 * Set ->key and ->tfm.  The rest of the key should be filled in before
  18 * this function is called.
  19 */
  20static int set_secret(struct ceph_crypto_key *key, void *buf)
  21{
  22        unsigned int noio_flag;
  23        int ret;
  24
  25        key->key = NULL;
  26        key->tfm = NULL;
  27
  28        switch (key->type) {
  29        case CEPH_CRYPTO_NONE:
  30                return 0; /* nothing to do */
  31        case CEPH_CRYPTO_AES:
  32                break;
  33        default:
  34                return -ENOTSUPP;
  35        }
  36
  37        if (!key->len)
  38                return -EINVAL;
  39
  40        key->key = kmemdup(buf, key->len, GFP_NOIO);
  41        if (!key->key) {
  42                ret = -ENOMEM;
  43                goto fail;
  44        }
  45
  46        /* crypto_alloc_skcipher() allocates with GFP_KERNEL */
  47        noio_flag = memalloc_noio_save();
  48        key->tfm = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
  49        memalloc_noio_restore(noio_flag);
  50        if (IS_ERR(key->tfm)) {
  51                ret = PTR_ERR(key->tfm);
  52                key->tfm = NULL;
  53                goto fail;
  54        }
  55
  56        ret = crypto_skcipher_setkey(key->tfm, key->key, key->len);
  57        if (ret)
  58                goto fail;
  59
  60        return 0;
  61
  62fail:
  63        ceph_crypto_key_destroy(key);
  64        return ret;
  65}
  66
  67int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
  68                          const struct ceph_crypto_key *src)
  69{
  70        memcpy(dst, src, sizeof(struct ceph_crypto_key));
  71        return set_secret(dst, src->key);
  72}
  73
  74int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
  75{
  76        if (*p + sizeof(u16) + sizeof(key->created) +
  77            sizeof(u16) + key->len > end)
  78                return -ERANGE;
  79        ceph_encode_16(p, key->type);
  80        ceph_encode_copy(p, &key->created, sizeof(key->created));
  81        ceph_encode_16(p, key->len);
  82        ceph_encode_copy(p, key->key, key->len);
  83        return 0;
  84}
  85
  86int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
  87{
  88        int ret;
  89
  90        ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
  91        key->type = ceph_decode_16(p);
  92        ceph_decode_copy(p, &key->created, sizeof(key->created));
  93        key->len = ceph_decode_16(p);
  94        ceph_decode_need(p, end, key->len, bad);
  95        ret = set_secret(key, *p);
  96        *p += key->len;
  97        return ret;
  98
  99bad:
 100        dout("failed to decode crypto key\n");
 101        return -EINVAL;
 102}
 103
 104int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
 105{
 106        int inlen = strlen(inkey);
 107        int blen = inlen * 3 / 4;
 108        void *buf, *p;
 109        int ret;
 110
 111        dout("crypto_key_unarmor %s\n", inkey);
 112        buf = kmalloc(blen, GFP_NOFS);
 113        if (!buf)
 114                return -ENOMEM;
 115        blen = ceph_unarmor(buf, inkey, inkey+inlen);
 116        if (blen < 0) {
 117                kfree(buf);
 118                return blen;
 119        }
 120
 121        p = buf;
 122        ret = ceph_crypto_key_decode(key, &p, p + blen);
 123        kfree(buf);
 124        if (ret)
 125                return ret;
 126        dout("crypto_key_unarmor key %p type %d len %d\n", key,
 127             key->type, key->len);
 128        return 0;
 129}
 130
 131void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
 132{
 133        if (key) {
 134                kfree(key->key);
 135                key->key = NULL;
 136                crypto_free_skcipher(key->tfm);
 137                key->tfm = NULL;
 138        }
 139}
 140
 141static const u8 *aes_iv = (u8 *)CEPH_AES_IV;
 142
 143/*
 144 * Should be used for buffers allocated with ceph_kvmalloc().
 145 * Currently these are encrypt out-buffer (ceph_buffer) and decrypt
 146 * in-buffer (msg front).
 147 *
 148 * Dispose of @sgt with teardown_sgtable().
 149 *
 150 * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
 151 * in cases where a single sg is sufficient.  No attempt to reduce the
 152 * number of sgs by squeezing physically contiguous pages together is
 153 * made though, for simplicity.
 154 */
 155static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
 156                         const void *buf, unsigned int buf_len)
 157{
 158        struct scatterlist *sg;
 159        const bool is_vmalloc = is_vmalloc_addr(buf);
 160        unsigned int off = offset_in_page(buf);
 161        unsigned int chunk_cnt = 1;
 162        unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
 163        int i;
 164        int ret;
 165
 166        if (buf_len == 0) {
 167                memset(sgt, 0, sizeof(*sgt));
 168                return -EINVAL;
 169        }
 170
 171        if (is_vmalloc) {
 172                chunk_cnt = chunk_len >> PAGE_SHIFT;
 173                chunk_len = PAGE_SIZE;
 174        }
 175
 176        if (chunk_cnt > 1) {
 177                ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
 178                if (ret)
 179                        return ret;
 180        } else {
 181                WARN_ON(chunk_cnt != 1);
 182                sg_init_table(prealloc_sg, 1);
 183                sgt->sgl = prealloc_sg;
 184                sgt->nents = sgt->orig_nents = 1;
 185        }
 186
 187        for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
 188                struct page *page;
 189                unsigned int len = min(chunk_len - off, buf_len);
 190
 191                if (is_vmalloc)
 192                        page = vmalloc_to_page(buf);
 193                else
 194                        page = virt_to_page(buf);
 195
 196                sg_set_page(sg, page, len, off);
 197
 198                off = 0;
 199                buf += len;
 200                buf_len -= len;
 201        }
 202        WARN_ON(buf_len != 0);
 203
 204        return 0;
 205}
 206
 207static void teardown_sgtable(struct sg_table *sgt)
 208{
 209        if (sgt->orig_nents > 1)
 210                sg_free_table(sgt);
 211}
 212
 213static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
 214                          void *buf, int buf_len, int in_len, int *pout_len)
 215{
 216        SKCIPHER_REQUEST_ON_STACK(req, key->tfm);
 217        struct sg_table sgt;
 218        struct scatterlist prealloc_sg;
 219        char iv[AES_BLOCK_SIZE] __aligned(8);
 220        int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1));
 221        int crypt_len = encrypt ? in_len + pad_byte : in_len;
 222        int ret;
 223
 224        WARN_ON(crypt_len > buf_len);
 225        if (encrypt)
 226                memset(buf + in_len, pad_byte, pad_byte);
 227        ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len);
 228        if (ret)
 229                return ret;
 230
 231        memcpy(iv, aes_iv, AES_BLOCK_SIZE);
 232        skcipher_request_set_tfm(req, key->tfm);
 233        skcipher_request_set_callback(req, 0, NULL, NULL);
 234        skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv);
 235
 236        /*
 237        print_hex_dump(KERN_ERR, "key: ", DUMP_PREFIX_NONE, 16, 1,
 238                       key->key, key->len, 1);
 239        print_hex_dump(KERN_ERR, " in: ", DUMP_PREFIX_NONE, 16, 1,
 240                       buf, crypt_len, 1);
 241        */
 242        if (encrypt)
 243                ret = crypto_skcipher_encrypt(req);
 244        else
 245                ret = crypto_skcipher_decrypt(req);
 246        skcipher_request_zero(req);
 247        if (ret) {
 248                pr_err("%s %scrypt failed: %d\n", __func__,
 249                       encrypt ? "en" : "de", ret);
 250                goto out_sgt;
 251        }
 252        /*
 253        print_hex_dump(KERN_ERR, "out: ", DUMP_PREFIX_NONE, 16, 1,
 254                       buf, crypt_len, 1);
 255        */
 256
 257        if (encrypt) {
 258                *pout_len = crypt_len;
 259        } else {
 260                pad_byte = *(char *)(buf + in_len - 1);
 261                if (pad_byte > 0 && pad_byte <= AES_BLOCK_SIZE &&
 262                    in_len >= pad_byte) {
 263                        *pout_len = in_len - pad_byte;
 264                } else {
 265                        pr_err("%s got bad padding %d on in_len %d\n",
 266                               __func__, pad_byte, in_len);
 267                        ret = -EPERM;
 268                        goto out_sgt;
 269                }
 270        }
 271
 272out_sgt:
 273        teardown_sgtable(&sgt);
 274        return ret;
 275}
 276
 277int ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
 278               void *buf, int buf_len, int in_len, int *pout_len)
 279{
 280        switch (key->type) {
 281        case CEPH_CRYPTO_NONE:
 282                *pout_len = in_len;
 283                return 0;
 284        case CEPH_CRYPTO_AES:
 285                return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len,
 286                                      pout_len);
 287        default:
 288                return -ENOTSUPP;
 289        }
 290}
 291
 292static int ceph_key_instantiate(struct key *key,
 293                                struct key_preparsed_payload *prep)
 294{
 295        struct ceph_crypto_key *ckey;
 296        size_t datalen = prep->datalen;
 297        int ret;
 298        void *p;
 299
 300        ret = -EINVAL;
 301        if (datalen <= 0 || datalen > 32767 || !prep->data)
 302                goto err;
 303
 304        ret = key_payload_reserve(key, datalen);
 305        if (ret < 0)
 306                goto err;
 307
 308        ret = -ENOMEM;
 309        ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
 310        if (!ckey)
 311                goto err;
 312
 313        /* TODO ceph_crypto_key_decode should really take const input */
 314        p = (void *)prep->data;
 315        ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
 316        if (ret < 0)
 317                goto err_ckey;
 318
 319        key->payload.data = ckey;
 320        return 0;
 321
 322err_ckey:
 323        kfree(ckey);
 324err:
 325        return ret;
 326}
 327
 328static int ceph_key_match(const struct key *key, const void *description)
 329{
 330        return strcmp(key->description, description) == 0;
 331}
 332
 333static void ceph_key_destroy(struct key *key) {
 334        struct ceph_crypto_key *ckey = key->payload.data;
 335
 336        ceph_crypto_key_destroy(ckey);
 337        kfree(ckey);
 338}
 339
 340struct key_type key_type_ceph = {
 341        .name           = "ceph",
 342        .instantiate    = ceph_key_instantiate,
 343        .match          = ceph_key_match,
 344        .destroy        = ceph_key_destroy,
 345};
 346
 347int __init ceph_crypto_init(void)
 348{
 349        return register_key_type(&key_type_ceph);
 350}
 351
 352void ceph_crypto_shutdown(void)
 353{
 354        unregister_key_type(&key_type_ceph);
 355}
 356