blob: c5fe95e49c6818eff78448be89435c89152d5788 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Jiri Bencf0706e82007-05-05 11:45:53 -07002/*
3 * Copyright 2003-2004, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
Xiang Gao4133da72017-10-10 22:31:49 -04005 * Copyright 2014-2015, Qualcomm Atheros, Inc.
Jiri Bencf0706e82007-05-05 11:45:53 -07006 *
Ard Biesheuvel7ec7c4a2013-10-10 09:55:20 +02007 * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
Jiri Bencf0706e82007-05-05 11:45:53 -07008 */
9
Ilpo Järvinen172589c2007-08-28 15:50:33 -070010#include <linux/kernel.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070011#include <linux/types.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070012#include <linux/err.h>
Xiang Gao4133da72017-10-10 22:31:49 -040013#include <linux/scatterlist.h>
Herbert Xud8fe0dd2015-04-22 15:06:32 +080014#include <crypto/aead.h>
Jiri Bencf0706e82007-05-05 11:45:53 -070015
Xiang Gao4133da72017-10-10 22:31:49 -040016#include "aead_api.h"
Jiri Bencf0706e82007-05-05 11:45:53 -070017
Xiang Gao4133da72017-10-10 22:31:49 -040018int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
19 u8 *data, size_t data_len, u8 *mic)
Jiri Bencf0706e82007-05-05 11:45:53 -070020{
Johannes Berg9e979642017-10-11 15:46:45 +020021 size_t mic_len = crypto_aead_authsize(tfm);
Herbert Xu957e0fe2015-05-27 16:03:50 +080022 struct scatterlist sg[3];
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010023 struct aead_request *aead_req;
24 int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
25 u8 *__aad;
Jiri Bencf0706e82007-05-05 11:45:53 -070026
Xiang Gao4133da72017-10-10 22:31:49 -040027 aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010028 if (!aead_req)
29 return -ENOMEM;
Jan-Simon Möller6e1ee5d2014-03-20 23:39:32 -070030
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010031 __aad = (u8 *)aead_req + reqsize;
Xiang Gao4133da72017-10-10 22:31:49 -040032 memcpy(__aad, aad, aad_len);
Harvey Harrison5fdae6b2008-07-02 16:30:53 -070033
Herbert Xu957e0fe2015-05-27 16:03:50 +080034 sg_init_table(sg, 3);
Xiang Gao4133da72017-10-10 22:31:49 -040035 sg_set_buf(&sg[0], __aad, aad_len);
Herbert Xu957e0fe2015-05-27 16:03:50 +080036 sg_set_buf(&sg[1], data, data_len);
37 sg_set_buf(&sg[2], mic, mic_len);
Jiri Bencf0706e82007-05-05 11:45:53 -070038
Jan-Simon Möller6e1ee5d2014-03-20 23:39:32 -070039 aead_request_set_tfm(aead_req, tfm);
Herbert Xu957e0fe2015-05-27 16:03:50 +080040 aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
41 aead_request_set_ad(aead_req, sg[0].length);
Jiri Bencf0706e82007-05-05 11:45:53 -070042
Jan-Simon Möller6e1ee5d2014-03-20 23:39:32 -070043 crypto_aead_encrypt(aead_req);
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010044 kzfree(aead_req);
45
46 return 0;
Jiri Bencf0706e82007-05-05 11:45:53 -070047}
48
Xiang Gao4133da72017-10-10 22:31:49 -040049int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
50 u8 *data, size_t data_len, u8 *mic)
Jiri Bencf0706e82007-05-05 11:45:53 -070051{
Johannes Berg9e979642017-10-11 15:46:45 +020052 size_t mic_len = crypto_aead_authsize(tfm);
Herbert Xu957e0fe2015-05-27 16:03:50 +080053 struct scatterlist sg[3];
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010054 struct aead_request *aead_req;
55 int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
56 u8 *__aad;
57 int err;
Jiri Bencf0706e82007-05-05 11:45:53 -070058
Ronald Wahl4f031fa2014-11-06 11:52:13 +010059 if (data_len == 0)
60 return -EINVAL;
61
Xiang Gao4133da72017-10-10 22:31:49 -040062 aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010063 if (!aead_req)
64 return -ENOMEM;
65
66 __aad = (u8 *)aead_req + reqsize;
Xiang Gao4133da72017-10-10 22:31:49 -040067 memcpy(__aad, aad, aad_len);
Jiri Bencf0706e82007-05-05 11:45:53 -070068
Herbert Xu957e0fe2015-05-27 16:03:50 +080069 sg_init_table(sg, 3);
Xiang Gao4133da72017-10-10 22:31:49 -040070 sg_set_buf(&sg[0], __aad, aad_len);
Herbert Xu957e0fe2015-05-27 16:03:50 +080071 sg_set_buf(&sg[1], data, data_len);
72 sg_set_buf(&sg[2], mic, mic_len);
Jiri Bencf0706e82007-05-05 11:45:53 -070073
Jan-Simon Möller6e1ee5d2014-03-20 23:39:32 -070074 aead_request_set_tfm(aead_req, tfm);
Herbert Xu957e0fe2015-05-27 16:03:50 +080075 aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
76 aead_request_set_ad(aead_req, sg[0].length);
Jiri Bencf0706e82007-05-05 11:45:53 -070077
Ard Biesheuvelf4a067f2016-10-17 15:05:33 +010078 err = crypto_aead_decrypt(aead_req);
79 kzfree(aead_req);
80
81 return err;
Jiri Bencf0706e82007-05-05 11:45:53 -070082}
83
Xiang Gao4133da72017-10-10 22:31:49 -040084struct crypto_aead *
85aead_key_setup_encrypt(const char *alg, const u8 key[],
86 size_t key_len, size_t mic_len)
Jiri Bencf0706e82007-05-05 11:45:53 -070087{
Ard Biesheuvel7ec7c4a2013-10-10 09:55:20 +020088 struct crypto_aead *tfm;
89 int err;
Jiri Bencf0706e82007-05-05 11:45:53 -070090
Xiang Gao4133da72017-10-10 22:31:49 -040091 tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC);
Ard Biesheuvel7ec7c4a2013-10-10 09:55:20 +020092 if (IS_ERR(tfm))
93 return tfm;
Jiri Bencf0706e82007-05-05 11:45:53 -070094
Jouni Malinen2b2ba0d2015-01-24 19:52:07 +020095 err = crypto_aead_setkey(tfm, key, key_len);
Dan Carpenter45fd6322015-03-23 17:08:14 +030096 if (err)
97 goto free_aead;
98 err = crypto_aead_setauthsize(tfm, mic_len);
99 if (err)
100 goto free_aead;
Jiri Bencf0706e82007-05-05 11:45:53 -0700101
Dan Carpenter45fd6322015-03-23 17:08:14 +0300102 return tfm;
103
104free_aead:
Ard Biesheuvel7ec7c4a2013-10-10 09:55:20 +0200105 crypto_free_aead(tfm);
106 return ERR_PTR(err);
Jiri Bencf0706e82007-05-05 11:45:53 -0700107}
108
Xiang Gao4133da72017-10-10 22:31:49 -0400109void aead_key_free(struct crypto_aead *tfm)
Jiri Bencf0706e82007-05-05 11:45:53 -0700110{
Ard Biesheuvel7ec7c4a2013-10-10 09:55:20 +0200111 crypto_free_aead(tfm);
Jiri Bencf0706e82007-05-05 11:45:53 -0700112}