diff options
Diffstat (limited to 'crypto/gcm.c')
-rw-r--r-- | crypto/gcm.c | 287 |
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 | ||
40 | struct crypto_rfc4543_ctx { | ||
41 | struct crypto_aead *child; | ||
42 | u8 nonce[4]; | ||
43 | }; | ||
44 | |||
45 | struct 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 | |||
40 | struct crypto_gcm_ghash_ctx { | 53 | struct 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 | ||
1063 | static 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 | |||
1071 | static 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 | |||
1094 | static 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 */ | ||
1106 | static 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 | |||
1120 | static 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 | |||
1174 | static 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 | |||
1192 | static 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 | |||
1199 | static 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 | |||
1223 | static 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 | |||
1230 | static 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 | |||
1305 | out: | ||
1306 | return inst; | ||
1307 | |||
1308 | out_drop_alg: | ||
1309 | crypto_drop_aead(spawn); | ||
1310 | out_free_inst: | ||
1311 | kfree(inst); | ||
1312 | inst = ERR_PTR(err); | ||
1313 | goto out; | ||
1314 | } | ||
1315 | |||
1316 | static void crypto_rfc4543_free(struct crypto_instance *inst) | ||
1317 | { | ||
1318 | crypto_drop_spawn(crypto_instance_ctx(inst)); | ||
1319 | kfree(inst); | ||
1320 | } | ||
1321 | |||
1322 | static 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 | |||
1050 | static int __init crypto_gcm_module_init(void) | 1329 | static 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 | ||
1355 | out_undo_rfc4106: | ||
1356 | crypto_unregister_template(&crypto_rfc4106_tmpl); | ||
1072 | out_undo_gcm: | 1357 | out_undo_gcm: |
1073 | crypto_unregister_template(&crypto_gcm_tmpl); | 1358 | crypto_unregister_template(&crypto_gcm_tmpl); |
1074 | out_undo_base: | 1359 | out_undo_base: |
@@ -1081,6 +1366,7 @@ out: | |||
1081 | static void __exit crypto_gcm_module_exit(void) | 1366 | static 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"); | |||
1094 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); | 1380 | MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); |
1095 | MODULE_ALIAS("gcm_base"); | 1381 | MODULE_ALIAS("gcm_base"); |
1096 | MODULE_ALIAS("rfc4106"); | 1382 | MODULE_ALIAS("rfc4106"); |
1383 | MODULE_ALIAS("rfc4543"); | ||