aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/gcm.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/crypto/gcm.c b/crypto/gcm.c
index c6547130624c..2f5fbba6576c 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -37,6 +37,19 @@ struct crypto_rfc4106_ctx {
37 u8 nonce[4]; 37 u8 nonce[4];
38}; 38};
39 39
40struct crypto_rfc4543_ctx {
41 struct crypto_aead *child;
42 u8 nonce[4];
43};
44
45struct crypto_rfc4543_req_ctx {
46 u8 auth_tag[16];
47 struct scatterlist cipher[1];
48 struct scatterlist payload[2];
49 struct scatterlist assoc[2];
50 struct aead_request subreq;
51};
52
40struct crypto_gcm_ghash_ctx { 53struct crypto_gcm_ghash_ctx {
41 unsigned int cryptlen; 54 unsigned int cryptlen;
42 struct scatterlist *src; 55 struct scatterlist *src;
@@ -1047,6 +1060,272 @@ static struct crypto_template crypto_rfc4106_tmpl = {
1047 .module = THIS_MODULE, 1060 .module = THIS_MODULE,
1048}; 1061};
1049 1062
1063static inline struct crypto_rfc4543_req_ctx *crypto_rfc4543_reqctx(
1064 struct aead_request *req)
1065{
1066 unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
1067
1068 return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
1069}
1070
1071static int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key,
1072 unsigned int keylen)
1073{
1074 struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
1075 struct crypto_aead *child = ctx->child;
1076 int err;
1077
1078 if (keylen < 4)
1079 return -EINVAL;
1080
1081 keylen -= 4;
1082 memcpy(ctx->nonce, key + keylen, 4);
1083
1084 crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
1085 crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
1086 CRYPTO_TFM_REQ_MASK);
1087 err = crypto_aead_setkey(child, key, keylen);
1088 crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
1089 CRYPTO_TFM_RES_MASK);
1090
1091 return err;
1092}
1093
1094static int crypto_rfc4543_setauthsize(struct crypto_aead *parent,
1095 unsigned int authsize)
1096{
1097 struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
1098
1099 if (authsize != 16)
1100 return -EINVAL;
1101
1102 return crypto_aead_setauthsize(ctx->child, authsize);
1103}
1104
1105/* this is the same as crypto_authenc_chain */
1106static void crypto_rfc4543_chain(struct scatterlist *head,
1107 struct scatterlist *sg, int chain)
1108{
1109 if (chain) {
1110 head->length += sg->length;
1111 sg = scatterwalk_sg_next(sg);
1112 }
1113
1114 if (sg)
1115 scatterwalk_sg_chain(head, 2, sg);
1116 else
1117 sg_mark_end(head);
1118}
1119
1120static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req,
1121 int enc)
1122{
1123 struct crypto_aead *aead = crypto_aead_reqtfm(req);
1124 struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
1125 struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
1126 struct aead_request *subreq = &rctx->subreq;
1127 struct scatterlist *dst = req->dst;
1128 struct scatterlist *cipher = rctx->cipher;
1129 struct scatterlist *payload = rctx->payload;
1130 struct scatterlist *assoc = rctx->assoc;
1131 unsigned int authsize = crypto_aead_authsize(aead);
1132 unsigned int assoclen = req->assoclen;
1133 struct page *dstp;
1134 u8 *vdst;
1135 u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child),
1136 crypto_aead_alignmask(ctx->child) + 1);
1137
1138 memcpy(iv, ctx->nonce, 4);
1139 memcpy(iv + 4, req->iv, 8);
1140
1141 /* construct cipher/plaintext */
1142 if (enc)
1143 memset(rctx->auth_tag, 0, authsize);
1144 else
1145 scatterwalk_map_and_copy(rctx->auth_tag, dst,
1146 req->cryptlen - authsize,
1147 authsize, 0);
1148
1149 sg_init_one(cipher, rctx->auth_tag, authsize);
1150
1151 /* construct the aad */
1152 dstp = sg_page(dst);
1153 vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst->offset;
1154
1155 sg_init_table(payload, 2);
1156 sg_set_buf(payload, req->iv, 8);
1157 crypto_rfc4543_chain(payload, dst, vdst == req->iv + 8);
1158 assoclen += 8 + req->cryptlen - (enc ? 0 : authsize);
1159
1160 sg_init_table(assoc, 2);
1161 sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
1162 req->assoc->offset);
1163 crypto_rfc4543_chain(assoc, payload, 0);
1164
1165 aead_request_set_tfm(subreq, ctx->child);
1166 aead_request_set_callback(subreq, req->base.flags, req->base.complete,
1167 req->base.data);
1168 aead_request_set_crypt(subreq, cipher, cipher, enc ? 0 : authsize, iv);
1169 aead_request_set_assoc(subreq, assoc, assoclen);
1170
1171 return subreq;
1172}
1173
1174static int crypto_rfc4543_encrypt(struct aead_request *req)
1175{
1176 struct crypto_aead *aead = crypto_aead_reqtfm(req);
1177 struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
1178 struct aead_request *subreq;
1179 int err;
1180
1181 subreq = crypto_rfc4543_crypt(req, 1);
1182 err = crypto_aead_encrypt(subreq);
1183 if (err)
1184 return err;
1185
1186 scatterwalk_map_and_copy(rctx->auth_tag, req->dst, req->cryptlen,
1187 crypto_aead_authsize(aead), 1);
1188
1189 return 0;
1190}
1191
1192static int crypto_rfc4543_decrypt(struct aead_request *req)
1193{
1194 req = crypto_rfc4543_crypt(req, 0);
1195
1196 return crypto_aead_decrypt(req);
1197}
1198
1199static int crypto_rfc4543_init_tfm(struct crypto_tfm *tfm)
1200{
1201 struct crypto_instance *inst = (void *)tfm->__crt_alg;
1202 struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
1203 struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm);
1204 struct crypto_aead *aead;
1205 unsigned long align;
1206
1207 aead = crypto_spawn_aead(spawn);
1208 if (IS_ERR(aead))
1209 return PTR_ERR(aead);
1210
1211 ctx->child = aead;
1212
1213 align = crypto_aead_alignmask(aead);
1214 align &= ~(crypto_tfm_ctx_alignment() - 1);
1215 tfm->crt_aead.reqsize = sizeof(struct crypto_rfc4543_req_ctx) +
1216 ALIGN(crypto_aead_reqsize(aead),
1217 crypto_tfm_ctx_alignment()) +
1218 align + 16;
1219
1220 return 0;
1221}
1222
1223static void crypto_rfc4543_exit_tfm(struct crypto_tfm *tfm)
1224{
1225 struct crypto_rfc4543_ctx *ctx = crypto_tfm_ctx(tfm);
1226
1227 crypto_free_aead(ctx->child);
1228}
1229
1230static struct crypto_instance *crypto_rfc4543_alloc(struct rtattr **tb)
1231{
1232 struct crypto_attr_type *algt;
1233 struct crypto_instance *inst;
1234 struct crypto_aead_spawn *spawn;
1235 struct crypto_alg *alg;
1236 const char *ccm_name;
1237 int err;
1238
1239 algt = crypto_get_attr_type(tb);
1240 err = PTR_ERR(algt);
1241 if (IS_ERR(algt))
1242 return ERR_PTR(err);
1243
1244 if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
1245 return ERR_PTR(-EINVAL);
1246
1247 ccm_name = crypto_attr_alg_name(tb[1]);
1248 err = PTR_ERR(ccm_name);
1249 if (IS_ERR(ccm_name))
1250 return ERR_PTR(err);
1251
1252 inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
1253 if (!inst)
1254 return ERR_PTR(-ENOMEM);
1255
1256 spawn = crypto_instance_ctx(inst);
1257 crypto_set_aead_spawn(spawn, inst);
1258 err = crypto_grab_aead(spawn, ccm_name, 0,
1259 crypto_requires_sync(algt->type, algt->mask));
1260 if (err)
1261 goto out_free_inst;
1262
1263 alg = crypto_aead_spawn_alg(spawn);
1264
1265 err = -EINVAL;
1266
1267 /* We only support 16-byte blocks. */
1268 if (alg->cra_aead.ivsize != 16)
1269 goto out_drop_alg;
1270
1271 /* Not a stream cipher? */
1272 if (alg->cra_blocksize != 1)
1273 goto out_drop_alg;
1274
1275 err = -ENAMETOOLONG;
1276 if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
1277 "rfc4543(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
1278 snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
1279 "rfc4543(%s)", alg->cra_driver_name) >=
1280 CRYPTO_MAX_ALG_NAME)
1281 goto out_drop_alg;
1282
1283 inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
1284 inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
1285 inst->alg.cra_priority = alg->cra_priority;
1286 inst->alg.cra_blocksize = 1;
1287 inst->alg.cra_alignmask = alg->cra_alignmask;
1288 inst->alg.cra_type = &crypto_nivaead_type;
1289
1290 inst->alg.cra_aead.ivsize = 8;
1291 inst->alg.cra_aead.maxauthsize = 16;
1292
1293 inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx);
1294
1295 inst->alg.cra_init = crypto_rfc4543_init_tfm;
1296 inst->alg.cra_exit = crypto_rfc4543_exit_tfm;
1297
1298 inst->alg.cra_aead.setkey = crypto_rfc4543_setkey;
1299 inst->alg.cra_aead.setauthsize = crypto_rfc4543_setauthsize;
1300 inst->alg.cra_aead.encrypt = crypto_rfc4543_encrypt;
1301 inst->alg.cra_aead.decrypt = crypto_rfc4543_decrypt;
1302
1303 inst->alg.cra_aead.geniv = "seqiv";
1304
1305out:
1306 return inst;
1307
1308out_drop_alg:
1309 crypto_drop_aead(spawn);
1310out_free_inst:
1311 kfree(inst);
1312 inst = ERR_PTR(err);
1313 goto out;
1314}
1315
1316static void crypto_rfc4543_free(struct crypto_instance *inst)
1317{
1318 crypto_drop_spawn(crypto_instance_ctx(inst));
1319 kfree(inst);
1320}
1321
1322static struct crypto_template crypto_rfc4543_tmpl = {
1323 .name = "rfc4543",
1324 .alloc = crypto_rfc4543_alloc,
1325 .free = crypto_rfc4543_free,
1326 .module = THIS_MODULE,
1327};
1328
1050static int __init crypto_gcm_module_init(void) 1329static int __init crypto_gcm_module_init(void)
1051{ 1330{
1052 int err; 1331 int err;
@@ -1067,8 +1346,14 @@ static int __init crypto_gcm_module_init(void)
1067 if (err) 1346 if (err)
1068 goto out_undo_gcm; 1347 goto out_undo_gcm;
1069 1348
1349 err = crypto_register_template(&crypto_rfc4543_tmpl);
1350 if (err)
1351 goto out_undo_rfc4106;
1352
1070 return 0; 1353 return 0;
1071 1354
1355out_undo_rfc4106:
1356 crypto_unregister_template(&crypto_rfc4106_tmpl);
1072out_undo_gcm: 1357out_undo_gcm:
1073 crypto_unregister_template(&crypto_gcm_tmpl); 1358 crypto_unregister_template(&crypto_gcm_tmpl);
1074out_undo_base: 1359out_undo_base:
@@ -1081,6 +1366,7 @@ out:
1081static void __exit crypto_gcm_module_exit(void) 1366static void __exit crypto_gcm_module_exit(void)
1082{ 1367{
1083 kfree(gcm_zeroes); 1368 kfree(gcm_zeroes);
1369 crypto_unregister_template(&crypto_rfc4543_tmpl);
1084 crypto_unregister_template(&crypto_rfc4106_tmpl); 1370 crypto_unregister_template(&crypto_rfc4106_tmpl);
1085 crypto_unregister_template(&crypto_gcm_tmpl); 1371 crypto_unregister_template(&crypto_gcm_tmpl);
1086 crypto_unregister_template(&crypto_gcm_base_tmpl); 1372 crypto_unregister_template(&crypto_gcm_base_tmpl);
@@ -1094,3 +1380,4 @@ MODULE_DESCRIPTION("Galois/Counter Mode");
1094MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); 1380MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>");
1095MODULE_ALIAS("gcm_base"); 1381MODULE_ALIAS("gcm_base");
1096MODULE_ALIAS("rfc4106"); 1382MODULE_ALIAS("rfc4106");
1383MODULE_ALIAS("rfc4543");