Skip to content

Commit

Permalink
[CRYPTO] gcm: Fix ICV handling
Browse files Browse the repository at this point in the history
The crypto_aead convention for ICVs is to include it directly in the
output.  If we decided to change this in future then we would make
the ICV (if the algorithm has an explicit one) available in the
request itself.

For now no algorithm needs this so this patch changes gcm to conform
to this convention.  It also adjusts the tcrypt aead tests to take
this into account.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Herbert Xu committed Jan 10, 2008
1 parent 8df213d commit 6160b28
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 129 deletions.
68 changes: 40 additions & 28 deletions crypto/gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,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;
};
Expand Down Expand Up @@ -89,6 +90,9 @@ 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) {
Expand Down Expand Up @@ -211,9 +215,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);
Expand All @@ -228,7 +233,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)
Expand All @@ -239,18 +244,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;
Expand All @@ -259,33 +262,38 @@ 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;

if (req->cryptlen) {
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)
Expand All @@ -296,25 +304,29 @@ 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))
scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
if (memcmp(iauth_tag, auth_tag, authsize))
return -EINVAL;

return crypto_ablkcipher_decrypt(&abreq);
Expand Down
44 changes: 16 additions & 28 deletions crypto/tcrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
struct scatterlist asg[8];
const char *e;
struct tcrypt_result result;
unsigned int authsize;

if (enc == ENCRYPT)
e = "encryption";
Expand Down Expand Up @@ -265,6 +266,8 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
return;
}

authsize = crypto_aead_authsize(tfm);

req = aead_request_alloc(tfm, GFP_KERNEL);
if (!req) {
printk(KERN_INFO "failed to allocate request for %s\n", algo);
Expand Down Expand Up @@ -296,7 +299,7 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
}

sg_init_one(&sg[0], aead_tv[i].input,
aead_tv[i].ilen);
aead_tv[i].ilen + (enc ? authsize : 0));

sg_init_one(&asg[0], aead_tv[i].assoc,
aead_tv[i].alen);
Expand All @@ -307,13 +310,9 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,

aead_request_set_assoc(req, asg, aead_tv[i].alen);

if (enc) {
ret = crypto_aead_encrypt(req);
} else {
memcpy(req->__ctx, aead_tv[i].tag,
aead_tv[i].tlen);
ret = crypto_aead_decrypt(req);
}
ret = enc ?
crypto_aead_encrypt(req) :
crypto_aead_decrypt(req);

switch (ret) {
case 0:
Expand All @@ -335,16 +334,10 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,

q = kmap(sg_page(&sg[0])) + sg[0].offset;
hexdump(q, aead_tv[i].rlen);
printk(KERN_INFO "auth tag: ");
hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen);

printk(KERN_INFO "enc/dec: %s\n",
memcmp(q, aead_tv[i].result,
aead_tv[i].rlen) ? "fail" : "pass");

printk(KERN_INFO "auth tag: %s\n",
memcmp(req->__ctx, aead_tv[i].tag,
aead_tv[i].tlen) ? "fail" : "pass");
}
}

Expand Down Expand Up @@ -381,6 +374,9 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
aead_tv[i].tap[k]);
}

if (enc)
sg[k - 1].length += authsize;

sg_init_table(asg, aead_tv[i].anp);
for (k = 0, temp = 0; k < aead_tv[i].anp; k++) {
memcpy(&axbuf[IDX[k]],
Expand All @@ -397,13 +393,9 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,

aead_request_set_assoc(req, asg, aead_tv[i].alen);

if (enc) {
ret = crypto_aead_encrypt(req);
} else {
memcpy(req->__ctx, aead_tv[i].tag,
aead_tv[i].tlen);
ret = crypto_aead_decrypt(req);
}
ret = enc ?
crypto_aead_encrypt(req) :
crypto_aead_decrypt(req);

switch (ret) {
case 0:
Expand All @@ -429,17 +421,13 @@ static void test_aead(char *algo, int enc, struct aead_testvec *template,
hexdump(q, aead_tv[i].tap[k]);
printk(KERN_INFO "%s\n",
memcmp(q, aead_tv[i].result + temp,
aead_tv[i].tap[k]) ?
aead_tv[i].tap[k] -
(k < aead_tv[i].np - 1 || enc ?
0 : authsize)) ?
"fail" : "pass");

temp += aead_tv[i].tap[k];
}
printk(KERN_INFO "auth tag: ");
hexdump((unsigned char *)req->__ctx, aead_tv[i].tlen);

printk(KERN_INFO "auth tag: %s\n",
memcmp(req->__ctx, aead_tv[i].tag,
aead_tv[i].tlen) ? "fail" : "pass");
}
}

Expand Down
Loading

0 comments on commit 6160b28

Please sign in to comment.