aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2010-01-17 05:52:11 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2010-01-17 05:52:11 -0500
commit73c89c15b959adf06366722c4be8d2eddec0a529 (patch)
tree91c0d936c49607fbae703e4c7331e39896004d28 /crypto
parentfaad98f29606d9d3c6bddae7c88693be37d2fb43 (diff)
crypto: gcm - Add RFC4543 wrapper for GCM
This patch adds the RFC4543 (GMAC) wrapper for GCM similar to the existing RFC4106 wrapper. The main differences between GCM and GMAC are the contents of the AAD and that the plaintext is empty for the latter. Signed-off-by: Tobias Brunner <tobias@strongswan.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
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");