17a7ffe65SHerbert Xu /* 27a7ffe65SHerbert Xu * Symmetric key cipher operations. 37a7ffe65SHerbert Xu * 47a7ffe65SHerbert Xu * Generic encrypt/decrypt wrapper for ciphers, handles operations across 57a7ffe65SHerbert Xu * multiple page boundaries by using temporary blocks. In user context, 67a7ffe65SHerbert Xu * the kernel is given a chance to schedule us once per page. 77a7ffe65SHerbert Xu * 87a7ffe65SHerbert Xu * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au> 97a7ffe65SHerbert Xu * 107a7ffe65SHerbert Xu * This program is free software; you can redistribute it and/or modify it 117a7ffe65SHerbert Xu * under the terms of the GNU General Public License as published by the Free 127a7ffe65SHerbert Xu * Software Foundation; either version 2 of the License, or (at your option) 137a7ffe65SHerbert Xu * any later version. 147a7ffe65SHerbert Xu * 157a7ffe65SHerbert Xu */ 167a7ffe65SHerbert Xu 177a7ffe65SHerbert Xu #include <crypto/internal/skcipher.h> 187a7ffe65SHerbert Xu #include <linux/bug.h> 197a7ffe65SHerbert Xu #include <linux/module.h> 207a7ffe65SHerbert Xu 217a7ffe65SHerbert Xu #include "internal.h" 227a7ffe65SHerbert Xu 237a7ffe65SHerbert Xu static unsigned int crypto_skcipher_extsize(struct crypto_alg *alg) 247a7ffe65SHerbert Xu { 257a7ffe65SHerbert Xu if (alg->cra_type == &crypto_blkcipher_type) 267a7ffe65SHerbert Xu return sizeof(struct crypto_blkcipher *); 277a7ffe65SHerbert Xu 287a7ffe65SHerbert Xu BUG_ON(alg->cra_type != &crypto_ablkcipher_type && 297a7ffe65SHerbert Xu alg->cra_type != &crypto_givcipher_type); 307a7ffe65SHerbert Xu 317a7ffe65SHerbert Xu return sizeof(struct crypto_ablkcipher *); 327a7ffe65SHerbert Xu } 337a7ffe65SHerbert Xu 347a7ffe65SHerbert Xu static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, 357a7ffe65SHerbert Xu const u8 *key, unsigned int keylen) 367a7ffe65SHerbert Xu { 377a7ffe65SHerbert Xu struct crypto_blkcipher **ctx = crypto_skcipher_ctx(tfm); 387a7ffe65SHerbert Xu struct crypto_blkcipher *blkcipher = *ctx; 397a7ffe65SHerbert Xu int err; 407a7ffe65SHerbert Xu 417a7ffe65SHerbert Xu crypto_blkcipher_clear_flags(blkcipher, ~0); 427a7ffe65SHerbert Xu crypto_blkcipher_set_flags(blkcipher, crypto_skcipher_get_flags(tfm) & 437a7ffe65SHerbert Xu CRYPTO_TFM_REQ_MASK); 447a7ffe65SHerbert Xu err = crypto_blkcipher_setkey(blkcipher, key, keylen); 457a7ffe65SHerbert Xu crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & 467a7ffe65SHerbert Xu CRYPTO_TFM_RES_MASK); 477a7ffe65SHerbert Xu 487a7ffe65SHerbert Xu return err; 497a7ffe65SHerbert Xu } 507a7ffe65SHerbert Xu 517a7ffe65SHerbert Xu static int skcipher_crypt_blkcipher(struct skcipher_request *req, 527a7ffe65SHerbert Xu int (*crypt)(struct blkcipher_desc *, 537a7ffe65SHerbert Xu struct scatterlist *, 547a7ffe65SHerbert Xu struct scatterlist *, 557a7ffe65SHerbert Xu unsigned int)) 567a7ffe65SHerbert Xu { 577a7ffe65SHerbert Xu struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 587a7ffe65SHerbert Xu struct crypto_blkcipher **ctx = crypto_skcipher_ctx(tfm); 597a7ffe65SHerbert Xu struct blkcipher_desc desc = { 607a7ffe65SHerbert Xu .tfm = *ctx, 617a7ffe65SHerbert Xu .info = req->iv, 627a7ffe65SHerbert Xu .flags = req->base.flags, 637a7ffe65SHerbert Xu }; 647a7ffe65SHerbert Xu 657a7ffe65SHerbert Xu 667a7ffe65SHerbert Xu return crypt(&desc, req->dst, req->src, req->cryptlen); 677a7ffe65SHerbert Xu } 687a7ffe65SHerbert Xu 697a7ffe65SHerbert Xu static int skcipher_encrypt_blkcipher(struct skcipher_request *req) 707a7ffe65SHerbert Xu { 717a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 727a7ffe65SHerbert Xu struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 737a7ffe65SHerbert Xu struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; 747a7ffe65SHerbert Xu 757a7ffe65SHerbert Xu return skcipher_crypt_blkcipher(req, alg->encrypt); 767a7ffe65SHerbert Xu } 777a7ffe65SHerbert Xu 787a7ffe65SHerbert Xu static int skcipher_decrypt_blkcipher(struct skcipher_request *req) 797a7ffe65SHerbert Xu { 807a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 817a7ffe65SHerbert Xu struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 827a7ffe65SHerbert Xu struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; 837a7ffe65SHerbert Xu 847a7ffe65SHerbert Xu return skcipher_crypt_blkcipher(req, alg->decrypt); 857a7ffe65SHerbert Xu } 867a7ffe65SHerbert Xu 877a7ffe65SHerbert Xu static void crypto_exit_skcipher_ops_blkcipher(struct crypto_tfm *tfm) 887a7ffe65SHerbert Xu { 897a7ffe65SHerbert Xu struct crypto_blkcipher **ctx = crypto_tfm_ctx(tfm); 907a7ffe65SHerbert Xu 917a7ffe65SHerbert Xu crypto_free_blkcipher(*ctx); 927a7ffe65SHerbert Xu } 937a7ffe65SHerbert Xu 94*ecdd6bedSGeliang Tang static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) 957a7ffe65SHerbert Xu { 967a7ffe65SHerbert Xu struct crypto_alg *calg = tfm->__crt_alg; 977a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); 987a7ffe65SHerbert Xu struct crypto_blkcipher **ctx = crypto_tfm_ctx(tfm); 997a7ffe65SHerbert Xu struct crypto_blkcipher *blkcipher; 1007a7ffe65SHerbert Xu struct crypto_tfm *btfm; 1017a7ffe65SHerbert Xu 1027a7ffe65SHerbert Xu if (!crypto_mod_get(calg)) 1037a7ffe65SHerbert Xu return -EAGAIN; 1047a7ffe65SHerbert Xu 1057a7ffe65SHerbert Xu btfm = __crypto_alloc_tfm(calg, CRYPTO_ALG_TYPE_BLKCIPHER, 1067a7ffe65SHerbert Xu CRYPTO_ALG_TYPE_MASK); 1077a7ffe65SHerbert Xu if (IS_ERR(btfm)) { 1087a7ffe65SHerbert Xu crypto_mod_put(calg); 1097a7ffe65SHerbert Xu return PTR_ERR(btfm); 1107a7ffe65SHerbert Xu } 1117a7ffe65SHerbert Xu 1127a7ffe65SHerbert Xu blkcipher = __crypto_blkcipher_cast(btfm); 1137a7ffe65SHerbert Xu *ctx = blkcipher; 1147a7ffe65SHerbert Xu tfm->exit = crypto_exit_skcipher_ops_blkcipher; 1157a7ffe65SHerbert Xu 1167a7ffe65SHerbert Xu skcipher->setkey = skcipher_setkey_blkcipher; 1177a7ffe65SHerbert Xu skcipher->encrypt = skcipher_encrypt_blkcipher; 1187a7ffe65SHerbert Xu skcipher->decrypt = skcipher_decrypt_blkcipher; 1197a7ffe65SHerbert Xu 1207a7ffe65SHerbert Xu skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); 1217a7ffe65SHerbert Xu 1227a7ffe65SHerbert Xu return 0; 1237a7ffe65SHerbert Xu } 1247a7ffe65SHerbert Xu 1257a7ffe65SHerbert Xu static int skcipher_setkey_ablkcipher(struct crypto_skcipher *tfm, 1267a7ffe65SHerbert Xu const u8 *key, unsigned int keylen) 1277a7ffe65SHerbert Xu { 1287a7ffe65SHerbert Xu struct crypto_ablkcipher **ctx = crypto_skcipher_ctx(tfm); 1297a7ffe65SHerbert Xu struct crypto_ablkcipher *ablkcipher = *ctx; 1307a7ffe65SHerbert Xu int err; 1317a7ffe65SHerbert Xu 1327a7ffe65SHerbert Xu crypto_ablkcipher_clear_flags(ablkcipher, ~0); 1337a7ffe65SHerbert Xu crypto_ablkcipher_set_flags(ablkcipher, 1347a7ffe65SHerbert Xu crypto_skcipher_get_flags(tfm) & 1357a7ffe65SHerbert Xu CRYPTO_TFM_REQ_MASK); 1367a7ffe65SHerbert Xu err = crypto_ablkcipher_setkey(ablkcipher, key, keylen); 1377a7ffe65SHerbert Xu crypto_skcipher_set_flags(tfm, 1387a7ffe65SHerbert Xu crypto_ablkcipher_get_flags(ablkcipher) & 1397a7ffe65SHerbert Xu CRYPTO_TFM_RES_MASK); 1407a7ffe65SHerbert Xu 1417a7ffe65SHerbert Xu return err; 1427a7ffe65SHerbert Xu } 1437a7ffe65SHerbert Xu 1447a7ffe65SHerbert Xu static int skcipher_crypt_ablkcipher(struct skcipher_request *req, 1457a7ffe65SHerbert Xu int (*crypt)(struct ablkcipher_request *)) 1467a7ffe65SHerbert Xu { 1477a7ffe65SHerbert Xu struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 1487a7ffe65SHerbert Xu struct crypto_ablkcipher **ctx = crypto_skcipher_ctx(tfm); 1497a7ffe65SHerbert Xu struct ablkcipher_request *subreq = skcipher_request_ctx(req); 1507a7ffe65SHerbert Xu 1517a7ffe65SHerbert Xu ablkcipher_request_set_tfm(subreq, *ctx); 1527a7ffe65SHerbert Xu ablkcipher_request_set_callback(subreq, skcipher_request_flags(req), 1537a7ffe65SHerbert Xu req->base.complete, req->base.data); 1547a7ffe65SHerbert Xu ablkcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, 1557a7ffe65SHerbert Xu req->iv); 1567a7ffe65SHerbert Xu 1577a7ffe65SHerbert Xu return crypt(subreq); 1587a7ffe65SHerbert Xu } 1597a7ffe65SHerbert Xu 1607a7ffe65SHerbert Xu static int skcipher_encrypt_ablkcipher(struct skcipher_request *req) 1617a7ffe65SHerbert Xu { 1627a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 1637a7ffe65SHerbert Xu struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 1647a7ffe65SHerbert Xu struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; 1657a7ffe65SHerbert Xu 1667a7ffe65SHerbert Xu return skcipher_crypt_ablkcipher(req, alg->encrypt); 1677a7ffe65SHerbert Xu } 1687a7ffe65SHerbert Xu 1697a7ffe65SHerbert Xu static int skcipher_decrypt_ablkcipher(struct skcipher_request *req) 1707a7ffe65SHerbert Xu { 1717a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 1727a7ffe65SHerbert Xu struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 1737a7ffe65SHerbert Xu struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; 1747a7ffe65SHerbert Xu 1757a7ffe65SHerbert Xu return skcipher_crypt_ablkcipher(req, alg->decrypt); 1767a7ffe65SHerbert Xu } 1777a7ffe65SHerbert Xu 1787a7ffe65SHerbert Xu static void crypto_exit_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) 1797a7ffe65SHerbert Xu { 1807a7ffe65SHerbert Xu struct crypto_ablkcipher **ctx = crypto_tfm_ctx(tfm); 1817a7ffe65SHerbert Xu 1827a7ffe65SHerbert Xu crypto_free_ablkcipher(*ctx); 1837a7ffe65SHerbert Xu } 1847a7ffe65SHerbert Xu 185*ecdd6bedSGeliang Tang static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) 1867a7ffe65SHerbert Xu { 1877a7ffe65SHerbert Xu struct crypto_alg *calg = tfm->__crt_alg; 1887a7ffe65SHerbert Xu struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); 1897a7ffe65SHerbert Xu struct crypto_ablkcipher **ctx = crypto_tfm_ctx(tfm); 1907a7ffe65SHerbert Xu struct crypto_ablkcipher *ablkcipher; 1917a7ffe65SHerbert Xu struct crypto_tfm *abtfm; 1927a7ffe65SHerbert Xu 1937a7ffe65SHerbert Xu if (!crypto_mod_get(calg)) 1947a7ffe65SHerbert Xu return -EAGAIN; 1957a7ffe65SHerbert Xu 1967a7ffe65SHerbert Xu abtfm = __crypto_alloc_tfm(calg, 0, 0); 1977a7ffe65SHerbert Xu if (IS_ERR(abtfm)) { 1987a7ffe65SHerbert Xu crypto_mod_put(calg); 1997a7ffe65SHerbert Xu return PTR_ERR(abtfm); 2007a7ffe65SHerbert Xu } 2017a7ffe65SHerbert Xu 2027a7ffe65SHerbert Xu ablkcipher = __crypto_ablkcipher_cast(abtfm); 2037a7ffe65SHerbert Xu *ctx = ablkcipher; 2047a7ffe65SHerbert Xu tfm->exit = crypto_exit_skcipher_ops_ablkcipher; 2057a7ffe65SHerbert Xu 2067a7ffe65SHerbert Xu skcipher->setkey = skcipher_setkey_ablkcipher; 2077a7ffe65SHerbert Xu skcipher->encrypt = skcipher_encrypt_ablkcipher; 2087a7ffe65SHerbert Xu skcipher->decrypt = skcipher_decrypt_ablkcipher; 2097a7ffe65SHerbert Xu 2107a7ffe65SHerbert Xu skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher); 2117a7ffe65SHerbert Xu skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) + 2127a7ffe65SHerbert Xu sizeof(struct ablkcipher_request); 2137a7ffe65SHerbert Xu 2147a7ffe65SHerbert Xu return 0; 2157a7ffe65SHerbert Xu } 2167a7ffe65SHerbert Xu 2177a7ffe65SHerbert Xu static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) 2187a7ffe65SHerbert Xu { 2197a7ffe65SHerbert Xu if (tfm->__crt_alg->cra_type == &crypto_blkcipher_type) 2207a7ffe65SHerbert Xu return crypto_init_skcipher_ops_blkcipher(tfm); 2217a7ffe65SHerbert Xu 2227a7ffe65SHerbert Xu BUG_ON(tfm->__crt_alg->cra_type != &crypto_ablkcipher_type && 2237a7ffe65SHerbert Xu tfm->__crt_alg->cra_type != &crypto_givcipher_type); 2247a7ffe65SHerbert Xu 2257a7ffe65SHerbert Xu return crypto_init_skcipher_ops_ablkcipher(tfm); 2267a7ffe65SHerbert Xu } 2277a7ffe65SHerbert Xu 2287a7ffe65SHerbert Xu static const struct crypto_type crypto_skcipher_type2 = { 2297a7ffe65SHerbert Xu .extsize = crypto_skcipher_extsize, 2307a7ffe65SHerbert Xu .init_tfm = crypto_skcipher_init_tfm, 2317a7ffe65SHerbert Xu .maskclear = ~CRYPTO_ALG_TYPE_MASK, 2327a7ffe65SHerbert Xu .maskset = CRYPTO_ALG_TYPE_BLKCIPHER_MASK, 2337a7ffe65SHerbert Xu .type = CRYPTO_ALG_TYPE_BLKCIPHER, 2347a7ffe65SHerbert Xu .tfmsize = offsetof(struct crypto_skcipher, base), 2357a7ffe65SHerbert Xu }; 2367a7ffe65SHerbert Xu 2377a7ffe65SHerbert Xu struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, 2387a7ffe65SHerbert Xu u32 type, u32 mask) 2397a7ffe65SHerbert Xu { 2407a7ffe65SHerbert Xu return crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask); 2417a7ffe65SHerbert Xu } 2427a7ffe65SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_skcipher); 2437a7ffe65SHerbert Xu 2447a7ffe65SHerbert Xu MODULE_LICENSE("GPL"); 2457a7ffe65SHerbert Xu MODULE_DESCRIPTION("Symmetric key cipher type"); 246