[CRYPTO] scatterwalk: Restore custom sg chaining for now
[safe/jmp/linux-2.6] / crypto / gcm.c
index 5681c79..502da92 100644 (file)
 
 #include <crypto/algapi.h>
 #include <crypto/gf128mul.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
-#include "scatterwalk.h"
+#include "internal.h"
 
 struct gcm_instance_ctx {
        struct crypto_spawn ctr;
@@ -36,6 +37,7 @@ struct crypto_gcm_ghash_ctx {
 
 struct crypto_gcm_req_priv_ctx {
        u8 auth_tag[16];
+       u8 iauth_tag[16];
        u8 counter[16];
        struct crypto_gcm_ghash_ctx ghash;
 };
@@ -89,13 +91,16 @@ static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx,
        u8 *src;
        int n;
 
+       if (!len)
+               return;
+
        scatterwalk_start(&walk, sg);
 
        while (len) {
                n = scatterwalk_clamp(&walk, len);
 
                if (!n) {
-                       scatterwalk_start(&walk, sg_next(walk.sg));
+                       scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
                        n = scatterwalk_clamp(&walk, len);
                }
 
@@ -211,9 +216,10 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
 }
 
 static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
-                                 struct aead_request *req,
-                                 void (*done)(struct crypto_async_request *,
-                                              int))
+                                struct aead_request *req,
+                                unsigned int cryptlen,
+                                void (*done)(struct crypto_async_request *,
+                                             int))
 {
        struct crypto_aead *aead = crypto_aead_reqtfm(req);
        struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
@@ -228,7 +234,7 @@ static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
        ablkcipher_request_set_callback(ablk_req, aead_request_flags(req),
                                        done, req);
        ablkcipher_request_set_crypt(ablk_req, req->src, req->dst,
-                                    req->cryptlen, counter);
+                                    cryptlen, counter);
 
        err = crypto_gcm_encrypt_counter(aead, auth_tag, 0, req->iv);
        if (err)
@@ -239,18 +245,16 @@ static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
 
        crypto_gcm_ghash_init(ghash, flags, ctx->gf128);
 
-       if (req->assoclen) {
-               crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen);
-               crypto_gcm_ghash_flush(ghash);
-       }
+       crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen);
+       crypto_gcm_ghash_flush(ghash);
 
  out:
        return err;
 }
 
-static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
+static int crypto_gcm_hash(struct aead_request *req)
 {
-       struct aead_request *req = areq->data;
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
        struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req);
        u8 *auth_tag = pctx->auth_tag;
        struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
@@ -259,18 +263,28 @@ static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
        crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
                                   auth_tag);
 
+       scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
+                                crypto_aead_authsize(aead), 1);
+       return 0;
+}
+
+static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
+{
+       struct aead_request *req = areq->data;
+
+       if (!err)
+               err = crypto_gcm_hash(req);
+
        aead_request_complete(req, err);
 }
 
 static int crypto_gcm_encrypt(struct aead_request *req)
 {
        struct ablkcipher_request abreq;
-       struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req);
-       u8 *auth_tag = pctx->auth_tag;
-       struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
        int err = 0;
 
-       err = crypto_gcm_init_crypt(&abreq, req, crypto_gcm_encrypt_done);
+       err = crypto_gcm_init_crypt(&abreq, req, req->cryptlen,
+                                   crypto_gcm_encrypt_done);
        if (err)
                return err;
 
@@ -278,14 +292,9 @@ static int crypto_gcm_encrypt(struct aead_request *req)
                err = crypto_ablkcipher_encrypt(&abreq);
                if (err)
                        return err;
-
-               crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen);
        }
 
-       crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
-                                  auth_tag);
-
-       return err;
+       return crypto_gcm_hash(req);
 }
 
 static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err)
@@ -296,26 +305,30 @@ static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err)
 static int crypto_gcm_decrypt(struct aead_request *req)
 {
        struct ablkcipher_request abreq;
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
        struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req);
        u8 *auth_tag = pctx->auth_tag;
+       u8 *iauth_tag = pctx->iauth_tag;
        struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
-       u8 tag[16];
+       unsigned int cryptlen = req->cryptlen;
+       unsigned int authsize = crypto_aead_authsize(aead);
        int err;
 
-       if (!req->cryptlen)
+       if (cryptlen < authsize)
                return -EINVAL;
+       cryptlen -= authsize;
 
-       memcpy(tag, auth_tag, 16);
-       err = crypto_gcm_init_crypt(&abreq, req, crypto_gcm_decrypt_done);
+       err = crypto_gcm_init_crypt(&abreq, req, cryptlen,
+                                   crypto_gcm_decrypt_done);
        if (err)
                return err;
 
-       crypto_gcm_ghash_update_sg(ghash, req->src, req->cryptlen);
-       crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
-                                  auth_tag);
+       crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen);
+       crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag);
 
-       if (memcmp(tag, auth_tag, 16))
-               return -EINVAL;
+       scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
+       if (memcmp(iauth_tag, auth_tag, authsize))
+               return -EBADMSG;
 
        return crypto_ablkcipher_decrypt(&abreq);
 }