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/slab.h>
   7#include <crypto/hash.h>
   8#include <linux/key-type.h>
   9
  10#include <keys/ceph-type.h>
  11#include <linux/ceph/decode.h>
  12#include "crypto.h"
  13
  14int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
  15                          const struct ceph_crypto_key *src)
  16{
  17        memcpy(dst, src, sizeof(struct ceph_crypto_key));
  18        dst->key = kmemdup(src->key, src->len, GFP_NOFS);
  19        if (!dst->key)
  20                return -ENOMEM;
  21        return 0;
  22}
  23
  24int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
  25{
  26        if (*p + sizeof(u16) + sizeof(key->created) +
  27            sizeof(u16) + key->len > end)
  28                return -ERANGE;
  29        ceph_encode_16(p, key->type);
  30        ceph_encode_copy(p, &key->created, sizeof(key->created));
  31        ceph_encode_16(p, key->len);
  32        ceph_encode_copy(p, key->key, key->len);
  33        return 0;
  34}
  35
  36int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
  37{
  38        ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
  39        key->type = ceph_decode_16(p);
  40        ceph_decode_copy(p, &key->created, sizeof(key->created));
  41        key->len = ceph_decode_16(p);
  42        ceph_decode_need(p, end, key->len, bad);
  43        key->key = kmalloc(key->len, GFP_NOFS);
  44        if (!key->key)
  45                return -ENOMEM;
  46        ceph_decode_copy(p, key->key, key->len);
  47        return 0;
  48
  49bad:
  50        dout("failed to decode crypto key\n");
  51        return -EINVAL;
  52}
  53
  54int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
  55{
  56        int inlen = strlen(inkey);
  57        int blen = inlen * 3 / 4;
  58        void *buf, *p;
  59        int ret;
  60
  61        dout("crypto_key_unarmor %s\n", inkey);
  62        buf = kmalloc(blen, GFP_NOFS);
  63        if (!buf)
  64                return -ENOMEM;
  65        blen = ceph_unarmor(buf, inkey, inkey+inlen);
  66        if (blen < 0) {
  67                kfree(buf);
  68                return blen;
  69        }
  70
  71        p = buf;
  72        ret = ceph_crypto_key_decode(key, &p, p + blen);
  73        kfree(buf);
  74        if (ret)
  75                return ret;
  76        dout("crypto_key_unarmor key %p type %d len %d\n", key,
  77             key->type, key->len);
  78        return 0;
  79}
  80
  81
  82
  83#define AES_KEY_SIZE 16
  84
  85static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void)
  86{
  87        return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
  88}
  89
  90static const u8 *aes_iv = (u8 *)CEPH_AES_IV;
  91
  92static int ceph_aes_encrypt(const void *key, int key_len,
  93                            void *dst, size_t *dst_len,
  94                            const void *src, size_t src_len)
  95{
  96        struct scatterlist sg_in[2], sg_out[1];
  97        struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
  98        struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
  99        int ret;
 100        void *iv;
 101        int ivsize;
 102        size_t zero_padding = (0x10 - (src_len & 0x0f));
 103        char pad[16];
 104
 105        if (IS_ERR(tfm))
 106                return PTR_ERR(tfm);
 107
 108        memset(pad, zero_padding, zero_padding);
 109
 110        *dst_len = src_len + zero_padding;
 111
 112        crypto_blkcipher_setkey((void *)tfm, key, key_len);
 113        sg_init_table(sg_in, 2);
 114        sg_set_buf(&sg_in[0], src, src_len);
 115        sg_set_buf(&sg_in[1], pad, zero_padding);
 116        sg_init_table(sg_out, 1);
 117        sg_set_buf(sg_out, dst, *dst_len);
 118        iv = crypto_blkcipher_crt(tfm)->iv;
 119        ivsize = crypto_blkcipher_ivsize(tfm);
 120
 121        memcpy(iv, aes_iv, ivsize);
 122        /*
 123        print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
 124                       key, key_len, 1);
 125        print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
 126                        src, src_len, 1);
 127        print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
 128                        pad, zero_padding, 1);
 129        */
 130        ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
 131                                     src_len + zero_padding);
 132        crypto_free_blkcipher(tfm);
 133        if (ret < 0)
 134                pr_err("ceph_aes_crypt failed %d\n", ret);
 135        /*
 136        print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
 137                       dst, *dst_len, 1);
 138        */
 139        return 0;
 140}
 141
 142static int ceph_aes_encrypt2(const void *key, int key_len, void *dst,
 143                             size_t *dst_len,
 144                             const void *src1, size_t src1_len,
 145                             const void *src2, size_t src2_len)
 146{
 147        struct scatterlist sg_in[3], sg_out[1];
 148        struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 149        struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
 150        int ret;
 151        void *iv;
 152        int ivsize;
 153        size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
 154        char pad[16];
 155
 156        if (IS_ERR(tfm))
 157                return PTR_ERR(tfm);
 158
 159        memset(pad, zero_padding, zero_padding);
 160
 161        *dst_len = src1_len + src2_len + zero_padding;
 162
 163        crypto_blkcipher_setkey((void *)tfm, key, key_len);
 164        sg_init_table(sg_in, 3);
 165        sg_set_buf(&sg_in[0], src1, src1_len);
 166        sg_set_buf(&sg_in[1], src2, src2_len);
 167        sg_set_buf(&sg_in[2], pad, zero_padding);
 168        sg_init_table(sg_out, 1);
 169        sg_set_buf(sg_out, dst, *dst_len);
 170        iv = crypto_blkcipher_crt(tfm)->iv;
 171        ivsize = crypto_blkcipher_ivsize(tfm);
 172
 173        memcpy(iv, aes_iv, ivsize);
 174        /*
 175        print_hex_dump(KERN_ERR, "enc  key: ", DUMP_PREFIX_NONE, 16, 1,
 176                       key, key_len, 1);
 177        print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
 178                        src1, src1_len, 1);
 179        print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
 180                        src2, src2_len, 1);
 181        print_hex_dump(KERN_ERR, "enc  pad: ", DUMP_PREFIX_NONE, 16, 1,
 182                        pad, zero_padding, 1);
 183        */
 184        ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
 185                                     src1_len + src2_len + zero_padding);
 186        crypto_free_blkcipher(tfm);
 187        if (ret < 0)
 188                pr_err("ceph_aes_crypt2 failed %d\n", ret);
 189        /*
 190        print_hex_dump(KERN_ERR, "enc  out: ", DUMP_PREFIX_NONE, 16, 1,
 191                       dst, *dst_len, 1);
 192        */
 193        return 0;
 194}
 195
 196static int ceph_aes_decrypt(const void *key, int key_len,
 197                            void *dst, size_t *dst_len,
 198                            const void *src, size_t src_len)
 199{
 200        struct scatterlist sg_in[1], sg_out[2];
 201        struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 202        struct blkcipher_desc desc = { .tfm = tfm };
 203        char pad[16];
 204        void *iv;
 205        int ivsize;
 206        int ret;
 207        int last_byte;
 208
 209        if (IS_ERR(tfm))
 210                return PTR_ERR(tfm);
 211
 212        crypto_blkcipher_setkey((void *)tfm, key, key_len);
 213        sg_init_table(sg_in, 1);
 214        sg_init_table(sg_out, 2);
 215        sg_set_buf(sg_in, src, src_len);
 216        sg_set_buf(&sg_out[0], dst, *dst_len);
 217        sg_set_buf(&sg_out[1], pad, sizeof(pad));
 218
 219        iv = crypto_blkcipher_crt(tfm)->iv;
 220        ivsize = crypto_blkcipher_ivsize(tfm);
 221
 222        memcpy(iv, aes_iv, ivsize);
 223
 224        /*
 225        print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
 226                       key, key_len, 1);
 227        print_hex_dump(KERN_ERR, "dec  in: ", DUMP_PREFIX_NONE, 16, 1,
 228                       src, src_len, 1);
 229        */
 230
 231        ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
 232        crypto_free_blkcipher(tfm);
 233        if (ret < 0) {
 234                pr_err("ceph_aes_decrypt failed %d\n", ret);
 235                return ret;
 236        }
 237
 238        if (src_len <= *dst_len)
 239                last_byte = ((char *)dst)[src_len - 1];
 240        else
 241                last_byte = pad[src_len - *dst_len - 1];
 242        if (last_byte <= 16 && src_len >= last_byte) {
 243                *dst_len = src_len - last_byte;
 244        } else {
 245                pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
 246                       last_byte, (int)src_len);
 247                return -EPERM;  /* bad padding */
 248        }
 249        /*
 250        print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
 251                       dst, *dst_len, 1);
 252        */
 253        return 0;
 254}
 255
 256static int ceph_aes_decrypt2(const void *key, int key_len,
 257                             void *dst1, size_t *dst1_len,
 258                             void *dst2, size_t *dst2_len,
 259                             const void *src, size_t src_len)
 260{
 261        struct scatterlist sg_in[1], sg_out[3];
 262        struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 263        struct blkcipher_desc desc = { .tfm = tfm };
 264        char pad[16];
 265        void *iv;
 266        int ivsize;
 267        int ret;
 268        int last_byte;
 269
 270        if (IS_ERR(tfm))
 271                return PTR_ERR(tfm);
 272
 273        sg_init_table(sg_in, 1);
 274        sg_set_buf(sg_in, src, src_len);
 275        sg_init_table(sg_out, 3);
 276        sg_set_buf(&sg_out[0], dst1, *dst1_len);
 277        sg_set_buf(&sg_out[1], dst2, *dst2_len);
 278        sg_set_buf(&sg_out[2], pad, sizeof(pad));
 279
 280        crypto_blkcipher_setkey((void *)tfm, key, key_len);
 281        iv = crypto_blkcipher_crt(tfm)->iv;
 282        ivsize = crypto_blkcipher_ivsize(tfm);
 283
 284        memcpy(iv, aes_iv, ivsize);
 285
 286        /*
 287        print_hex_dump(KERN_ERR, "dec  key: ", DUMP_PREFIX_NONE, 16, 1,
 288                       key, key_len, 1);
 289        print_hex_dump(KERN_ERR, "dec   in: ", DUMP_PREFIX_NONE, 16, 1,
 290                       src, src_len, 1);
 291        */
 292
 293        ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
 294        crypto_free_blkcipher(tfm);
 295        if (ret < 0) {
 296                pr_err("ceph_aes_decrypt failed %d\n", ret);
 297                return ret;
 298        }
 299
 300        if (src_len <= *dst1_len)
 301                last_byte = ((char *)dst1)[src_len - 1];
 302        else if (src_len <= *dst1_len + *dst2_len)
 303                last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
 304        else
 305                last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
 306        if (last_byte <= 16 && src_len >= last_byte) {
 307                src_len -= last_byte;
 308        } else {
 309                pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
 310                       last_byte, (int)src_len);
 311                return -EPERM;  /* bad padding */
 312        }
 313
 314        if (src_len < *dst1_len) {
 315                *dst1_len = src_len;
 316                *dst2_len = 0;
 317        } else {
 318                *dst2_len = src_len - *dst1_len;
 319        }
 320        /*
 321        print_hex_dump(KERN_ERR, "dec  out1: ", DUMP_PREFIX_NONE, 16, 1,
 322                       dst1, *dst1_len, 1);
 323        print_hex_dump(KERN_ERR, "dec  out2: ", DUMP_PREFIX_NONE, 16, 1,
 324                       dst2, *dst2_len, 1);
 325        */
 326
 327        return 0;
 328}
 329
 330
 331int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 332                 const void *src, size_t src_len)
 333{
 334        switch (secret->type) {
 335        case CEPH_CRYPTO_NONE:
 336                if (*dst_len < src_len)
 337                        return -ERANGE;
 338                memcpy(dst, src, src_len);
 339                *dst_len = src_len;
 340                return 0;
 341
 342        case CEPH_CRYPTO_AES:
 343                return ceph_aes_decrypt(secret->key, secret->len, dst,
 344                                        dst_len, src, src_len);
 345
 346        default:
 347                return -EINVAL;
 348        }
 349}
 350
 351int ceph_decrypt2(struct ceph_crypto_key *secret,
 352                        void *dst1, size_t *dst1_len,
 353                        void *dst2, size_t *dst2_len,
 354                        const void *src, size_t src_len)
 355{
 356        size_t t;
 357
 358        switch (secret->type) {
 359        case CEPH_CRYPTO_NONE:
 360                if (*dst1_len + *dst2_len < src_len)
 361                        return -ERANGE;
 362                t = min(*dst1_len, src_len);
 363                memcpy(dst1, src, t);
 364                *dst1_len = t;
 365                src += t;
 366                src_len -= t;
 367                if (src_len) {
 368                        t = min(*dst2_len, src_len);
 369                        memcpy(dst2, src, t);
 370                        *dst2_len = t;
 371                }
 372                return 0;
 373
 374        case CEPH_CRYPTO_AES:
 375                return ceph_aes_decrypt2(secret->key, secret->len,
 376                                         dst1, dst1_len, dst2, dst2_len,
 377                                         src, src_len);
 378
 379        default:
 380                return -EINVAL;
 381        }
 382}
 383
 384int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 385                 const void *src, size_t src_len)
 386{
 387        switch (secret->type) {
 388        case CEPH_CRYPTO_NONE:
 389                if (*dst_len < src_len)
 390                        return -ERANGE;
 391                memcpy(dst, src, src_len);
 392                *dst_len = src_len;
 393                return 0;
 394
 395        case CEPH_CRYPTO_AES:
 396                return ceph_aes_encrypt(secret->key, secret->len, dst,
 397                                        dst_len, src, src_len);
 398
 399        default:
 400                return -EINVAL;
 401        }
 402}
 403
 404int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 405                  const void *src1, size_t src1_len,
 406                  const void *src2, size_t src2_len)
 407{
 408        switch (secret->type) {
 409        case CEPH_CRYPTO_NONE:
 410                if (*dst_len < src1_len + src2_len)
 411                        return -ERANGE;
 412                memcpy(dst, src1, src1_len);
 413                memcpy(dst + src1_len, src2, src2_len);
 414                *dst_len = src1_len + src2_len;
 415                return 0;
 416
 417        case CEPH_CRYPTO_AES:
 418                return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
 419                                         src1, src1_len, src2, src2_len);
 420
 421        default:
 422                return -EINVAL;
 423        }
 424}
 425
 426int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
 427{
 428        struct ceph_crypto_key *ckey;
 429        int ret;
 430        void *p;
 431
 432        ret = -EINVAL;
 433        if (datalen <= 0 || datalen > 32767 || !data)
 434                goto err;
 435
 436        ret = key_payload_reserve(key, datalen);
 437        if (ret < 0)
 438                goto err;
 439
 440        ret = -ENOMEM;
 441        ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
 442        if (!ckey)
 443                goto err;
 444
 445        /* TODO ceph_crypto_key_decode should really take const input */
 446        p = (void *)data;
 447        ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
 448        if (ret < 0)
 449                goto err_ckey;
 450
 451        key->payload.data = ckey;
 452        return 0;
 453
 454err_ckey:
 455        kfree(ckey);
 456err:
 457        return ret;
 458}
 459
 460int ceph_key_match(const struct key *key, const void *description)
 461{
 462        return strcmp(key->description, description) == 0;
 463}
 464
 465void ceph_key_destroy(struct key *key) {
 466        struct ceph_crypto_key *ckey = key->payload.data;
 467
 468        ceph_crypto_key_destroy(ckey);
 469        kfree(ckey);
 470}
 471
 472struct key_type key_type_ceph = {
 473        .name           = "ceph",
 474        .instantiate    = ceph_key_instantiate,
 475        .match          = ceph_key_match,
 476        .destroy        = ceph_key_destroy,
 477};
 478
 479int ceph_crypto_init(void) {
 480        return register_key_type(&key_type_ceph);
 481}
 482
 483void ceph_crypto_shutdown(void) {
 484        unregister_key_type(&key_type_ceph);
 485}
 486
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.