1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2003-2004, Instant802 Networks, Inc. |
4 | * Copyright 2005-2006, Devicescape Software, Inc. |
5 | * Copyright 2014-2015, Qualcomm Atheros, Inc. |
6 | * |
7 | * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/types.h> |
12 | #include <linux/err.h> |
13 | #include <linux/scatterlist.h> |
14 | #include <crypto/aead.h> |
15 | |
16 | #include "aead_api.h" |
17 | |
18 | int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, |
19 | u8 *data, size_t data_len, u8 *mic) |
20 | { |
21 | size_t mic_len = crypto_aead_authsize(tfm); |
22 | struct scatterlist sg[3]; |
23 | struct aead_request *aead_req; |
24 | int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); |
25 | u8 *__aad; |
26 | int ret; |
27 | |
28 | aead_req = kzalloc(size: reqsize + aad_len, GFP_ATOMIC); |
29 | if (!aead_req) |
30 | return -ENOMEM; |
31 | |
32 | __aad = (u8 *)aead_req + reqsize; |
33 | memcpy(__aad, aad, aad_len); |
34 | |
35 | sg_init_table(sg, 3); |
36 | sg_set_buf(sg: &sg[0], buf: __aad, buflen: aad_len); |
37 | sg_set_buf(sg: &sg[1], buf: data, buflen: data_len); |
38 | sg_set_buf(sg: &sg[2], buf: mic, buflen: mic_len); |
39 | |
40 | aead_request_set_tfm(req: aead_req, tfm); |
41 | aead_request_set_crypt(req: aead_req, src: sg, dst: sg, cryptlen: data_len, iv: b_0); |
42 | aead_request_set_ad(req: aead_req, assoclen: sg[0].length); |
43 | |
44 | ret = crypto_aead_encrypt(req: aead_req); |
45 | kfree_sensitive(objp: aead_req); |
46 | |
47 | return ret; |
48 | } |
49 | |
50 | int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, |
51 | u8 *data, size_t data_len, u8 *mic) |
52 | { |
53 | size_t mic_len = crypto_aead_authsize(tfm); |
54 | struct scatterlist sg[3]; |
55 | struct aead_request *aead_req; |
56 | int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); |
57 | u8 *__aad; |
58 | int err; |
59 | |
60 | if (data_len == 0) |
61 | return -EINVAL; |
62 | |
63 | aead_req = kzalloc(size: reqsize + aad_len, GFP_ATOMIC); |
64 | if (!aead_req) |
65 | return -ENOMEM; |
66 | |
67 | __aad = (u8 *)aead_req + reqsize; |
68 | memcpy(__aad, aad, aad_len); |
69 | |
70 | sg_init_table(sg, 3); |
71 | sg_set_buf(sg: &sg[0], buf: __aad, buflen: aad_len); |
72 | sg_set_buf(sg: &sg[1], buf: data, buflen: data_len); |
73 | sg_set_buf(sg: &sg[2], buf: mic, buflen: mic_len); |
74 | |
75 | aead_request_set_tfm(req: aead_req, tfm); |
76 | aead_request_set_crypt(req: aead_req, src: sg, dst: sg, cryptlen: data_len + mic_len, iv: b_0); |
77 | aead_request_set_ad(req: aead_req, assoclen: sg[0].length); |
78 | |
79 | err = crypto_aead_decrypt(req: aead_req); |
80 | kfree_sensitive(objp: aead_req); |
81 | |
82 | return err; |
83 | } |
84 | |
85 | struct crypto_aead * |
86 | aead_key_setup_encrypt(const char *alg, const u8 key[], |
87 | size_t key_len, size_t mic_len) |
88 | { |
89 | struct crypto_aead *tfm; |
90 | int err; |
91 | |
92 | tfm = crypto_alloc_aead(alg_name: alg, type: 0, CRYPTO_ALG_ASYNC); |
93 | if (IS_ERR(ptr: tfm)) |
94 | return tfm; |
95 | |
96 | err = crypto_aead_setkey(tfm, key, keylen: key_len); |
97 | if (err) |
98 | goto free_aead; |
99 | err = crypto_aead_setauthsize(tfm, authsize: mic_len); |
100 | if (err) |
101 | goto free_aead; |
102 | |
103 | return tfm; |
104 | |
105 | free_aead: |
106 | crypto_free_aead(tfm); |
107 | return ERR_PTR(error: err); |
108 | } |
109 | |
110 | void aead_key_free(struct crypto_aead *tfm) |
111 | { |
112 | crypto_free_aead(tfm); |
113 | } |
114 | |