linux/arch/arm64/crypto/aes-ce-ccm-glue.c
<<
>>
Prefs
   1/*
   2 * aes-ccm-glue.c - AES-CCM transform for ARMv8 with Crypto Extensions
   3 *
   4 * Copyright (C) 2013 - 2014 Linaro Ltd <ard.biesheuvel@linaro.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <asm/neon.h>
  12#include <asm/unaligned.h>
  13#include <crypto/aes.h>
  14#include <crypto/algapi.h>
  15#include <crypto/scatterwalk.h>
  16#include <crypto/internal/aead.h>
  17#include <linux/module.h>
  18
  19#include "aes-ce-setkey.h"
  20
  21static int num_rounds(struct crypto_aes_ctx *ctx)
  22{
  23        /*
  24         * # of rounds specified by AES:
  25         * 128 bit key          10 rounds
  26         * 192 bit key          12 rounds
  27         * 256 bit key          14 rounds
  28         * => n byte key        => 6 + (n/4) rounds
  29         */
  30        return 6 + ctx->key_length / 4;
  31}
  32
  33asmlinkage void ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes,
  34                                     u32 *macp, u32 const rk[], u32 rounds);
  35
  36asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes,
  37                                   u32 const rk[], u32 rounds, u8 mac[],
  38                                   u8 ctr[]);
  39
  40asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes,
  41                                   u32 const rk[], u32 rounds, u8 mac[],
  42                                   u8 ctr[]);
  43
  44asmlinkage void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u32 const rk[],
  45                                 u32 rounds);
  46
  47static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key,
  48                      unsigned int key_len)
  49{
  50        struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm);
  51        int ret;
  52
  53        ret = ce_aes_expandkey(ctx, in_key, key_len);
  54        if (!ret)
  55                return 0;
  56
  57        tfm->base.crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
  58        return -EINVAL;
  59}
  60
  61static int ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
  62{
  63        if ((authsize & 1) || authsize < 4)
  64                return -EINVAL;
  65        return 0;
  66}
  67
  68static int ccm_init_mac(struct aead_request *req, u8 maciv[], u32 msglen)
  69{
  70        struct crypto_aead *aead = crypto_aead_reqtfm(req);
  71        __be32 *n = (__be32 *)&maciv[AES_BLOCK_SIZE - 8];
  72        u32 l = req->iv[0] + 1;
  73
  74        /* verify that CCM dimension 'L' is set correctly in the IV */
  75        if (l < 2 || l > 8)
  76                return -EINVAL;
  77
  78        /* verify that msglen can in fact be represented in L bytes */
  79        if (l < 4 && msglen >> (8 * l))
  80                return -EOVERFLOW;
  81
  82        /*
  83         * Even if the CCM spec allows L values of up to 8, the Linux cryptoapi
  84         * uses a u32 type to represent msglen so the top 4 bytes are always 0.
  85         */
  86        n[0] = 0;
  87        n[1] = cpu_to_be32(msglen);
  88
  89        memcpy(maciv, req->iv, AES_BLOCK_SIZE - l);
  90
  91        /*
  92         * Meaning of byte 0 according to CCM spec (RFC 3610/NIST 800-38C)
  93         * - bits 0..2  : max # of bytes required to represent msglen, minus 1
  94         *                (already set by caller)
  95         * - bits 3..5  : size of auth tag (1 => 4 bytes, 2 => 6 bytes, etc)
  96         * - bit 6      : indicates presence of authenticate-only data
  97         */
  98        maciv[0] |= (crypto_aead_authsize(aead) - 2) << 2;
  99        if (req->assoclen)
 100                maciv[0] |= 0x40;
 101
 102        memset(&req->iv[AES_BLOCK_SIZE - l], 0, l);
 103        return 0;
 104}
 105
 106static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[])
 107{
 108        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 109        struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
 110        struct __packed { __be16 l; __be32 h; u16 len; } ltag;
 111        struct scatter_walk walk;
 112        u32 len = req->assoclen;
 113        u32 macp = 0;
 114
 115        /* prepend the AAD with a length tag */
 116        if (len < 0xff00) {
 117                ltag.l = cpu_to_be16(len);
 118                ltag.len = 2;
 119        } else  {
 120                ltag.l = cpu_to_be16(0xfffe);
 121                put_unaligned_be32(len, &ltag.h);
 122                ltag.len = 6;
 123        }
 124
 125        ce_aes_ccm_auth_data(mac, (u8 *)&ltag, ltag.len, &macp, ctx->key_enc,
 126                             num_rounds(ctx));
 127        scatterwalk_start(&walk, req->src);
 128
 129        do {
 130                u32 n = scatterwalk_clamp(&walk, len);
 131                u8 *p;
 132
 133                if (!n) {
 134                        scatterwalk_start(&walk, sg_next(walk.sg));
 135                        n = scatterwalk_clamp(&walk, len);
 136                }
 137                p = scatterwalk_map(&walk);
 138                ce_aes_ccm_auth_data(mac, p, n, &macp, ctx->key_enc,
 139                                     num_rounds(ctx));
 140                len -= n;
 141
 142                scatterwalk_unmap(p);
 143                scatterwalk_advance(&walk, n);
 144                scatterwalk_done(&walk, 0, len);
 145        } while (len);
 146}
 147
 148static int ccm_encrypt(struct aead_request *req)
 149{
 150        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 151        struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
 152        struct blkcipher_desc desc = { .info = req->iv };
 153        struct blkcipher_walk walk;
 154        struct scatterlist srcbuf[2];
 155        struct scatterlist dstbuf[2];
 156        struct scatterlist *src;
 157        struct scatterlist *dst;
 158        u8 __aligned(8) mac[AES_BLOCK_SIZE];
 159        u8 buf[AES_BLOCK_SIZE];
 160        u32 len = req->cryptlen;
 161        int err;
 162
 163        err = ccm_init_mac(req, mac, len);
 164        if (err)
 165                return err;
 166
 167        kernel_neon_begin_partial(6);
 168
 169        if (req->assoclen)
 170                ccm_calculate_auth_mac(req, mac);
 171
 172        /* preserve the original iv for the final round */
 173        memcpy(buf, req->iv, AES_BLOCK_SIZE);
 174
 175        src = scatterwalk_ffwd(srcbuf, req->src, req->assoclen);
 176        dst = src;
 177        if (req->src != req->dst)
 178                dst = scatterwalk_ffwd(dstbuf, req->dst, req->assoclen);
 179
 180        blkcipher_walk_init(&walk, dst, src, len);
 181        err = blkcipher_aead_walk_virt_block(&desc, &walk, aead,
 182                                             AES_BLOCK_SIZE);
 183
 184        while (walk.nbytes) {
 185                u32 tail = walk.nbytes % AES_BLOCK_SIZE;
 186
 187                if (walk.nbytes == len)
 188                        tail = 0;
 189
 190                ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr,
 191                                   walk.nbytes - tail, ctx->key_enc,
 192                                   num_rounds(ctx), mac, walk.iv);
 193
 194                len -= walk.nbytes - tail;
 195                err = blkcipher_walk_done(&desc, &walk, tail);
 196        }
 197        if (!err)
 198                ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
 199
 200        kernel_neon_end();
 201
 202        if (err)
 203                return err;
 204
 205        /* copy authtag to end of dst */
 206        scatterwalk_map_and_copy(mac, dst, req->cryptlen,
 207                                 crypto_aead_authsize(aead), 1);
 208
 209        return 0;
 210}
 211
 212static int ccm_decrypt(struct aead_request *req)
 213{
 214        struct crypto_aead *aead = crypto_aead_reqtfm(req);
 215        struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead);
 216        unsigned int authsize = crypto_aead_authsize(aead);
 217        struct blkcipher_desc desc = { .info = req->iv };
 218        struct blkcipher_walk walk;
 219        struct scatterlist srcbuf[2];
 220        struct scatterlist dstbuf[2];
 221        struct scatterlist *src;
 222        struct scatterlist *dst;
 223        u8 __aligned(8) mac[AES_BLOCK_SIZE];
 224        u8 buf[AES_BLOCK_SIZE];
 225        u32 len = req->cryptlen - authsize;
 226        int err;
 227
 228        err = ccm_init_mac(req, mac, len);
 229        if (err)
 230                return err;
 231
 232        kernel_neon_begin_partial(6);
 233
 234        if (req->assoclen)
 235                ccm_calculate_auth_mac(req, mac);
 236
 237        /* preserve the original iv for the final round */
 238        memcpy(buf, req->iv, AES_BLOCK_SIZE);
 239
 240        src = scatterwalk_ffwd(srcbuf, req->src, req->assoclen);
 241        dst = src;
 242        if (req->src != req->dst)
 243                dst = scatterwalk_ffwd(dstbuf, req->dst, req->assoclen);
 244
 245        blkcipher_walk_init(&walk, dst, src, len);
 246        err = blkcipher_aead_walk_virt_block(&desc, &walk, aead,
 247                                             AES_BLOCK_SIZE);
 248
 249        while (walk.nbytes) {
 250                u32 tail = walk.nbytes % AES_BLOCK_SIZE;
 251
 252                if (walk.nbytes == len)
 253                        tail = 0;
 254
 255                ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr,
 256                                   walk.nbytes - tail, ctx->key_enc,
 257                                   num_rounds(ctx), mac, walk.iv);
 258
 259                len -= walk.nbytes - tail;
 260                err = blkcipher_walk_done(&desc, &walk, tail);
 261        }
 262        if (!err)
 263                ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx));
 264
 265        kernel_neon_end();
 266
 267        if (err)
 268                return err;
 269
 270        /* compare calculated auth tag with the stored one */
 271        scatterwalk_map_and_copy(buf, src, req->cryptlen - authsize,
 272                                 authsize, 0);
 273
 274        if (crypto_memneq(mac, buf, authsize))
 275                return -EBADMSG;
 276        return 0;
 277}
 278
 279static struct aead_alg ccm_aes_alg = {
 280        .base = {
 281                .cra_name               = "ccm(aes)",
 282                .cra_driver_name        = "ccm-aes-ce",
 283                .cra_priority           = 300,
 284                .cra_blocksize          = 1,
 285                .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
 286                .cra_alignmask          = 7,
 287                .cra_module             = THIS_MODULE,
 288        },
 289        .ivsize         = AES_BLOCK_SIZE,
 290        .maxauthsize    = AES_BLOCK_SIZE,
 291        .setkey         = ccm_setkey,
 292        .setauthsize    = ccm_setauthsize,
 293        .encrypt        = ccm_encrypt,
 294        .decrypt        = ccm_decrypt,
 295};
 296
 297static int __init aes_mod_init(void)
 298{
 299        if (!(elf_hwcap & HWCAP_AES))
 300                return -ENODEV;
 301        return crypto_register_aead(&ccm_aes_alg);
 302}
 303
 304static void __exit aes_mod_exit(void)
 305{
 306        crypto_unregister_aead(&ccm_aes_alg);
 307}
 308
 309module_init(aes_mod_init);
 310module_exit(aes_mod_exit);
 311
 312MODULE_DESCRIPTION("Synchronous AES in CCM mode using ARMv8 Crypto Extensions");
 313MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 314MODULE_LICENSE("GPL v2");
 315MODULE_ALIAS_CRYPTO("ccm(aes)");
 316