| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * GCM: Galois/Counter Mode. | 
|  | 3 | * | 
|  | 4 | * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or modify it | 
|  | 7 | * under the terms of the GNU General Public License version 2 as published | 
|  | 8 | * by the Free Software Foundation. | 
|  | 9 | */ | 
|  | 10 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 11 | #include <crypto/gf128mul.h> | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 12 | #include <crypto/internal/aead.h> | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 13 | #include <crypto/internal/skcipher.h> | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 14 | #include <crypto/internal/hash.h> | 
| Herbert Xu | 17db854 | 2015-05-21 15:11:11 +0800 | [diff] [blame] | 15 | #include <crypto/null.h> | 
| Herbert Xu | 42c271c | 2007-12-07 18:52:49 +0800 | [diff] [blame] | 16 | #include <crypto/scatterwalk.h> | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 17 | #include <crypto/hash.h> | 
|  | 18 | #include "internal.h" | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 19 | #include <linux/completion.h> | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 20 | #include <linux/err.h> | 
|  | 21 | #include <linux/init.h> | 
|  | 22 | #include <linux/kernel.h> | 
|  | 23 | #include <linux/module.h> | 
|  | 24 | #include <linux/slab.h> | 
|  | 25 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 26 | struct gcm_instance_ctx { | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 27 | struct crypto_skcipher_spawn ctr; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 28 | struct crypto_ahash_spawn ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 29 | }; | 
|  | 30 |  | 
|  | 31 | struct crypto_gcm_ctx { | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 32 | struct crypto_skcipher *ctr; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 33 | struct crypto_ahash *ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 34 | }; | 
|  | 35 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 36 | struct crypto_rfc4106_ctx { | 
|  | 37 | struct crypto_aead *child; | 
|  | 38 | u8 nonce[4]; | 
|  | 39 | }; | 
|  | 40 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 41 | struct crypto_rfc4106_req_ctx { | 
|  | 42 | struct scatterlist src[3]; | 
|  | 43 | struct scatterlist dst[3]; | 
|  | 44 | struct aead_request subreq; | 
|  | 45 | }; | 
|  | 46 |  | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 47 | struct crypto_rfc4543_instance_ctx { | 
|  | 48 | struct crypto_aead_spawn aead; | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 49 | }; | 
|  | 50 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 51 | struct crypto_rfc4543_ctx { | 
|  | 52 | struct crypto_aead *child; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 53 | struct crypto_skcipher *null; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 54 | u8 nonce[4]; | 
|  | 55 | }; | 
|  | 56 |  | 
|  | 57 | struct crypto_rfc4543_req_ctx { | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 58 | struct aead_request subreq; | 
|  | 59 | }; | 
|  | 60 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 61 | struct crypto_gcm_ghash_ctx { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 62 | unsigned int cryptlen; | 
|  | 63 | struct scatterlist *src; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 64 | int (*complete)(struct aead_request *req, u32 flags); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 65 | }; | 
|  | 66 |  | 
|  | 67 | struct crypto_gcm_req_priv_ctx { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 68 | u8 iv[16]; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 69 | u8 auth_tag[16]; | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 70 | u8 iauth_tag[16]; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 71 | struct scatterlist src[3]; | 
|  | 72 | struct scatterlist dst[3]; | 
|  | 73 | struct scatterlist sg; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 74 | struct crypto_gcm_ghash_ctx ghash_ctx; | 
|  | 75 | union { | 
|  | 76 | struct ahash_request ahreq; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 77 | struct skcipher_request skreq; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 78 | } u; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 79 | }; | 
|  | 80 |  | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 81 | struct crypto_gcm_setkey_result { | 
|  | 82 | int err; | 
|  | 83 | struct completion completion; | 
|  | 84 | }; | 
|  | 85 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 86 | static struct { | 
|  | 87 | u8 buf[16]; | 
|  | 88 | struct scatterlist sg; | 
|  | 89 | } *gcm_zeroes; | 
|  | 90 |  | 
|  | 91 | static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 92 |  | 
| Herbert Xu | 2589469 | 2007-12-12 19:16:38 +0800 | [diff] [blame] | 93 | static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx( | 
|  | 94 | struct aead_request *req) | 
|  | 95 | { | 
|  | 96 | unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req)); | 
|  | 97 |  | 
|  | 98 | return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1); | 
|  | 99 | } | 
|  | 100 |  | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 101 | static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 102 | { | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 103 | struct crypto_gcm_setkey_result *result = req->data; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 104 |  | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 105 | if (err == -EINPROGRESS) | 
|  | 106 | return; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 107 |  | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 108 | result->err = err; | 
|  | 109 | complete(&result->completion); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 110 | } | 
|  | 111 |  | 
|  | 112 | static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, | 
|  | 113 | unsigned int keylen) | 
|  | 114 | { | 
|  | 115 | struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 116 | struct crypto_ahash *ghash = ctx->ghash; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 117 | struct crypto_skcipher *ctr = ctx->ctr; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 118 | struct { | 
|  | 119 | be128 hash; | 
| Ondrej Mosnáček | 50d2e6d | 2016-09-23 10:47:32 +0200 | [diff] [blame] | 120 | u8 iv[16]; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 121 |  | 
|  | 122 | struct crypto_gcm_setkey_result result; | 
|  | 123 |  | 
|  | 124 | struct scatterlist sg[1]; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 125 | struct skcipher_request req; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 126 | } *data; | 
|  | 127 | int err; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 128 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 129 | crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK); | 
|  | 130 | crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) & | 
|  | 131 | CRYPTO_TFM_REQ_MASK); | 
|  | 132 | err = crypto_skcipher_setkey(ctr, key, keylen); | 
|  | 133 | crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) & | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 134 | CRYPTO_TFM_RES_MASK); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 135 | if (err) | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 136 | return err; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 137 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 138 | data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr), | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 139 | GFP_KERNEL); | 
|  | 140 | if (!data) | 
|  | 141 | return -ENOMEM; | 
|  | 142 |  | 
|  | 143 | init_completion(&data->result.completion); | 
|  | 144 | sg_init_one(data->sg, &data->hash, sizeof(data->hash)); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 145 | skcipher_request_set_tfm(&data->req, ctr); | 
|  | 146 | skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP | | 
|  | 147 | CRYPTO_TFM_REQ_MAY_BACKLOG, | 
|  | 148 | crypto_gcm_setkey_done, | 
|  | 149 | &data->result); | 
|  | 150 | skcipher_request_set_crypt(&data->req, data->sg, data->sg, | 
|  | 151 | sizeof(data->hash), data->iv); | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 152 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 153 | err = crypto_skcipher_encrypt(&data->req); | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 154 | if (err == -EINPROGRESS || err == -EBUSY) { | 
| Gilad Ben-Yossef | f3ad587 | 2017-05-18 16:29:25 +0300 | [diff] [blame] | 155 | wait_for_completion(&data->result.completion); | 
|  | 156 | err = data->result.err; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 157 | } | 
|  | 158 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 159 | if (err) | 
|  | 160 | goto out; | 
|  | 161 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 162 | crypto_ahash_clear_flags(ghash, CRYPTO_TFM_REQ_MASK); | 
|  | 163 | crypto_ahash_set_flags(ghash, crypto_aead_get_flags(aead) & | 
|  | 164 | CRYPTO_TFM_REQ_MASK); | 
|  | 165 | err = crypto_ahash_setkey(ghash, (u8 *)&data->hash, sizeof(be128)); | 
|  | 166 | crypto_aead_set_flags(aead, crypto_ahash_get_flags(ghash) & | 
|  | 167 | CRYPTO_TFM_RES_MASK); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 168 |  | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 169 | out: | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 170 | kzfree(data); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 171 | return err; | 
|  | 172 | } | 
|  | 173 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 174 | static int crypto_gcm_setauthsize(struct crypto_aead *tfm, | 
|  | 175 | unsigned int authsize) | 
|  | 176 | { | 
|  | 177 | switch (authsize) { | 
|  | 178 | case 4: | 
|  | 179 | case 8: | 
|  | 180 | case 12: | 
|  | 181 | case 13: | 
|  | 182 | case 14: | 
|  | 183 | case 15: | 
|  | 184 | case 16: | 
|  | 185 | break; | 
|  | 186 | default: | 
|  | 187 | return -EINVAL; | 
|  | 188 | } | 
|  | 189 |  | 
|  | 190 | return 0; | 
|  | 191 | } | 
|  | 192 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 193 | static void crypto_gcm_init_common(struct aead_request *req) | 
|  | 194 | { | 
|  | 195 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
|  | 196 | __be32 counter = cpu_to_be32(1); | 
|  | 197 | struct scatterlist *sg; | 
|  | 198 |  | 
|  | 199 | memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag)); | 
|  | 200 | memcpy(pctx->iv, req->iv, 12); | 
|  | 201 | memcpy(pctx->iv + 12, &counter, 4); | 
|  | 202 |  | 
|  | 203 | sg_init_table(pctx->src, 3); | 
|  | 204 | sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag)); | 
|  | 205 | sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen); | 
|  | 206 | if (sg != pctx->src + 1) | 
| Dan Williams | c56f6d1 | 2015-08-07 18:15:13 +0200 | [diff] [blame] | 207 | sg_chain(pctx->src, 2, sg); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 208 |  | 
|  | 209 | if (req->src != req->dst) { | 
|  | 210 | sg_init_table(pctx->dst, 3); | 
|  | 211 | sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag)); | 
|  | 212 | sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen); | 
|  | 213 | if (sg != pctx->dst + 1) | 
| Dan Williams | c56f6d1 | 2015-08-07 18:15:13 +0200 | [diff] [blame] | 214 | sg_chain(pctx->dst, 2, sg); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 215 | } | 
|  | 216 | } | 
|  | 217 |  | 
|  | 218 | static void crypto_gcm_init_crypt(struct aead_request *req, | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 219 | unsigned int cryptlen) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 220 | { | 
|  | 221 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
|  | 222 | struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); | 
| Herbert Xu | 2589469 | 2007-12-12 19:16:38 +0800 | [diff] [blame] | 223 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 224 | struct skcipher_request *skreq = &pctx->u.skreq; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 225 | struct scatterlist *dst; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 226 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 227 | dst = req->src == req->dst ? pctx->src : pctx->dst; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 228 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 229 | skcipher_request_set_tfm(skreq, ctx->ctr); | 
|  | 230 | skcipher_request_set_crypt(skreq, pctx->src, dst, | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 231 | cryptlen + sizeof(pctx->auth_tag), | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 232 | pctx->iv); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 235 | static inline unsigned int gcm_remain(unsigned int len) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 236 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 237 | len &= 0xfU; | 
|  | 238 | return len ? 16 - len : 0; | 
|  | 239 | } | 
|  | 240 |  | 
|  | 241 | static void gcm_hash_len_done(struct crypto_async_request *areq, int err); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 242 |  | 
|  | 243 | static int gcm_hash_update(struct aead_request *req, | 
| Mark Rustad | 3e3dc25 | 2014-07-25 02:53:38 -0700 | [diff] [blame] | 244 | crypto_completion_t compl, | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 245 | struct scatterlist *src, | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 246 | unsigned int len, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 247 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 248 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 249 | struct ahash_request *ahreq = &pctx->u.ahreq; | 
|  | 250 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 251 | ahash_request_set_callback(ahreq, flags, compl, req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 252 | ahash_request_set_crypt(ahreq, src, NULL, len); | 
|  | 253 |  | 
|  | 254 | return crypto_ahash_update(ahreq); | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | static int gcm_hash_remain(struct aead_request *req, | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 258 | unsigned int remain, | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 259 | crypto_completion_t compl, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 260 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 261 | return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 262 | } | 
|  | 263 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 264 | static int gcm_hash_len(struct aead_request *req, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 265 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 266 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 267 | struct ahash_request *ahreq = &pctx->u.ahreq; | 
|  | 268 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
|  | 269 | u128 lengths; | 
|  | 270 |  | 
|  | 271 | lengths.a = cpu_to_be64(req->assoclen * 8); | 
|  | 272 | lengths.b = cpu_to_be64(gctx->cryptlen * 8); | 
|  | 273 | memcpy(pctx->iauth_tag, &lengths, 16); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 274 | sg_init_one(&pctx->sg, pctx->iauth_tag, 16); | 
|  | 275 | ahash_request_set_callback(ahreq, flags, gcm_hash_len_done, req); | 
|  | 276 | ahash_request_set_crypt(ahreq, &pctx->sg, | 
|  | 277 | pctx->iauth_tag, sizeof(lengths)); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 278 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 279 | return crypto_ahash_finup(ahreq); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 280 | } | 
|  | 281 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 282 | static int gcm_hash_len_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 283 | { | 
| Herbert Xu | 2589469 | 2007-12-12 19:16:38 +0800 | [diff] [blame] | 284 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 285 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 286 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 287 | return gctx->complete(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 288 | } | 
|  | 289 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 290 | static void gcm_hash_len_done(struct crypto_async_request *areq, int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 291 | { | 
|  | 292 | struct aead_request *req = areq->data; | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 293 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 294 | if (err) | 
|  | 295 | goto out; | 
|  | 296 |  | 
|  | 297 | err = gcm_hash_len_continue(req, 0); | 
|  | 298 | if (err == -EINPROGRESS) | 
|  | 299 | return; | 
|  | 300 |  | 
|  | 301 | out: | 
|  | 302 | aead_request_complete(req, err); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 303 | } | 
|  | 304 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 305 | static int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 306 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 307 | return gcm_hash_len(req, flags) ?: | 
|  | 308 | gcm_hash_len_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 309 | } | 
|  | 310 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 311 | static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq, | 
|  | 312 | int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 313 | { | 
|  | 314 | struct aead_request *req = areq->data; | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 315 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 316 | if (err) | 
|  | 317 | goto out; | 
|  | 318 |  | 
|  | 319 | err = gcm_hash_crypt_remain_continue(req, 0); | 
|  | 320 | if (err == -EINPROGRESS) | 
|  | 321 | return; | 
|  | 322 |  | 
|  | 323 | out: | 
|  | 324 | aead_request_complete(req, err); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 325 | } | 
|  | 326 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 327 | static int gcm_hash_crypt_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 328 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 329 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
|  | 330 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
|  | 331 | unsigned int remain; | 
|  | 332 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 333 | remain = gcm_remain(gctx->cryptlen); | 
|  | 334 | if (remain) | 
|  | 335 | return gcm_hash_remain(req, remain, | 
|  | 336 | gcm_hash_crypt_remain_done, flags) ?: | 
|  | 337 | gcm_hash_crypt_remain_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 338 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 339 | return gcm_hash_crypt_remain_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 340 | } | 
|  | 341 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 342 | static void gcm_hash_crypt_done(struct crypto_async_request *areq, int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 343 | { | 
|  | 344 | struct aead_request *req = areq->data; | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 345 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 346 | if (err) | 
|  | 347 | goto out; | 
|  | 348 |  | 
|  | 349 | err = gcm_hash_crypt_continue(req, 0); | 
|  | 350 | if (err == -EINPROGRESS) | 
|  | 351 | return; | 
|  | 352 |  | 
|  | 353 | out: | 
|  | 354 | aead_request_complete(req, err); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 355 | } | 
|  | 356 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 357 | static int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 358 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 359 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
|  | 360 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 361 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 362 | if (gctx->cryptlen) | 
|  | 363 | return gcm_hash_update(req, gcm_hash_crypt_done, | 
|  | 364 | gctx->src, gctx->cryptlen, flags) ?: | 
|  | 365 | gcm_hash_crypt_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 366 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 367 | return gcm_hash_crypt_remain_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 368 | } | 
|  | 369 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 370 | static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq, | 
|  | 371 | int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 372 | { | 
|  | 373 | struct aead_request *req = areq->data; | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 374 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 375 | if (err) | 
|  | 376 | goto out; | 
|  | 377 |  | 
|  | 378 | err = gcm_hash_assoc_remain_continue(req, 0); | 
|  | 379 | if (err == -EINPROGRESS) | 
|  | 380 | return; | 
|  | 381 |  | 
|  | 382 | out: | 
|  | 383 | aead_request_complete(req, err); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 384 | } | 
|  | 385 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 386 | static int gcm_hash_assoc_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 387 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 388 | unsigned int remain; | 
|  | 389 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 390 | remain = gcm_remain(req->assoclen); | 
|  | 391 | if (remain) | 
|  | 392 | return gcm_hash_remain(req, remain, | 
|  | 393 | gcm_hash_assoc_remain_done, flags) ?: | 
|  | 394 | gcm_hash_assoc_remain_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 395 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 396 | return gcm_hash_assoc_remain_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 397 | } | 
|  | 398 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 399 | static void gcm_hash_assoc_done(struct crypto_async_request *areq, int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 400 | { | 
|  | 401 | struct aead_request *req = areq->data; | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 402 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 403 | if (err) | 
|  | 404 | goto out; | 
|  | 405 |  | 
|  | 406 | err = gcm_hash_assoc_continue(req, 0); | 
|  | 407 | if (err == -EINPROGRESS) | 
|  | 408 | return; | 
|  | 409 |  | 
|  | 410 | out: | 
|  | 411 | aead_request_complete(req, err); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 412 | } | 
|  | 413 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 414 | static int gcm_hash_init_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 415 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 416 | if (req->assoclen) | 
|  | 417 | return gcm_hash_update(req, gcm_hash_assoc_done, | 
|  | 418 | req->src, req->assoclen, flags) ?: | 
|  | 419 | gcm_hash_assoc_continue(req, flags); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 420 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 421 | return gcm_hash_assoc_remain_continue(req, flags); | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 422 | } | 
|  | 423 |  | 
|  | 424 | static void gcm_hash_init_done(struct crypto_async_request *areq, int err) | 
|  | 425 | { | 
|  | 426 | struct aead_request *req = areq->data; | 
|  | 427 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 428 | if (err) | 
|  | 429 | goto out; | 
|  | 430 |  | 
|  | 431 | err = gcm_hash_init_continue(req, 0); | 
|  | 432 | if (err == -EINPROGRESS) | 
|  | 433 | return; | 
|  | 434 |  | 
|  | 435 | out: | 
|  | 436 | aead_request_complete(req, err); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 437 | } | 
|  | 438 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 439 | static int gcm_hash(struct aead_request *req, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 440 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 441 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 442 | struct ahash_request *ahreq = &pctx->u.ahreq; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 443 | struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 444 |  | 
|  | 445 | ahash_request_set_tfm(ahreq, ctx->ghash); | 
|  | 446 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 447 | ahash_request_set_callback(ahreq, flags, gcm_hash_init_done, req); | 
|  | 448 | return crypto_ahash_init(ahreq) ?: | 
|  | 449 | gcm_hash_init_continue(req, flags); | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 450 | } | 
|  | 451 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 452 | static int gcm_enc_copy_hash(struct aead_request *req, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 453 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 454 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 455 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
|  | 456 | u8 *auth_tag = pctx->auth_tag; | 
|  | 457 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 458 | crypto_xor(auth_tag, pctx->iauth_tag, 16); | 
|  | 459 | scatterwalk_map_and_copy(auth_tag, req->dst, | 
|  | 460 | req->assoclen + req->cryptlen, | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 461 | crypto_aead_authsize(aead), 1); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 462 | return 0; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 463 | } | 
|  | 464 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 465 | static int gcm_encrypt_continue(struct aead_request *req, u32 flags) | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 466 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 467 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 468 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 469 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 470 | gctx->src = sg_next(req->src == req->dst ? pctx->src : pctx->dst); | 
|  | 471 | gctx->cryptlen = req->cryptlen; | 
|  | 472 | gctx->complete = gcm_enc_copy_hash; | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 473 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 474 | return gcm_hash(req, flags); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 475 | } | 
|  | 476 |  | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 477 | static void gcm_encrypt_done(struct crypto_async_request *areq, int err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 478 | { | 
|  | 479 | struct aead_request *req = areq->data; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 480 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 481 | if (err) | 
|  | 482 | goto out; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 483 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 484 | err = gcm_encrypt_continue(req, 0); | 
|  | 485 | if (err == -EINPROGRESS) | 
|  | 486 | return; | 
|  | 487 |  | 
|  | 488 | out: | 
| Huang Ying | 62c5593 | 2009-11-16 21:52:22 +0800 | [diff] [blame] | 489 | aead_request_complete(req, err); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 490 | } | 
|  | 491 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 492 | static int crypto_gcm_encrypt(struct aead_request *req) | 
|  | 493 | { | 
| Herbert Xu | 2589469 | 2007-12-12 19:16:38 +0800 | [diff] [blame] | 494 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 495 | struct skcipher_request *skreq = &pctx->u.skreq; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 496 | u32 flags = aead_request_flags(req); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 497 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 498 | crypto_gcm_init_common(req); | 
|  | 499 | crypto_gcm_init_crypt(req, req->cryptlen); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 500 | skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 501 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 502 | return crypto_skcipher_encrypt(skreq) ?: | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 503 | gcm_encrypt_continue(req, flags); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 504 | } | 
|  | 505 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 506 | static int crypto_gcm_verify(struct aead_request *req) | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 507 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 508 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 509 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 510 | u8 *auth_tag = pctx->auth_tag; | 
|  | 511 | u8 *iauth_tag = pctx->iauth_tag; | 
|  | 512 | unsigned int authsize = crypto_aead_authsize(aead); | 
|  | 513 | unsigned int cryptlen = req->cryptlen - authsize; | 
|  | 514 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 515 | crypto_xor(auth_tag, iauth_tag, 16); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 516 | scatterwalk_map_and_copy(iauth_tag, req->src, | 
|  | 517 | req->assoclen + cryptlen, authsize, 0); | 
| James Yonan | 6bf37e5 | 2013-09-26 02:20:39 -0600 | [diff] [blame] | 518 | return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0; | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 519 | } | 
|  | 520 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 521 | static void gcm_decrypt_done(struct crypto_async_request *areq, int err) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 522 | { | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 523 | struct aead_request *req = areq->data; | 
|  | 524 |  | 
|  | 525 | if (!err) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 526 | err = crypto_gcm_verify(req); | 
| Herbert Xu | 84c9115 | 2007-12-17 21:42:08 +0800 | [diff] [blame] | 527 |  | 
|  | 528 | aead_request_complete(req, err); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 529 | } | 
|  | 530 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 531 | static int gcm_dec_hash_continue(struct aead_request *req, u32 flags) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 532 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 533 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 534 | struct skcipher_request *skreq = &pctx->u.skreq; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 535 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
|  | 536 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 537 | crypto_gcm_init_crypt(req, gctx->cryptlen); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 538 | skcipher_request_set_callback(skreq, flags, gcm_decrypt_done, req); | 
|  | 539 | return crypto_skcipher_decrypt(skreq) ?: crypto_gcm_verify(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 540 | } | 
|  | 541 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 542 | static int crypto_gcm_decrypt(struct aead_request *req) | 
|  | 543 | { | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 544 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
| Herbert Xu | 2589469 | 2007-12-12 19:16:38 +0800 | [diff] [blame] | 545 | struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 546 | struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 547 | unsigned int authsize = crypto_aead_authsize(aead); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 548 | unsigned int cryptlen = req->cryptlen; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 549 | u32 flags = aead_request_flags(req); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 550 |  | 
| Herbert Xu | 6160b28 | 2007-12-04 19:17:50 +1100 | [diff] [blame] | 551 | cryptlen -= authsize; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 552 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 553 | crypto_gcm_init_common(req); | 
|  | 554 |  | 
|  | 555 | gctx->src = sg_next(pctx->src); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 556 | gctx->cryptlen = cryptlen; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 557 | gctx->complete = gcm_dec_hash_continue; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 558 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 559 | return gcm_hash(req, flags); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 560 | } | 
|  | 561 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 562 | static int crypto_gcm_init_tfm(struct crypto_aead *tfm) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 563 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 564 | struct aead_instance *inst = aead_alg_instance(tfm); | 
|  | 565 | struct gcm_instance_ctx *ictx = aead_instance_ctx(inst); | 
|  | 566 | struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 567 | struct crypto_skcipher *ctr; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 568 | struct crypto_ahash *ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 569 | unsigned long align; | 
|  | 570 | int err; | 
|  | 571 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 572 | ghash = crypto_spawn_ahash(&ictx->ghash); | 
|  | 573 | if (IS_ERR(ghash)) | 
|  | 574 | return PTR_ERR(ghash); | 
|  | 575 |  | 
| Eric Biggers | 60425a8 | 2016-10-28 09:52:19 -0700 | [diff] [blame] | 576 | ctr = crypto_spawn_skcipher(&ictx->ctr); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 577 | err = PTR_ERR(ctr); | 
|  | 578 | if (IS_ERR(ctr)) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 579 | goto err_free_hash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 580 |  | 
|  | 581 | ctx->ctr = ctr; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 582 | ctx->ghash = ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 583 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 584 | align = crypto_aead_alignmask(tfm); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 585 | align &= ~(crypto_tfm_ctx_alignment() - 1); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 586 | crypto_aead_set_reqsize(tfm, | 
| Herbert Xu | 5d72336 | 2015-05-11 17:47:59 +0800 | [diff] [blame] | 587 | align + offsetof(struct crypto_gcm_req_priv_ctx, u) + | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 588 | max(sizeof(struct skcipher_request) + | 
|  | 589 | crypto_skcipher_reqsize(ctr), | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 590 | sizeof(struct ahash_request) + | 
| Herbert Xu | 5d72336 | 2015-05-11 17:47:59 +0800 | [diff] [blame] | 591 | crypto_ahash_reqsize(ghash))); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 592 |  | 
|  | 593 | return 0; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 594 |  | 
|  | 595 | err_free_hash: | 
|  | 596 | crypto_free_ahash(ghash); | 
|  | 597 | return err; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 598 | } | 
|  | 599 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 600 | static void crypto_gcm_exit_tfm(struct crypto_aead *tfm) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 601 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 602 | struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 603 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 604 | crypto_free_ahash(ctx->ghash); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 605 | crypto_free_skcipher(ctx->ctr); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 606 | } | 
|  | 607 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 608 | static void crypto_gcm_free(struct aead_instance *inst) | 
|  | 609 | { | 
|  | 610 | struct gcm_instance_ctx *ctx = aead_instance_ctx(inst); | 
|  | 611 |  | 
|  | 612 | crypto_drop_skcipher(&ctx->ctr); | 
|  | 613 | crypto_drop_ahash(&ctx->ghash); | 
|  | 614 | kfree(inst); | 
|  | 615 | } | 
|  | 616 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 617 | static int crypto_gcm_create_common(struct crypto_template *tmpl, | 
|  | 618 | struct rtattr **tb, | 
|  | 619 | const char *full_name, | 
|  | 620 | const char *ctr_name, | 
|  | 621 | const char *ghash_name) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 622 | { | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 623 | struct crypto_attr_type *algt; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 624 | struct aead_instance *inst; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 625 | struct skcipher_alg *ctr; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 626 | struct crypto_alg *ghash_alg; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 627 | struct hash_alg_common *ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 628 | struct gcm_instance_ctx *ctx; | 
|  | 629 | int err; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 630 |  | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 631 | algt = crypto_get_attr_type(tb); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 632 | if (IS_ERR(algt)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 633 | return PTR_ERR(algt); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 634 |  | 
| Herbert Xu | 5e4b8c1 | 2015-08-13 17:29:06 +0800 | [diff] [blame] | 635 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 636 | return -EINVAL; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 637 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 638 | ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type, | 
|  | 639 | CRYPTO_ALG_TYPE_HASH, | 
| Herbert Xu | b30bdfa | 2016-06-15 22:27:05 +0800 | [diff] [blame] | 640 | CRYPTO_ALG_TYPE_AHASH_MASK | | 
|  | 641 | crypto_requires_sync(algt->type, | 
|  | 642 | algt->mask)); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 643 | if (IS_ERR(ghash_alg)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 644 | return PTR_ERR(ghash_alg); | 
|  | 645 |  | 
|  | 646 | ghash = __crypto_hash_alg_common(ghash_alg); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 647 |  | 
|  | 648 | err = -ENOMEM; | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 649 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); | 
|  | 650 | if (!inst) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 651 | goto out_put_ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 652 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 653 | ctx = aead_instance_ctx(inst); | 
|  | 654 | err = crypto_init_ahash_spawn(&ctx->ghash, ghash, | 
|  | 655 | aead_crypto_instance(inst)); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 656 | if (err) | 
|  | 657 | goto err_free_inst; | 
|  | 658 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 659 | err = -EINVAL; | 
|  | 660 | if (ghash->digestsize != 16) | 
|  | 661 | goto err_drop_ghash; | 
|  | 662 |  | 
|  | 663 | crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst)); | 
| Eric Biggers | a35528e | 2016-10-28 09:51:13 -0700 | [diff] [blame] | 664 | err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0, | 
|  | 665 | crypto_requires_sync(algt->type, | 
|  | 666 | algt->mask)); | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 667 | if (err) | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 668 | goto err_drop_ghash; | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 669 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 670 | ctr = crypto_spawn_skcipher_alg(&ctx->ctr); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 671 |  | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 672 | /* We only support 16-byte blocks. */ | 
| Wei Yongjun | 9b40f79 | 2016-10-17 15:10:06 +0000 | [diff] [blame] | 673 | err = -EINVAL; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 674 | if (crypto_skcipher_alg_ivsize(ctr) != 16) | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 675 | goto out_put_ctr; | 
|  | 676 |  | 
|  | 677 | /* Not a stream cipher? */ | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 678 | if (ctr->base.cra_blocksize != 1) | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 679 | goto out_put_ctr; | 
|  | 680 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 681 | err = -ENAMETOOLONG; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 682 | if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 683 | "gcm_base(%s,%s)", ctr->base.cra_driver_name, | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 684 | ghash_alg->cra_driver_name) >= | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 685 | CRYPTO_MAX_ALG_NAME) | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 686 | goto out_put_ctr; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 687 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 688 | memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 689 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 690 | inst->alg.base.cra_flags = (ghash->base.cra_flags | | 
|  | 691 | ctr->base.cra_flags) & CRYPTO_ALG_ASYNC; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 692 | inst->alg.base.cra_priority = (ghash->base.cra_priority + | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 693 | ctr->base.cra_priority) / 2; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 694 | inst->alg.base.cra_blocksize = 1; | 
|  | 695 | inst->alg.base.cra_alignmask = ghash->base.cra_alignmask | | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 696 | ctr->base.cra_alignmask; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 697 | inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx); | 
|  | 698 | inst->alg.ivsize = 12; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 699 | inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 700 | inst->alg.maxauthsize = 16; | 
|  | 701 | inst->alg.init = crypto_gcm_init_tfm; | 
|  | 702 | inst->alg.exit = crypto_gcm_exit_tfm; | 
|  | 703 | inst->alg.setkey = crypto_gcm_setkey; | 
|  | 704 | inst->alg.setauthsize = crypto_gcm_setauthsize; | 
|  | 705 | inst->alg.encrypt = crypto_gcm_encrypt; | 
|  | 706 | inst->alg.decrypt = crypto_gcm_decrypt; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 707 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 708 | inst->free = crypto_gcm_free; | 
|  | 709 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 710 | err = aead_register_instance(tmpl, inst); | 
|  | 711 | if (err) | 
|  | 712 | goto out_put_ctr; | 
|  | 713 |  | 
|  | 714 | out_put_ghash: | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 715 | crypto_mod_put(ghash_alg); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 716 | return err; | 
| Herbert Xu | 1472e5e | 2007-12-07 19:26:11 +0800 | [diff] [blame] | 717 |  | 
|  | 718 | out_put_ctr: | 
|  | 719 | crypto_drop_skcipher(&ctx->ctr); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 720 | err_drop_ghash: | 
|  | 721 | crypto_drop_ahash(&ctx->ghash); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 722 | err_free_inst: | 
|  | 723 | kfree(inst); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 724 | goto out_put_ghash; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 725 | } | 
|  | 726 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 727 | static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb) | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 728 | { | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 729 | const char *cipher_name; | 
|  | 730 | char ctr_name[CRYPTO_MAX_ALG_NAME]; | 
|  | 731 | char full_name[CRYPTO_MAX_ALG_NAME]; | 
|  | 732 |  | 
|  | 733 | cipher_name = crypto_attr_alg_name(tb[1]); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 734 | if (IS_ERR(cipher_name)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 735 | return PTR_ERR(cipher_name); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 736 |  | 
|  | 737 | if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >= | 
|  | 738 | CRYPTO_MAX_ALG_NAME) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 739 | return -ENAMETOOLONG; | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 740 |  | 
|  | 741 | if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >= | 
|  | 742 | CRYPTO_MAX_ALG_NAME) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 743 | return -ENAMETOOLONG; | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 744 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 745 | return crypto_gcm_create_common(tmpl, tb, full_name, | 
|  | 746 | ctr_name, "ghash"); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 747 | } | 
|  | 748 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 749 | static struct crypto_template crypto_gcm_tmpl = { | 
|  | 750 | .name = "gcm", | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 751 | .create = crypto_gcm_create, | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 752 | .module = THIS_MODULE, | 
|  | 753 | }; | 
|  | 754 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 755 | static int crypto_gcm_base_create(struct crypto_template *tmpl, | 
|  | 756 | struct rtattr **tb) | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 757 | { | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 758 | const char *ctr_name; | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 759 | const char *ghash_name; | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 760 | char full_name[CRYPTO_MAX_ALG_NAME]; | 
|  | 761 |  | 
|  | 762 | ctr_name = crypto_attr_alg_name(tb[1]); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 763 | if (IS_ERR(ctr_name)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 764 | return PTR_ERR(ctr_name); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 765 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 766 | ghash_name = crypto_attr_alg_name(tb[2]); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 767 | if (IS_ERR(ghash_name)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 768 | return PTR_ERR(ghash_name); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 769 |  | 
|  | 770 | if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)", | 
|  | 771 | ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 772 | return -ENAMETOOLONG; | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 773 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 774 | return crypto_gcm_create_common(tmpl, tb, full_name, | 
|  | 775 | ctr_name, ghash_name); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 776 | } | 
|  | 777 |  | 
|  | 778 | static struct crypto_template crypto_gcm_base_tmpl = { | 
|  | 779 | .name = "gcm_base", | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 780 | .create = crypto_gcm_base_create, | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 781 | .module = THIS_MODULE, | 
|  | 782 | }; | 
|  | 783 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 784 | static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key, | 
|  | 785 | unsigned int keylen) | 
|  | 786 | { | 
|  | 787 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); | 
|  | 788 | struct crypto_aead *child = ctx->child; | 
|  | 789 | int err; | 
|  | 790 |  | 
|  | 791 | if (keylen < 4) | 
|  | 792 | return -EINVAL; | 
|  | 793 |  | 
|  | 794 | keylen -= 4; | 
|  | 795 | memcpy(ctx->nonce, key + keylen, 4); | 
|  | 796 |  | 
|  | 797 | crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); | 
|  | 798 | crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & | 
|  | 799 | CRYPTO_TFM_REQ_MASK); | 
|  | 800 | err = crypto_aead_setkey(child, key, keylen); | 
|  | 801 | crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & | 
|  | 802 | CRYPTO_TFM_RES_MASK); | 
|  | 803 |  | 
|  | 804 | return err; | 
|  | 805 | } | 
|  | 806 |  | 
|  | 807 | static int crypto_rfc4106_setauthsize(struct crypto_aead *parent, | 
|  | 808 | unsigned int authsize) | 
|  | 809 | { | 
|  | 810 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent); | 
|  | 811 |  | 
|  | 812 | switch (authsize) { | 
|  | 813 | case 8: | 
|  | 814 | case 12: | 
|  | 815 | case 16: | 
|  | 816 | break; | 
|  | 817 | default: | 
|  | 818 | return -EINVAL; | 
|  | 819 | } | 
|  | 820 |  | 
|  | 821 | return crypto_aead_setauthsize(ctx->child, authsize); | 
|  | 822 | } | 
|  | 823 |  | 
|  | 824 | static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req) | 
|  | 825 | { | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 826 | struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 827 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
|  | 828 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead); | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 829 | struct aead_request *subreq = &rctx->subreq; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 830 | struct crypto_aead *child = ctx->child; | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 831 | struct scatterlist *sg; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 832 | u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child), | 
|  | 833 | crypto_aead_alignmask(child) + 1); | 
|  | 834 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 835 | scatterwalk_map_and_copy(iv + 12, req->src, 0, req->assoclen - 8, 0); | 
|  | 836 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 837 | memcpy(iv, ctx->nonce, 4); | 
|  | 838 | memcpy(iv + 4, req->iv, 8); | 
|  | 839 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 840 | sg_init_table(rctx->src, 3); | 
|  | 841 | sg_set_buf(rctx->src, iv + 12, req->assoclen - 8); | 
|  | 842 | sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen); | 
|  | 843 | if (sg != rctx->src + 1) | 
|  | 844 | sg_chain(rctx->src, 2, sg); | 
|  | 845 |  | 
|  | 846 | if (req->src != req->dst) { | 
|  | 847 | sg_init_table(rctx->dst, 3); | 
|  | 848 | sg_set_buf(rctx->dst, iv + 12, req->assoclen - 8); | 
|  | 849 | sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen); | 
|  | 850 | if (sg != rctx->dst + 1) | 
|  | 851 | sg_chain(rctx->dst, 2, sg); | 
|  | 852 | } | 
|  | 853 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 854 | aead_request_set_tfm(subreq, child); | 
|  | 855 | aead_request_set_callback(subreq, req->base.flags, req->base.complete, | 
|  | 856 | req->base.data); | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 857 | aead_request_set_crypt(subreq, rctx->src, | 
|  | 858 | req->src == req->dst ? rctx->src : rctx->dst, | 
|  | 859 | req->cryptlen, iv); | 
|  | 860 | aead_request_set_ad(subreq, req->assoclen - 8); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 861 |  | 
|  | 862 | return subreq; | 
|  | 863 | } | 
|  | 864 |  | 
|  | 865 | static int crypto_rfc4106_encrypt(struct aead_request *req) | 
|  | 866 | { | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 867 | if (req->assoclen != 16 && req->assoclen != 20) | 
|  | 868 | return -EINVAL; | 
|  | 869 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 870 | req = crypto_rfc4106_crypt(req); | 
|  | 871 |  | 
|  | 872 | return crypto_aead_encrypt(req); | 
|  | 873 | } | 
|  | 874 |  | 
|  | 875 | static int crypto_rfc4106_decrypt(struct aead_request *req) | 
|  | 876 | { | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 877 | if (req->assoclen != 16 && req->assoclen != 20) | 
|  | 878 | return -EINVAL; | 
|  | 879 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 880 | req = crypto_rfc4106_crypt(req); | 
|  | 881 |  | 
|  | 882 | return crypto_aead_decrypt(req); | 
|  | 883 | } | 
|  | 884 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 885 | static int crypto_rfc4106_init_tfm(struct crypto_aead *tfm) | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 886 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 887 | struct aead_instance *inst = aead_alg_instance(tfm); | 
|  | 888 | struct crypto_aead_spawn *spawn = aead_instance_ctx(inst); | 
|  | 889 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 890 | struct crypto_aead *aead; | 
|  | 891 | unsigned long align; | 
|  | 892 |  | 
|  | 893 | aead = crypto_spawn_aead(spawn); | 
|  | 894 | if (IS_ERR(aead)) | 
|  | 895 | return PTR_ERR(aead); | 
|  | 896 |  | 
|  | 897 | ctx->child = aead; | 
|  | 898 |  | 
|  | 899 | align = crypto_aead_alignmask(aead); | 
|  | 900 | align &= ~(crypto_tfm_ctx_alignment() - 1); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 901 | crypto_aead_set_reqsize( | 
|  | 902 | tfm, | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 903 | sizeof(struct crypto_rfc4106_req_ctx) + | 
| Herbert Xu | 5d72336 | 2015-05-11 17:47:59 +0800 | [diff] [blame] | 904 | ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) + | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 905 | align + 24); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 906 |  | 
|  | 907 | return 0; | 
|  | 908 | } | 
|  | 909 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 910 | static void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm) | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 911 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 912 | struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 913 |  | 
|  | 914 | crypto_free_aead(ctx->child); | 
|  | 915 | } | 
|  | 916 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 917 | static void crypto_rfc4106_free(struct aead_instance *inst) | 
|  | 918 | { | 
|  | 919 | crypto_drop_aead(aead_instance_ctx(inst)); | 
|  | 920 | kfree(inst); | 
|  | 921 | } | 
|  | 922 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 923 | static int crypto_rfc4106_create(struct crypto_template *tmpl, | 
|  | 924 | struct rtattr **tb) | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 925 | { | 
|  | 926 | struct crypto_attr_type *algt; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 927 | struct aead_instance *inst; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 928 | struct crypto_aead_spawn *spawn; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 929 | struct aead_alg *alg; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 930 | const char *ccm_name; | 
|  | 931 | int err; | 
|  | 932 |  | 
|  | 933 | algt = crypto_get_attr_type(tb); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 934 | if (IS_ERR(algt)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 935 | return PTR_ERR(algt); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 936 |  | 
| Herbert Xu | 5e4b8c1 | 2015-08-13 17:29:06 +0800 | [diff] [blame] | 937 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 938 | return -EINVAL; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 939 |  | 
|  | 940 | ccm_name = crypto_attr_alg_name(tb[1]); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 941 | if (IS_ERR(ccm_name)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 942 | return PTR_ERR(ccm_name); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 943 |  | 
|  | 944 | inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); | 
|  | 945 | if (!inst) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 946 | return -ENOMEM; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 947 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 948 | spawn = aead_instance_ctx(inst); | 
|  | 949 | crypto_set_aead_spawn(spawn, aead_crypto_instance(inst)); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 950 | err = crypto_grab_aead(spawn, ccm_name, 0, | 
|  | 951 | crypto_requires_sync(algt->type, algt->mask)); | 
|  | 952 | if (err) | 
|  | 953 | goto out_free_inst; | 
|  | 954 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 955 | alg = crypto_spawn_aead_alg(spawn); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 956 |  | 
|  | 957 | err = -EINVAL; | 
|  | 958 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 959 | /* Underlying IV size must be 12. */ | 
|  | 960 | if (crypto_aead_alg_ivsize(alg) != 12) | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 961 | goto out_drop_alg; | 
|  | 962 |  | 
|  | 963 | /* Not a stream cipher? */ | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 964 | if (alg->base.cra_blocksize != 1) | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 965 | goto out_drop_alg; | 
|  | 966 |  | 
|  | 967 | err = -ENAMETOOLONG; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 968 | if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, | 
|  | 969 | "rfc4106(%s)", alg->base.cra_name) >= | 
|  | 970 | CRYPTO_MAX_ALG_NAME || | 
|  | 971 | snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, | 
|  | 972 | "rfc4106(%s)", alg->base.cra_driver_name) >= | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 973 | CRYPTO_MAX_ALG_NAME) | 
|  | 974 | goto out_drop_alg; | 
|  | 975 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 976 | inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 977 | inst->alg.base.cra_priority = alg->base.cra_priority; | 
|  | 978 | inst->alg.base.cra_blocksize = 1; | 
|  | 979 | inst->alg.base.cra_alignmask = alg->base.cra_alignmask; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 980 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 981 | inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 982 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 983 | inst->alg.ivsize = 8; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 984 | inst->alg.chunksize = crypto_aead_alg_chunksize(alg); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 985 | inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 986 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 987 | inst->alg.init = crypto_rfc4106_init_tfm; | 
|  | 988 | inst->alg.exit = crypto_rfc4106_exit_tfm; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 989 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 990 | inst->alg.setkey = crypto_rfc4106_setkey; | 
|  | 991 | inst->alg.setauthsize = crypto_rfc4106_setauthsize; | 
|  | 992 | inst->alg.encrypt = crypto_rfc4106_encrypt; | 
|  | 993 | inst->alg.decrypt = crypto_rfc4106_decrypt; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 994 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 995 | inst->free = crypto_rfc4106_free; | 
|  | 996 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 997 | err = aead_register_instance(tmpl, inst); | 
|  | 998 | if (err) | 
|  | 999 | goto out_drop_alg; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1000 |  | 
|  | 1001 | out: | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1002 | return err; | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1003 |  | 
|  | 1004 | out_drop_alg: | 
|  | 1005 | crypto_drop_aead(spawn); | 
|  | 1006 | out_free_inst: | 
|  | 1007 | kfree(inst); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1008 | goto out; | 
|  | 1009 | } | 
|  | 1010 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1011 | static struct crypto_template crypto_rfc4106_tmpl = { | 
|  | 1012 | .name = "rfc4106", | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1013 | .create = crypto_rfc4106_create, | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1014 | .module = THIS_MODULE, | 
|  | 1015 | }; | 
|  | 1016 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1017 | static int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key, | 
|  | 1018 | unsigned int keylen) | 
|  | 1019 | { | 
|  | 1020 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); | 
|  | 1021 | struct crypto_aead *child = ctx->child; | 
|  | 1022 | int err; | 
|  | 1023 |  | 
|  | 1024 | if (keylen < 4) | 
|  | 1025 | return -EINVAL; | 
|  | 1026 |  | 
|  | 1027 | keylen -= 4; | 
|  | 1028 | memcpy(ctx->nonce, key + keylen, 4); | 
|  | 1029 |  | 
|  | 1030 | crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); | 
|  | 1031 | crypto_aead_set_flags(child, crypto_aead_get_flags(parent) & | 
|  | 1032 | CRYPTO_TFM_REQ_MASK); | 
|  | 1033 | err = crypto_aead_setkey(child, key, keylen); | 
|  | 1034 | crypto_aead_set_flags(parent, crypto_aead_get_flags(child) & | 
|  | 1035 | CRYPTO_TFM_RES_MASK); | 
|  | 1036 |  | 
|  | 1037 | return err; | 
|  | 1038 | } | 
|  | 1039 |  | 
|  | 1040 | static int crypto_rfc4543_setauthsize(struct crypto_aead *parent, | 
|  | 1041 | unsigned int authsize) | 
|  | 1042 | { | 
|  | 1043 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent); | 
|  | 1044 |  | 
|  | 1045 | if (authsize != 16) | 
|  | 1046 | return -EINVAL; | 
|  | 1047 |  | 
|  | 1048 | return crypto_aead_setauthsize(ctx->child, authsize); | 
|  | 1049 | } | 
|  | 1050 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1051 | static int crypto_rfc4543_crypt(struct aead_request *req, bool enc) | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1052 | { | 
|  | 1053 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
|  | 1054 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1055 | struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1056 | struct aead_request *subreq = &rctx->subreq; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1057 | unsigned int authsize = crypto_aead_authsize(aead); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1058 | u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child), | 
|  | 1059 | crypto_aead_alignmask(ctx->child) + 1); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1060 | int err; | 
|  | 1061 |  | 
|  | 1062 | if (req->src != req->dst) { | 
|  | 1063 | err = crypto_rfc4543_copy_src_to_dst(req, enc); | 
|  | 1064 | if (err) | 
|  | 1065 | return err; | 
|  | 1066 | } | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1067 |  | 
|  | 1068 | memcpy(iv, ctx->nonce, 4); | 
|  | 1069 | memcpy(iv + 4, req->iv, 8); | 
|  | 1070 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1071 | aead_request_set_tfm(subreq, ctx->child); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1072 | aead_request_set_callback(subreq, req->base.flags, | 
|  | 1073 | req->base.complete, req->base.data); | 
|  | 1074 | aead_request_set_crypt(subreq, req->src, req->dst, | 
|  | 1075 | enc ? 0 : authsize, iv); | 
|  | 1076 | aead_request_set_ad(subreq, req->assoclen + req->cryptlen - | 
|  | 1077 | subreq->cryptlen); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1078 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1079 | return enc ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1080 | } | 
|  | 1081 |  | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1082 | static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc) | 
|  | 1083 | { | 
|  | 1084 | struct crypto_aead *aead = crypto_aead_reqtfm(req); | 
|  | 1085 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead); | 
|  | 1086 | unsigned int authsize = crypto_aead_authsize(aead); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1087 | unsigned int nbytes = req->assoclen + req->cryptlen - | 
|  | 1088 | (enc ? 0 : authsize); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1089 | SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null); | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1090 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1091 | skcipher_request_set_tfm(nreq, ctx->null); | 
|  | 1092 | skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL); | 
|  | 1093 | skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL); | 
|  | 1094 |  | 
|  | 1095 | return crypto_skcipher_encrypt(nreq); | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1096 | } | 
|  | 1097 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1098 | static int crypto_rfc4543_encrypt(struct aead_request *req) | 
|  | 1099 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1100 | return crypto_rfc4543_crypt(req, true); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1101 | } | 
|  | 1102 |  | 
|  | 1103 | static int crypto_rfc4543_decrypt(struct aead_request *req) | 
|  | 1104 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1105 | return crypto_rfc4543_crypt(req, false); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1106 | } | 
|  | 1107 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1108 | static int crypto_rfc4543_init_tfm(struct crypto_aead *tfm) | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1109 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1110 | struct aead_instance *inst = aead_alg_instance(tfm); | 
|  | 1111 | struct crypto_rfc4543_instance_ctx *ictx = aead_instance_ctx(inst); | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1112 | struct crypto_aead_spawn *spawn = &ictx->aead; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1113 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1114 | struct crypto_aead *aead; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1115 | struct crypto_skcipher *null; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1116 | unsigned long align; | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1117 | int err = 0; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1118 |  | 
|  | 1119 | aead = crypto_spawn_aead(spawn); | 
|  | 1120 | if (IS_ERR(aead)) | 
|  | 1121 | return PTR_ERR(aead); | 
|  | 1122 |  | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1123 | null = crypto_get_default_null_skcipher2(); | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1124 | err = PTR_ERR(null); | 
|  | 1125 | if (IS_ERR(null)) | 
|  | 1126 | goto err_free_aead; | 
|  | 1127 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1128 | ctx->child = aead; | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1129 | ctx->null = null; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1130 |  | 
|  | 1131 | align = crypto_aead_alignmask(aead); | 
|  | 1132 | align &= ~(crypto_tfm_ctx_alignment() - 1); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1133 | crypto_aead_set_reqsize( | 
|  | 1134 | tfm, | 
| Herbert Xu | 5d72336 | 2015-05-11 17:47:59 +0800 | [diff] [blame] | 1135 | sizeof(struct crypto_rfc4543_req_ctx) + | 
|  | 1136 | ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) + | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1137 | align + 12); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1138 |  | 
|  | 1139 | return 0; | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1140 |  | 
|  | 1141 | err_free_aead: | 
|  | 1142 | crypto_free_aead(aead); | 
|  | 1143 | return err; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1144 | } | 
|  | 1145 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1146 | static void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm) | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1147 | { | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1148 | struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1149 |  | 
|  | 1150 | crypto_free_aead(ctx->child); | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1151 | crypto_put_default_null_skcipher2(); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1152 | } | 
|  | 1153 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 1154 | static void crypto_rfc4543_free(struct aead_instance *inst) | 
|  | 1155 | { | 
|  | 1156 | struct crypto_rfc4543_instance_ctx *ctx = aead_instance_ctx(inst); | 
|  | 1157 |  | 
|  | 1158 | crypto_drop_aead(&ctx->aead); | 
|  | 1159 |  | 
|  | 1160 | kfree(inst); | 
|  | 1161 | } | 
|  | 1162 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1163 | static int crypto_rfc4543_create(struct crypto_template *tmpl, | 
|  | 1164 | struct rtattr **tb) | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1165 | { | 
|  | 1166 | struct crypto_attr_type *algt; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1167 | struct aead_instance *inst; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1168 | struct crypto_aead_spawn *spawn; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1169 | struct aead_alg *alg; | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1170 | struct crypto_rfc4543_instance_ctx *ctx; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1171 | const char *ccm_name; | 
|  | 1172 | int err; | 
|  | 1173 |  | 
|  | 1174 | algt = crypto_get_attr_type(tb); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1175 | if (IS_ERR(algt)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1176 | return PTR_ERR(algt); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1177 |  | 
| Herbert Xu | 5e4b8c1 | 2015-08-13 17:29:06 +0800 | [diff] [blame] | 1178 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1179 | return -EINVAL; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1180 |  | 
|  | 1181 | ccm_name = crypto_attr_alg_name(tb[1]); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1182 | if (IS_ERR(ccm_name)) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1183 | return PTR_ERR(ccm_name); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1184 |  | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1185 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1186 | if (!inst) | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1187 | return -ENOMEM; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1188 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1189 | ctx = aead_instance_ctx(inst); | 
| Jussi Kivilinna | 9489667d | 2013-04-07 16:43:41 +0300 | [diff] [blame] | 1190 | spawn = &ctx->aead; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1191 | crypto_set_aead_spawn(spawn, aead_crypto_instance(inst)); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1192 | err = crypto_grab_aead(spawn, ccm_name, 0, | 
|  | 1193 | crypto_requires_sync(algt->type, algt->mask)); | 
|  | 1194 | if (err) | 
|  | 1195 | goto out_free_inst; | 
|  | 1196 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1197 | alg = crypto_spawn_aead_alg(spawn); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1198 |  | 
|  | 1199 | err = -EINVAL; | 
|  | 1200 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1201 | /* Underlying IV size must be 12. */ | 
|  | 1202 | if (crypto_aead_alg_ivsize(alg) != 12) | 
| Herbert Xu | 17db854 | 2015-05-21 15:11:11 +0800 | [diff] [blame] | 1203 | goto out_drop_alg; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1204 |  | 
|  | 1205 | /* Not a stream cipher? */ | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1206 | if (alg->base.cra_blocksize != 1) | 
| Herbert Xu | 17db854 | 2015-05-21 15:11:11 +0800 | [diff] [blame] | 1207 | goto out_drop_alg; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1208 |  | 
|  | 1209 | err = -ENAMETOOLONG; | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1210 | if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, | 
|  | 1211 | "rfc4543(%s)", alg->base.cra_name) >= | 
|  | 1212 | CRYPTO_MAX_ALG_NAME || | 
|  | 1213 | snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, | 
|  | 1214 | "rfc4543(%s)", alg->base.cra_driver_name) >= | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1215 | CRYPTO_MAX_ALG_NAME) | 
| Herbert Xu | 17db854 | 2015-05-21 15:11:11 +0800 | [diff] [blame] | 1216 | goto out_drop_alg; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1217 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1218 | inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; | 
|  | 1219 | inst->alg.base.cra_priority = alg->base.cra_priority; | 
|  | 1220 | inst->alg.base.cra_blocksize = 1; | 
|  | 1221 | inst->alg.base.cra_alignmask = alg->base.cra_alignmask; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1222 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1223 | inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1224 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1225 | inst->alg.ivsize = 8; | 
| Herbert Xu | 16f37ecd | 2016-07-12 13:17:39 +0800 | [diff] [blame] | 1226 | inst->alg.chunksize = crypto_aead_alg_chunksize(alg); | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1227 | inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1228 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1229 | inst->alg.init = crypto_rfc4543_init_tfm; | 
|  | 1230 | inst->alg.exit = crypto_rfc4543_exit_tfm; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1231 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1232 | inst->alg.setkey = crypto_rfc4543_setkey; | 
|  | 1233 | inst->alg.setauthsize = crypto_rfc4543_setauthsize; | 
|  | 1234 | inst->alg.encrypt = crypto_rfc4543_encrypt; | 
|  | 1235 | inst->alg.decrypt = crypto_rfc4543_decrypt; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1236 |  | 
| Herbert Xu | 7b05a37 | 2015-07-09 07:17:30 +0800 | [diff] [blame] | 1237 | inst->free = crypto_rfc4543_free, | 
|  | 1238 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1239 | err = aead_register_instance(tmpl, inst); | 
|  | 1240 | if (err) | 
|  | 1241 | goto out_drop_alg; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1242 |  | 
|  | 1243 | out: | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1244 | return err; | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1245 |  | 
|  | 1246 | out_drop_alg: | 
|  | 1247 | crypto_drop_aead(spawn); | 
|  | 1248 | out_free_inst: | 
|  | 1249 | kfree(inst); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1250 | goto out; | 
|  | 1251 | } | 
|  | 1252 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1253 | static struct crypto_template crypto_rfc4543_tmpl = { | 
|  | 1254 | .name = "rfc4543", | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1255 | .create = crypto_rfc4543_create, | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1256 | .module = THIS_MODULE, | 
|  | 1257 | }; | 
|  | 1258 |  | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 1259 | static int __init crypto_gcm_module_init(void) | 
|  | 1260 | { | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 1261 | int err; | 
|  | 1262 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1263 | gcm_zeroes = kzalloc(sizeof(*gcm_zeroes), GFP_KERNEL); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 1264 | if (!gcm_zeroes) | 
|  | 1265 | return -ENOMEM; | 
|  | 1266 |  | 
| Herbert Xu | adcbc68 | 2015-06-16 13:54:18 +0800 | [diff] [blame] | 1267 | sg_init_one(&gcm_zeroes->sg, gcm_zeroes->buf, sizeof(gcm_zeroes->buf)); | 
|  | 1268 |  | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 1269 | err = crypto_register_template(&crypto_gcm_base_tmpl); | 
|  | 1270 | if (err) | 
|  | 1271 | goto out; | 
|  | 1272 |  | 
|  | 1273 | err = crypto_register_template(&crypto_gcm_tmpl); | 
|  | 1274 | if (err) | 
|  | 1275 | goto out_undo_base; | 
|  | 1276 |  | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1277 | err = crypto_register_template(&crypto_rfc4106_tmpl); | 
|  | 1278 | if (err) | 
|  | 1279 | goto out_undo_gcm; | 
|  | 1280 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1281 | err = crypto_register_template(&crypto_rfc4543_tmpl); | 
|  | 1282 | if (err) | 
|  | 1283 | goto out_undo_rfc4106; | 
|  | 1284 |  | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 1285 | return 0; | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 1286 |  | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1287 | out_undo_rfc4106: | 
|  | 1288 | crypto_unregister_template(&crypto_rfc4106_tmpl); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1289 | out_undo_gcm: | 
|  | 1290 | crypto_unregister_template(&crypto_gcm_tmpl); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 1291 | out_undo_base: | 
|  | 1292 | crypto_unregister_template(&crypto_gcm_base_tmpl); | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 1293 | out: | 
|  | 1294 | kfree(gcm_zeroes); | 
|  | 1295 | return err; | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 1296 | } | 
|  | 1297 |  | 
|  | 1298 | static void __exit crypto_gcm_module_exit(void) | 
|  | 1299 | { | 
| Huang Ying | 9382d97 | 2009-08-06 15:34:26 +1000 | [diff] [blame] | 1300 | kfree(gcm_zeroes); | 
| Tobias Brunner | 73c89c1 | 2010-01-17 21:52:11 +1100 | [diff] [blame] | 1301 | crypto_unregister_template(&crypto_rfc4543_tmpl); | 
| Herbert Xu | dadbc53 | 2007-12-17 15:33:17 +0800 | [diff] [blame] | 1302 | crypto_unregister_template(&crypto_rfc4106_tmpl); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 1303 | crypto_unregister_template(&crypto_gcm_tmpl); | 
| Herbert Xu | d00aa19 | 2007-12-07 20:31:10 +0800 | [diff] [blame] | 1304 | crypto_unregister_template(&crypto_gcm_base_tmpl); | 
| Mikko Herranen | 28db8e3 | 2007-11-26 22:24:11 +0800 | [diff] [blame] | 1305 | } | 
|  | 1306 |  | 
|  | 1307 | module_init(crypto_gcm_module_init); | 
|  | 1308 | module_exit(crypto_gcm_module_exit); | 
|  | 1309 |  | 
|  | 1310 | MODULE_LICENSE("GPL"); | 
|  | 1311 | MODULE_DESCRIPTION("Galois/Counter Mode"); | 
|  | 1312 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); | 
| Kees Cook | 5d26a10 | 2014-11-20 17:05:53 -0800 | [diff] [blame] | 1313 | MODULE_ALIAS_CRYPTO("gcm_base"); | 
|  | 1314 | MODULE_ALIAS_CRYPTO("rfc4106"); | 
|  | 1315 | MODULE_ALIAS_CRYPTO("rfc4543"); | 
| Kees Cook | 4943ba1 | 2014-11-24 16:32:38 -0800 | [diff] [blame] | 1316 | MODULE_ALIAS_CRYPTO("gcm"); |