diff options
Diffstat (limited to 'xlators/encryption/crypt/src/data.c')
| -rw-r--r-- | xlators/encryption/crypt/src/data.c | 715 | 
1 files changed, 0 insertions, 715 deletions
diff --git a/xlators/encryption/crypt/src/data.c b/xlators/encryption/crypt/src/data.c deleted file mode 100644 index 93288b1a414..00000000000 --- a/xlators/encryption/crypt/src/data.c +++ /dev/null @@ -1,715 +0,0 @@ -/* -  Copyright (c) 2008-2013 Red Hat, Inc. <http://www.redhat.com> -  This file is part of GlusterFS. - -  This file is licensed to you under your choice of the GNU Lesser -  General Public License, version 3 or any later version (LGPLv3 or -  later), or the GNU General Public License, version 2 (GPLv2), in all -  cases as published by the Free Software Foundation. -*/ - -#include <glusterfs/defaults.h> -#include "crypt-common.h" -#include "crypt.h" - -static void -set_iv_aes_xts(off_t offset, struct object_cipher_info *object) -{ -    unsigned char *ivec; - -    ivec = object->u.aes_xts.ivec; - -    /* convert the tweak into a little-endian byte -     * array (IEEE P1619/D16, May 2007, section 5.1) -     */ - -    *((uint64_t *)ivec) = htole64(offset); - -    /* ivec is padded with zeroes */ -} - -static int32_t -aes_set_keys_common(unsigned char *raw_key, uint32_t key_size, AES_KEY *keys) -{ -    int32_t ret; - -    ret = AES_set_encrypt_key(raw_key, key_size, &keys[AES_ENCRYPT]); -    if (ret) { -        gf_log("crypt", GF_LOG_ERROR, "Set encrypt key failed"); -        return ret; -    } -    ret = AES_set_decrypt_key(raw_key, key_size, &keys[AES_DECRYPT]); -    if (ret) { -        gf_log("crypt", GF_LOG_ERROR, "Set decrypt key failed"); -        return ret; -    } -    return 0; -} - -/* - * set private cipher info for xts mode - */ -static int32_t -set_private_aes_xts(struct crypt_inode_info *info, -                    struct master_cipher_info *master) -{ -    int ret; -    struct object_cipher_info *object = get_object_cinfo(info); -    unsigned char *data_key; -    uint32_t subkey_size; - -    /* init tweak value */ -    memset(object->u.aes_xts.ivec, 0, 16); - -    data_key = GF_CALLOC(1, object->o_dkey_size, gf_crypt_mt_key); -    if (!data_key) -        return ENOMEM; - -    /* -     * retrieve data keying material -     */ -    ret = get_data_file_key(info, master, object->o_dkey_size, data_key); -    if (ret) { -        gf_log("crypt", GF_LOG_ERROR, "Failed to retrieve data key"); -        GF_FREE(data_key); -        return ret; -    } -    /* -     * parse compound xts key -     */ -    subkey_size = object->o_dkey_size >> 4; /* (xts-key-size-in-bytes / 2) */ -    /* -     * install key for data encryption -     */ -    ret = aes_set_keys_common(data_key, subkey_size << 3, -                              object->u.aes_xts.dkey); -    if (ret) { -        GF_FREE(data_key); -        return ret; -    } -    /* -     * set up key used to encrypt tweaks -     */ -    ret = AES_set_encrypt_key(data_key + subkey_size, object->o_dkey_size / 2, -                              &object->u.aes_xts.tkey); -    if (ret < 0) -        gf_log("crypt", GF_LOG_ERROR, "Set tweak key failed"); - -    GF_FREE(data_key); -    return ret; -} - -static int32_t -aes_xts_init(void) -{ -    cassert(AES_BLOCK_SIZE == (1 << AES_BLOCK_BITS)); -    return 0; -} - -static int32_t -check_key_aes_xts(uint32_t keysize) -{ -    switch (keysize) { -        case 256: -        case 512: -            return 0; -        default: -            break; -    } -    return -1; -} - -static int32_t -encrypt_aes_xts(const unsigned char *from, unsigned char *to, size_t length, -                off_t offset, const int enc, struct object_cipher_info *object) -{ -    XTS128_CONTEXT ctx; -    if (enc) { -        ctx.key1 = &object->u.aes_xts.dkey[AES_ENCRYPT]; -        ctx.block1 = (block128_f)AES_encrypt; -    } else { -        ctx.key1 = &object->u.aes_xts.dkey[AES_DECRYPT]; -        ctx.block1 = (block128_f)AES_decrypt; -    } -    ctx.key2 = &object->u.aes_xts.tkey; -    ctx.block2 = (block128_f)AES_encrypt; - -    return CRYPTO_xts128_encrypt(&ctx, object->u.aes_xts.ivec, from, to, length, -                                 enc); -} - -/* - * Cipher input chunk @from of length @len; - * @to: result of cipher transform; - * @off: offset in a file (must be cblock-aligned); - */ -static void -cipher_data(struct object_cipher_info *object, char *from, char *to, off_t off, -            size_t len, const int enc) -{ -    crypt_check_input_len(len, object); - -#if TRIVIAL_TFM && DEBUG_CRYPT -    return; -#endif -    data_cipher_algs[object->o_alg][object->o_mode].set_iv(off, object); -    data_cipher_algs[object->o_alg][object->o_mode].encrypt( -        (const unsigned char *)from, (unsigned char *)to, len, off, enc, -        object); -} - -#define MAX_CIPHER_CHUNK (1 << 30) - -/* - * Do cipher (encryption/decryption) transform of a - * continuous region of memory. - * - * @len: a number of bytes to transform; - * @buf: data to transform; - * @off: offset in a file, should be block-aligned - *       for atomic cipher modes and ksize-aligned - *       for other modes). - * @dir: direction of transform (encrypt/decrypt). - */ -static void -cipher_region(struct object_cipher_info *object, char *from, char *to, -              off_t off, size_t len, int dir) -{ -    while (len > 0) { -        size_t to_cipher; - -        to_cipher = len; -        if (to_cipher > MAX_CIPHER_CHUNK) -            to_cipher = MAX_CIPHER_CHUNK; - -        /* this will reset IV */ -        cipher_data(object, from, to, off, to_cipher, dir); -        from += to_cipher; -        to += to_cipher; -        off += to_cipher; -        len -= to_cipher; -    } -} - -/* - * Do cipher transform (encryption/decryption) of - * plaintext/ciphertext represented by @vec. - * - * Pre-conditions: @vec represents a continuous piece - * of data in a file at offset @off to be ciphered - * (encrypted/decrypted). - * @count is the number of vec's components. All the - * components must be block-aligned, the caller is - * responsible for this. @dir is "direction" of - * transform (encrypt/decrypt). - */ -static void -cipher_aligned_iov(struct object_cipher_info *object, struct iovec *vec, -                   int count, off_t off, int32_t dir) -{ -    int i; -    int len = 0; - -    for (i = 0; i < count; i++) { -        cipher_region(object, vec[i].iov_base, vec[i].iov_base, off + len, -                      vec[i].iov_len, dir); -        len += vec[i].iov_len; -    } -} - -void -encrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec, -                    int count, off_t off) -{ -    cipher_aligned_iov(object, vec, count, off, 1); -} - -void -decrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec, -                    int count, off_t off) -{ -    cipher_aligned_iov(object, vec, count, off, 0); -} - -#if DEBUG_CRYPT -static void -compound_stream(struct iovec *vec, int count, char *buf, off_t skip) -{ -    int i; -    int off = 0; -    for (i = 0; i < count; i++) { -        memcpy(buf + off, vec[i].iov_base + skip, vec[i].iov_len - skip); - -        off += (vec[i].iov_len - skip); -        skip = 0; -    } -} - -static void -check_iovecs(struct iovec *vec, int cnt, struct iovec *avec, int acnt, -             uint32_t off_in_head) -{ -    char *s1, *s2; -    uint32_t size, asize; - -    size = iov_length(vec, cnt); -    asize = iov_length(avec, acnt) - off_in_head; -    if (size != asize) { -        gf_log("crypt", GF_LOG_DEBUG, "size %d is not eq asize %d", size, -               asize); -        return; -    } -    s1 = GF_CALLOC(1, size, gf_crypt_mt_data); -    if (!s1) { -        gf_log("crypt", GF_LOG_DEBUG, "Can not allocate stream "); -        return; -    } -    s2 = GF_CALLOC(1, asize, gf_crypt_mt_data); -    if (!s2) { -        GF_FREE(s1); -        gf_log("crypt", GF_LOG_DEBUG, "Can not allocate stream "); -        return; -    } -    compound_stream(vec, cnt, s1, 0); -    compound_stream(avec, acnt, s2, off_in_head); -    if (memcmp(s1, s2, size)) -        gf_log("crypt", GF_LOG_DEBUG, "chunks of different data"); -    GF_FREE(s1); -    GF_FREE(s2); -} - -#else -#define check_iovecs(vec, count, avec, avecn, off) noop -#endif /* DEBUG_CRYPT */ - -static char * -data_alloc_block(xlator_t *this, crypt_local_t *local, int32_t block_size) -{ -    struct iobuf *iobuf = NULL; - -    iobuf = iobuf_get2(this->ctx->iobuf_pool, block_size); -    if (!iobuf) { -        gf_log("crypt", GF_LOG_ERROR, "Failed to get iobuf"); -        return NULL; -    } -    if (!local->iobref_data) { -        local->iobref_data = iobref_new(); -        if (!local->iobref_data) { -            gf_log("crypt", GF_LOG_ERROR, "Failed to get iobref"); -            iobuf_unref(iobuf); -            return NULL; -        } -    } -    iobref_add(local->iobref_data, iobuf); -    return iobuf->ptr; -} - -/* - * Compound @avec, which represent the same data - * chunk as @vec, but has aligned components of - * specified block size. Alloc blocks, if needed. - * In particular, incomplete head and tail blocks - * must be allocated. - * Put number of allocated blocks to @num_blocks. - * - * Example: - * - * input: data chunk represented by 4 components - * [AB],[BC],[CD],[DE]; - * output: 5 logical blocks (0, 1, 2, 3, 4). - * - *   A     B       C     D               E - *   *-----*+------*-+---*----+--------+-* - *   |     ||      | |   |    |        | | - * *-+-----+*------+-*---+----*--------*-+------* - * 0        1        2        3        4 - * - * 0 - incomplete compound (head); - * 1, 2 - full compound; - * 3 - full non-compound (the case of reuse); - * 4 - incomplete non-compound (tail). - */ -int32_t -align_iov_by_atoms(xlator_t *this, crypt_local_t *local, -                   struct object_cipher_info *object, -                   struct iovec *vec /* input vector */, -                   int32_t count /* number of vec components */, -                   struct iovec *avec /* aligned vector */, -                   char **blocks /* pool of blocks */, -                   uint32_t *blocks_allocated, struct avec_config *conf) -{ -    int vecn = 0;      /* number of the current component in vec */ -    int avecn = 0;     /* number of the current component in avec */ -    off_t vec_off = 0; /* offset in the current vec component, -                        * i.e. the number of bytes have already -                        * been copied */ -    int32_t block_size = get_atom_size(object); -    size_t to_process; /* number of vec's bytes to copy and(or) re-use */ -    int32_t off_in_head = conf->off_in_head; - -    to_process = iov_length(vec, count); - -    while (to_process > 0) { -        if (off_in_head || vec[vecn].iov_len - vec_off < block_size) { -            /* -             * less than block_size: -             * the case of incomplete (head or tail), -             * or compound block -             */ -            size_t copied = 0; -            /* -             * populate the pool with a new block -             */ -            blocks[*blocks_allocated] = data_alloc_block(this, local, -                                                         block_size); -            if (!blocks[*blocks_allocated]) -                return -ENOMEM; -            memset(blocks[*blocks_allocated], 0, off_in_head); -            /* -             * fill the block with vec components -             */ -            do { -                size_t to_copy; - -                to_copy = vec[vecn].iov_len - vec_off; -                if (to_copy > block_size - off_in_head) -                    to_copy = block_size - off_in_head; - -                memcpy(blocks[*blocks_allocated] + off_in_head + copied, -                       vec[vecn].iov_base + vec_off, to_copy); - -                copied += to_copy; -                to_process -= to_copy; - -                vec_off += to_copy; -                if (vec_off == vec[vecn].iov_len) { -                    /* finished with this vecn */ -                    vec_off = 0; -                    vecn++; -                } -            } while (copied < (block_size - off_in_head) && to_process > 0); -            /* -             * update avec -             */ -            avec[avecn].iov_len = off_in_head + copied; -            avec[avecn].iov_base = blocks[*blocks_allocated]; - -            (*blocks_allocated)++; -            off_in_head = 0; -        } else { -            /* -             * the rest of the current vec component -             * is not less than block_size, so reuse -             * the memory buffer of the component. -             */ -            size_t to_reuse; -            to_reuse = (to_process > block_size ? block_size : to_process); -            avec[avecn].iov_len = to_reuse; -            avec[avecn].iov_base = vec[vecn].iov_base + vec_off; - -            vec_off += to_reuse; -            if (vec_off == vec[vecn].iov_len) { -                /* finished with this vecn */ -                vec_off = 0; -                vecn++; -            } -            to_process -= to_reuse; -        } -        avecn++; -    } -    check_iovecs(vec, count, avec, avecn, conf->off_in_head); -    return 0; -} - -/* - * allocate and setup aligned vector for data submission - * Pre-condition: @conf is set. - */ -int32_t -set_config_avec_data(xlator_t *this, crypt_local_t *local, -                     struct avec_config *conf, -                     struct object_cipher_info *object, struct iovec *vec, -                     int32_t vec_count) -{ -    int32_t ret = ENOMEM; -    struct iovec *avec; -    char **pool; -    uint32_t blocks_in_pool = 0; - -    conf->type = DATA_ATOM; - -    avec = GF_CALLOC(conf->acount, sizeof(*avec), gf_crypt_mt_iovec); -    if (!avec) -        return ret; -    pool = GF_CALLOC(conf->acount, sizeof(*pool), gf_crypt_mt_char); -    if (!pool) { -        GF_FREE(avec); -        return ret; -    } -    if (!vec) { -        /* -         * degenerated case: no data -         */ -        pool[0] = data_alloc_block(this, local, get_atom_size(object)); -        if (!pool[0]) -            goto free; -        blocks_in_pool = 1; -        avec->iov_base = pool[0]; -        avec->iov_len = conf->off_in_tail; -    } else { -        ret = align_iov_by_atoms(this, local, object, vec, vec_count, avec, -                                 pool, &blocks_in_pool, conf); -        if (ret) -            goto free; -    } -    conf->avec = avec; -    conf->pool = pool; -    conf->blocks_in_pool = blocks_in_pool; -    return 0; -free: -    GF_FREE(avec); -    GF_FREE(pool); -    return ret; -} - -/* - * allocate and setup aligned vector for hole submission - */ -int32_t -set_config_avec_hole(xlator_t *this, crypt_local_t *local, -                     struct avec_config *conf, -                     struct object_cipher_info *object, glusterfs_fop_t fop) -{ -    uint32_t i, idx; -    struct iovec *avec; -    char **pool; -    uint32_t num_blocks; -    uint32_t blocks_in_pool = 0; - -    conf->type = HOLE_ATOM; - -    num_blocks = conf->acount - -                 (conf->nr_full_blocks ? conf->nr_full_blocks - 1 : 0); - -    switch (fop) { -        case GF_FOP_WRITE: -            /* -             * hole goes before data -             */ -            if (num_blocks == 1 && conf->off_in_tail != 0) -                /* -                 * we won't submit a hole which fits into -                 * a data atom: this part of hole will be -                 * submitted with data write -                 */ -                return 0; -            break; -        case GF_FOP_FTRUNCATE: -            /* -             * expanding truncate, hole goes after data, -             * and will be submitted in any case. -             */ -            break; -        default: -            gf_log("crypt", GF_LOG_WARNING, "bad file operation %d", fop); -            return 0; -    } -    avec = GF_CALLOC(num_blocks, sizeof(*avec), gf_crypt_mt_iovec); -    if (!avec) -        return ENOMEM; -    pool = GF_CALLOC(num_blocks, sizeof(*pool), gf_crypt_mt_char); -    if (!pool) { -        GF_FREE(avec); -        return ENOMEM; -    } -    for (i = 0; i < num_blocks; i++) { -        pool[i] = data_alloc_block(this, local, get_atom_size(object)); -        if (pool[i] == NULL) -            goto free; -        blocks_in_pool++; -    } -    if (has_head_block(conf)) { -        /* set head block */ -        idx = 0; -        avec[idx].iov_base = pool[idx]; -        avec[idx].iov_len = get_atom_size(object); -        memset(avec[idx].iov_base + conf->off_in_head, 0, -               get_atom_size(object) - conf->off_in_head); -    } -    if (has_tail_block(conf)) { -        /* set tail block */ -        idx = num_blocks - 1; -        avec[idx].iov_base = pool[idx]; -        avec[idx].iov_len = get_atom_size(object); -        memset(avec[idx].iov_base, 0, conf->off_in_tail); -    } -    if (has_full_blocks(conf)) { -        /* set full block */ -        idx = conf->off_in_head ? 1 : 0; -        avec[idx].iov_base = pool[idx]; -        avec[idx].iov_len = get_atom_size(object); -        /* -         * since we re-use the buffer, -         * zeroes will be set every time -         * before encryption, see submit_full() -         */ -    } -    conf->avec = avec; -    conf->pool = pool; -    conf->blocks_in_pool = blocks_in_pool; -    return 0; -free: -    GF_FREE(avec); -    GF_FREE(pool); -    return ENOMEM; -} - -/* A helper for setting up config of partial atoms (which - * participate in read-modify-write sequence). - * - * Calculate and setup precise amount of "extra-bytes" - * that should be uptodated at the end of partial (not - * necessarily tail!) block. - * - * Pre-condition: local->old_file_size is valid! - * @conf contains setup, which is enough for correct calculation - * of has_tail_block(), ->get_offset(). - */ -void -set_gap_at_end(call_frame_t *frame, struct object_cipher_info *object, -               struct avec_config *conf, atom_data_type dtype) -{ -    uint32_t to_block; -    crypt_local_t *local = frame->local; -    uint64_t old_file_size = local->old_file_size; -    struct rmw_atom *partial = atom_by_types( -        dtype, has_tail_block(conf) ? TAIL_ATOM : HEAD_ATOM); - -    if (old_file_size <= partial->offset_at(frame, object)) -        to_block = 0; -    else { -        to_block = old_file_size - partial->offset_at(frame, object); -        if (to_block > get_atom_size(object)) -            to_block = get_atom_size(object); -    } -    if (to_block > conf->off_in_tail) -        conf->gap_in_tail = to_block - conf->off_in_tail; -    else -        /* -         * nothing to uptodate -         */ -        conf->gap_in_tail = 0; -} - -/* - * fill struct avec_config with offsets layouts - */ -void -set_config_offsets(call_frame_t *frame, xlator_t *this, uint64_t offset, -                   uint64_t count, atom_data_type dtype, int32_t set_gap) -{ -    crypt_local_t *local; -    struct object_cipher_info *object; -    struct avec_config *conf; -    uint32_t resid; - -    uint32_t atom_size; -    uint32_t atom_bits; - -    size_t orig_size; -    off_t orig_offset; -    size_t expanded_size; -    off_t aligned_offset; - -    uint32_t off_in_head = 0; -    uint32_t off_in_tail = 0; -    uint32_t nr_full_blocks; -    int32_t size_full_blocks; - -    uint32_t acount; /* number of aligned components to write. -                      * The same as number of occupied logical -                      * blocks (atoms) -                      */ -    local = frame->local; -    object = &local->info->cinfo; -    conf = (dtype == DATA_ATOM ? get_data_conf(frame) : get_hole_conf(frame)); - -    orig_offset = offset; -    orig_size = count; - -    atom_size = get_atom_size(object); -    atom_bits = get_atom_bits(object); - -    /* -     * Round-down the start, -     * round-up the end. -     */ -    resid = offset & (uint64_t)(atom_size - 1); - -    if (resid) -        off_in_head = resid; -    aligned_offset = offset - off_in_head; -    expanded_size = orig_size + off_in_head; - -    /* calculate tail, -       expand size forward  */ -    resid = (offset + orig_size) & (uint64_t)(atom_size - 1); - -    if (resid) { -        off_in_tail = resid; -        expanded_size += (atom_size - off_in_tail); -    } -    /* -     * calculate number of occupied blocks -     */ -    acount = expanded_size >> atom_bits; -    /* -     * calculate number of full blocks -     */ -    size_full_blocks = expanded_size; -    if (off_in_head) -        size_full_blocks -= atom_size; -    if (off_in_tail && size_full_blocks > 0) -        size_full_blocks -= atom_size; -    nr_full_blocks = size_full_blocks >> atom_bits; - -    conf->atom_size = atom_size; -    conf->orig_size = orig_size; -    conf->orig_offset = orig_offset; -    conf->expanded_size = expanded_size; -    conf->aligned_offset = aligned_offset; - -    conf->off_in_head = off_in_head; -    conf->off_in_tail = off_in_tail; -    conf->nr_full_blocks = nr_full_blocks; -    conf->acount = acount; -    /* -     * Finally, calculate precise amount of -     * "extra-bytes" that should be uptodated -     * at the end. -     * Only if RMW is expected. -     */ -    if (off_in_tail && set_gap) -        set_gap_at_end(frame, object, conf, dtype); -} - -struct data_cipher_alg data_cipher_algs[LAST_CIPHER_ALG][LAST_CIPHER_MODE] = { -    [AES_CIPHER_ALG][XTS_CIPHER_MODE] = {.atomic = _gf_true, -                                         .should_pad = _gf_true, -                                         .blkbits = AES_BLOCK_BITS, -                                         .init = aes_xts_init, -                                         .set_private = set_private_aes_xts, -                                         .check_key = check_key_aes_xts, -                                         .set_iv = set_iv_aes_xts, -                                         .encrypt = encrypt_aes_xts}}; - -/* -  Local variables: -  c-indentation-style: "K&R" -  mode-name: "LC" -  c-basic-offset: 8 -  tab-width: 8 -  fill-column: 80 -  scroll-step: 1 -  End: -*/  | 
