linux/crypto/cipher.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Cryptographic API.
   4 *
   5 * Single-block cipher operations.
   6 *
   7 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
   8 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
   9 */
  10
  11#include <crypto/algapi.h>
  12#include <linux/kernel.h>
  13#include <linux/crypto.h>
  14#include <linux/errno.h>
  15#include <linux/slab.h>
  16#include <linux/string.h>
  17#include "internal.h"
  18
  19static int setkey_unaligned(struct crypto_cipher *tfm, const u8 *key,
  20                            unsigned int keylen)
  21{
  22        struct cipher_alg *cia = crypto_cipher_alg(tfm);
  23        unsigned long alignmask = crypto_cipher_alignmask(tfm);
  24        int ret;
  25        u8 *buffer, *alignbuffer;
  26        unsigned long absize;
  27
  28        absize = keylen + alignmask;
  29        buffer = kmalloc(absize, GFP_ATOMIC);
  30        if (!buffer)
  31                return -ENOMEM;
  32
  33        alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
  34        memcpy(alignbuffer, key, keylen);
  35        ret = cia->cia_setkey(crypto_cipher_tfm(tfm), alignbuffer, keylen);
  36        memset(alignbuffer, 0, keylen);
  37        kfree(buffer);
  38        return ret;
  39
  40}
  41
  42int crypto_cipher_setkey(struct crypto_cipher *tfm,
  43                         const u8 *key, unsigned int keylen)
  44{
  45        struct cipher_alg *cia = crypto_cipher_alg(tfm);
  46        unsigned long alignmask = crypto_cipher_alignmask(tfm);
  47
  48        if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize)
  49                return -EINVAL;
  50
  51        if ((unsigned long)key & alignmask)
  52                return setkey_unaligned(tfm, key, keylen);
  53
  54        return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen);
  55}
  56EXPORT_SYMBOL_GPL(crypto_cipher_setkey);
  57
  58static inline void cipher_crypt_one(struct crypto_cipher *tfm,
  59                                    u8 *dst, const u8 *src, bool enc)
  60{
  61        unsigned long alignmask = crypto_cipher_alignmask(tfm);
  62        struct cipher_alg *cia = crypto_cipher_alg(tfm);
  63        void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
  64                enc ? cia->cia_encrypt : cia->cia_decrypt;
  65
  66        if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
  67                unsigned int bs = crypto_cipher_blocksize(tfm);
  68                u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
  69                u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
  70
  71                memcpy(tmp, src, bs);
  72                fn(crypto_cipher_tfm(tfm), tmp, tmp);
  73                memcpy(dst, tmp, bs);
  74        } else {
  75                fn(crypto_cipher_tfm(tfm), dst, src);
  76        }
  77}
  78
  79void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
  80                               u8 *dst, const u8 *src)
  81{
  82        cipher_crypt_one(tfm, dst, src, true);
  83}
  84EXPORT_SYMBOL_GPL(crypto_cipher_encrypt_one);
  85
  86void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
  87                               u8 *dst, const u8 *src)
  88{
  89        cipher_crypt_one(tfm, dst, src, false);
  90}
  91EXPORT_SYMBOL_GPL(crypto_cipher_decrypt_one);
  92