]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - include/linux/crypto.h
[CRYPTO] cipher: Added block cipher type
[linux-3.10.git] / include / linux / crypto.h
index 7f946241b8792f9e163765d6b1d8b7a53534a3e8..5a5466d518e8e74c85232f92245e0ad08cc63df3 100644 (file)
 #ifndef _LINUX_CRYPTO_H
 #define _LINUX_CRYPTO_H
 
+#include <asm/atomic.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/string.h>
-#include <asm/page.h>
+#include <linux/uaccess.h>
 
 /*
  * Algorithm masks and types.
  */
-#define CRYPTO_ALG_TYPE_MASK           0x000000ff
+#define CRYPTO_ALG_TYPE_MASK           0x0000000f
 #define CRYPTO_ALG_TYPE_CIPHER         0x00000001
 #define CRYPTO_ALG_TYPE_DIGEST         0x00000002
+#define CRYPTO_ALG_TYPE_BLKCIPHER      0x00000003
 #define CRYPTO_ALG_TYPE_COMPRESS       0x00000004
 
+#define CRYPTO_ALG_LARVAL              0x00000010
+#define CRYPTO_ALG_DEAD                        0x00000020
+#define CRYPTO_ALG_DYING               0x00000040
+#define CRYPTO_ALG_ASYNC               0x00000080
+
 /*
  * Transform masks and values (for crt_flags).
  */
 #define CRYPTO_DIR_ENCRYPT             1
 #define CRYPTO_DIR_DECRYPT             0
 
+/*
+ * The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual
+ * declaration) is used to ensure that the crypto_tfm context structure is
+ * aligned correctly for the given architecture so that there are no alignment
+ * faults for C data types.  In particular, this is required on platforms such
+ * as arm where pointers are 32-bit aligned but there are data types such as
+ * u64 which require 64-bit alignment.
+ */
+#if defined(ARCH_KMALLOC_MINALIGN)
+#define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN
+#elif defined(ARCH_SLAB_MINALIGN)
+#define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN
+#endif
+
+#ifdef CRYPTO_MINALIGN
+#define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN)))
+#else
+#define CRYPTO_MINALIGN_ATTR
+#endif
+
 struct scatterlist;
+struct crypto_blkcipher;
 struct crypto_tfm;
+struct crypto_type;
+
+struct blkcipher_desc {
+       struct crypto_blkcipher *tfm;
+       void *info;
+       u32 flags;
+};
 
 struct cipher_desc {
        struct crypto_tfm *tfm;
@@ -76,11 +112,26 @@ struct cipher_desc {
  * Algorithms: modular crypto algorithm implementations, managed
  * via crypto_register_alg() and crypto_unregister_alg().
  */
+struct blkcipher_alg {
+       int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
+                     unsigned int keylen);
+       int (*encrypt)(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes);
+       int (*decrypt)(struct blkcipher_desc *desc,
+                      struct scatterlist *dst, struct scatterlist *src,
+                      unsigned int nbytes);
+
+       unsigned int min_keysize;
+       unsigned int max_keysize;
+       unsigned int ivsize;
+};
+
 struct cipher_alg {
        unsigned int cia_min_keysize;
        unsigned int cia_max_keysize;
        int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key,
-                         unsigned int keylen, u32 *flags);
+                         unsigned int keylen);
        void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
        void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 
@@ -105,7 +156,7 @@ struct digest_alg {
                           unsigned int len);
        void (*dia_final)(struct crypto_tfm *tfm, u8 *out);
        int (*dia_setkey)(struct crypto_tfm *tfm, const u8 *key,
-                         unsigned int keylen, u32 *flags);
+                         unsigned int keylen);
 };
 
 struct compress_alg {
@@ -115,23 +166,30 @@ struct compress_alg {
                              unsigned int slen, u8 *dst, unsigned int *dlen);
 };
 
+#define cra_blkcipher  cra_u.blkcipher
 #define cra_cipher     cra_u.cipher
 #define cra_digest     cra_u.digest
 #define cra_compress   cra_u.compress
 
 struct crypto_alg {
        struct list_head cra_list;
+       struct list_head cra_users;
+
        u32 cra_flags;
        unsigned int cra_blocksize;
        unsigned int cra_ctxsize;
        unsigned int cra_alignmask;
 
        int cra_priority;
+       atomic_t cra_refcnt;
 
        char cra_name[CRYPTO_MAX_ALG_NAME];
        char cra_driver_name[CRYPTO_MAX_ALG_NAME];
 
+       const struct crypto_type *cra_type;
+
        union {
+               struct blkcipher_alg blkcipher;
                struct cipher_alg cipher;
                struct digest_alg digest;
                struct compress_alg compress;
@@ -139,6 +197,7 @@ struct crypto_alg {
 
        int (*cra_init)(struct crypto_tfm *tfm);
        void (*cra_exit)(struct crypto_tfm *tfm);
+       void (*cra_destroy)(struct crypto_alg *alg);
        
        struct module *cra_module;
 };
@@ -163,10 +222,20 @@ static inline int crypto_alg_available(const char *name, u32 flags)
 
 /*
  * Transforms: user-instantiated objects which encapsulate algorithms
- * and core processing logic.  Managed via crypto_alloc_tfm() and
- * crypto_free_tfm(), as well as the various helpers below.
+ * and core processing logic.  Managed via crypto_alloc_*() and
+ * crypto_free_*(), as well as the various helpers below.
  */
 
+struct blkcipher_tfm {
+       void *iv;
+       int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
+                     unsigned int keylen);
+       int (*encrypt)(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes);
+       int (*decrypt)(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes);
+};
+
 struct cipher_tfm {
        void *cit_iv;
        unsigned int cit_ivsize;
@@ -190,6 +259,8 @@ struct cipher_tfm {
                           struct scatterlist *src,
                           unsigned int nbytes, u8 *iv);
        void (*cit_xor_block)(u8 *dst, const u8 *src);
+       void (*cit_encrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
+       void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
 };
 
 struct digest_tfm {
@@ -215,6 +286,7 @@ struct compress_tfm {
                              u8 *dst, unsigned int *dlen);
 };
 
+#define crt_blkcipher  crt_u.blkcipher
 #define crt_cipher     crt_u.cipher
 #define crt_digest     crt_u.digest
 #define crt_compress   crt_u.compress
@@ -224,6 +296,7 @@ struct crypto_tfm {
        u32 crt_flags;
        
        union {
+               struct blkcipher_tfm blkcipher;
                struct cipher_tfm cipher;
                struct digest_tfm digest;
                struct compress_tfm compress;
@@ -231,23 +304,30 @@ struct crypto_tfm {
        
        struct crypto_alg *__crt_alg;
 
-       char __crt_ctx[] __attribute__ ((__aligned__));
+       void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
+#define crypto_cipher crypto_tfm
+
+struct crypto_blkcipher {
+       struct crypto_tfm base;
+};
+
+enum {
+       CRYPTOA_UNSPEC,
+       CRYPTOA_ALG,
+};
+
+struct crypto_attr_alg {
+       char name[CRYPTO_MAX_ALG_NAME];
 };
 
 /* 
  * Transform user interface.
  */
  
-/*
- * crypto_alloc_tfm() will first attempt to locate an already loaded algorithm.
- * If that fails and the kernel supports dynamically loadable modules, it
- * will then attempt to load a module of the same name or alias.  A refcount
- * is grabbed on the algorithm which is then associated with the new transform.
- *
- * crypto_free_tfm() frees up the transform and any associated resources,
- * then drops the refcount on the associated algorithm.
- */
 struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
+struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask);
 void crypto_free_tfm(struct crypto_tfm *tfm);
 
 /*
@@ -258,6 +338,16 @@ static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm)
        return tfm->__crt_alg->cra_name;
 }
 
+static inline const char *crypto_tfm_alg_driver_name(struct crypto_tfm *tfm)
+{
+       return tfm->__crt_alg->cra_driver_name;
+}
+
+static inline int crypto_tfm_alg_priority(struct crypto_tfm *tfm)
+{
+       return tfm->__crt_alg->cra_priority;
+}
+
 static inline const char *crypto_tfm_alg_modname(struct crypto_tfm *tfm)
 {
        return module_name(tfm->__crt_alg->cra_module);
@@ -302,6 +392,21 @@ static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm)
        return tfm->__crt_alg->cra_alignmask;
 }
 
+static inline u32 crypto_tfm_get_flags(struct crypto_tfm *tfm)
+{
+       return tfm->crt_flags;
+}
+
+static inline void crypto_tfm_set_flags(struct crypto_tfm *tfm, u32 flags)
+{
+       tfm->crt_flags |= flags;
+}
+
+static inline void crypto_tfm_clear_flags(struct crypto_tfm *tfm, u32 flags)
+{
+       tfm->crt_flags &= ~flags;
+}
+
 static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
 {
        return tfm->__crt_ctx;
@@ -316,6 +421,221 @@ static inline unsigned int crypto_tfm_ctx_alignment(void)
 /*
  * API wrappers.
  */
+static inline struct crypto_blkcipher *__crypto_blkcipher_cast(
+       struct crypto_tfm *tfm)
+{
+       return (struct crypto_blkcipher *)tfm;
+}
+
+static inline struct crypto_blkcipher *crypto_blkcipher_cast(
+       struct crypto_tfm *tfm)
+{
+       BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_BLKCIPHER);
+       return __crypto_blkcipher_cast(tfm);
+}
+
+static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
+       const char *alg_name, u32 type, u32 mask)
+{
+       type &= ~CRYPTO_ALG_TYPE_MASK;
+       type |= CRYPTO_ALG_TYPE_BLKCIPHER;
+       mask |= CRYPTO_ALG_TYPE_MASK;
+
+       return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_blkcipher_tfm(
+       struct crypto_blkcipher *tfm)
+{
+       return &tfm->base;
+}
+
+static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm)
+{
+       crypto_free_tfm(crypto_blkcipher_tfm(tfm));
+}
+
+static inline const char *crypto_blkcipher_name(struct crypto_blkcipher *tfm)
+{
+       return crypto_tfm_alg_name(crypto_blkcipher_tfm(tfm));
+}
+
+static inline struct blkcipher_tfm *crypto_blkcipher_crt(
+       struct crypto_blkcipher *tfm)
+{
+       return &crypto_blkcipher_tfm(tfm)->crt_blkcipher;
+}
+
+static inline struct blkcipher_alg *crypto_blkcipher_alg(
+       struct crypto_blkcipher *tfm)
+{
+       return &crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher;
+}
+
+static inline unsigned int crypto_blkcipher_ivsize(struct crypto_blkcipher *tfm)
+{
+       return crypto_blkcipher_alg(tfm)->ivsize;
+}
+
+static inline unsigned int crypto_blkcipher_blocksize(
+       struct crypto_blkcipher *tfm)
+{
+       return crypto_tfm_alg_blocksize(crypto_blkcipher_tfm(tfm));
+}
+
+static inline unsigned int crypto_blkcipher_alignmask(
+       struct crypto_blkcipher *tfm)
+{
+       return crypto_tfm_alg_alignmask(crypto_blkcipher_tfm(tfm));
+}
+
+static inline u32 crypto_blkcipher_get_flags(struct crypto_blkcipher *tfm)
+{
+       return crypto_tfm_get_flags(crypto_blkcipher_tfm(tfm));
+}
+
+static inline void crypto_blkcipher_set_flags(struct crypto_blkcipher *tfm,
+                                             u32 flags)
+{
+       crypto_tfm_set_flags(crypto_blkcipher_tfm(tfm), flags);
+}
+
+static inline void crypto_blkcipher_clear_flags(struct crypto_blkcipher *tfm,
+                                               u32 flags)
+{
+       crypto_tfm_clear_flags(crypto_blkcipher_tfm(tfm), flags);
+}
+
+static inline int crypto_blkcipher_setkey(struct crypto_blkcipher *tfm,
+                                         const u8 *key, unsigned int keylen)
+{
+       return crypto_blkcipher_crt(tfm)->setkey(crypto_blkcipher_tfm(tfm),
+                                                key, keylen);
+}
+
+static inline int crypto_blkcipher_encrypt(struct blkcipher_desc *desc,
+                                          struct scatterlist *dst,
+                                          struct scatterlist *src,
+                                          unsigned int nbytes)
+{
+       desc->info = crypto_blkcipher_crt(desc->tfm)->iv;
+       return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes);
+}
+
+static inline int crypto_blkcipher_encrypt_iv(struct blkcipher_desc *desc,
+                                             struct scatterlist *dst,
+                                             struct scatterlist *src,
+                                             unsigned int nbytes)
+{
+       return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes);
+}
+
+static inline int crypto_blkcipher_decrypt(struct blkcipher_desc *desc,
+                                          struct scatterlist *dst,
+                                          struct scatterlist *src,
+                                          unsigned int nbytes)
+{
+       desc->info = crypto_blkcipher_crt(desc->tfm)->iv;
+       return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes);
+}
+
+static inline int crypto_blkcipher_decrypt_iv(struct blkcipher_desc *desc,
+                                             struct scatterlist *dst,
+                                             struct scatterlist *src,
+                                             unsigned int nbytes)
+{
+       return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes);
+}
+
+static inline void crypto_blkcipher_set_iv(struct crypto_blkcipher *tfm,
+                                          const u8 *src, unsigned int len)
+{
+       memcpy(crypto_blkcipher_crt(tfm)->iv, src, len);
+}
+
+static inline void crypto_blkcipher_get_iv(struct crypto_blkcipher *tfm,
+                                          u8 *dst, unsigned int len)
+{
+       memcpy(dst, crypto_blkcipher_crt(tfm)->iv, len);
+}
+
+static inline struct crypto_cipher *__crypto_cipher_cast(struct crypto_tfm *tfm)
+{
+       return (struct crypto_cipher *)tfm;
+}
+
+static inline struct crypto_cipher *crypto_cipher_cast(struct crypto_tfm *tfm)
+{
+       BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
+       return __crypto_cipher_cast(tfm);
+}
+
+static inline struct crypto_cipher *crypto_alloc_cipher(const char *alg_name,
+                                                       u32 type, u32 mask)
+{
+       type &= ~CRYPTO_ALG_TYPE_MASK;
+       type |= CRYPTO_ALG_TYPE_CIPHER;
+       mask |= CRYPTO_ALG_TYPE_MASK;
+
+       return __crypto_cipher_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm)
+{
+       return tfm;
+}
+
+static inline void crypto_free_cipher(struct crypto_cipher *tfm)
+{
+       crypto_free_tfm(crypto_cipher_tfm(tfm));
+}
+
+static inline struct cipher_tfm *crypto_cipher_crt(struct crypto_cipher *tfm)
+{
+       return &crypto_cipher_tfm(tfm)->crt_cipher;
+}
+
+static inline unsigned int crypto_cipher_blocksize(struct crypto_cipher *tfm)
+{
+       return crypto_tfm_alg_blocksize(crypto_cipher_tfm(tfm));
+}
+
+static inline unsigned int crypto_cipher_alignmask(struct crypto_cipher *tfm)
+{
+       return crypto_tfm_alg_alignmask(crypto_cipher_tfm(tfm));
+}
+
+static inline u32 crypto_cipher_get_flags(struct crypto_cipher *tfm)
+{
+       return crypto_tfm_get_flags(crypto_cipher_tfm(tfm));
+}
+
+static inline void crypto_cipher_set_flags(struct crypto_cipher *tfm,
+                                          u32 flags)
+{
+       crypto_tfm_set_flags(crypto_cipher_tfm(tfm), flags);
+}
+
+static inline void crypto_cipher_clear_flags(struct crypto_cipher *tfm,
+                                            u32 flags)
+{
+       crypto_tfm_clear_flags(crypto_cipher_tfm(tfm), flags);
+}
+
+static inline void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
+                                            u8 *dst, const u8 *src)
+{
+       crypto_cipher_crt(tfm)->cit_encrypt_one(crypto_cipher_tfm(tfm),
+                                               dst, src);
+}
+
+static inline void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
+                                            u8 *dst, const u8 *src)
+{
+       crypto_cipher_crt(tfm)->cit_decrypt_one(crypto_cipher_tfm(tfm),
+                                               dst, src);
+}
+
 static inline void crypto_digest_init(struct crypto_tfm *tfm)
 {
        BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
@@ -348,8 +668,6 @@ static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
                                        const u8 *key, unsigned int keylen)
 {
        BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
-       if (tfm->crt_digest.dit_setkey == NULL)
-               return -ENOSYS;
        return tfm->crt_digest.dit_setkey(tfm, key, keylen);
 }
 
@@ -375,7 +693,6 @@ static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm,
                                            unsigned int nbytes, u8 *iv)
 {
        BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-       BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
        return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv);
 }                                        
 
@@ -394,7 +711,6 @@ static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm,
                                            unsigned int nbytes, u8 *iv)
 {
        BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER);
-       BUG_ON(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB);
        return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv);
 }