11c6fdbd8SKent Overstreet // SPDX-License-Identifier: GPL-2.0 21c6fdbd8SKent Overstreet #include "bcachefs.h" 31c6fdbd8SKent Overstreet #include "checksum.h" 41c6fdbd8SKent Overstreet #include "super.h" 51c6fdbd8SKent Overstreet #include "super-io.h" 61c6fdbd8SKent Overstreet 71c6fdbd8SKent Overstreet #include <linux/crc32c.h> 81c6fdbd8SKent Overstreet #include <linux/crypto.h> 941e63382Sjpsollie #include <linux/xxhash.h> 101c6fdbd8SKent Overstreet #include <linux/key.h> 111c6fdbd8SKent Overstreet #include <linux/random.h> 121c6fdbd8SKent Overstreet #include <linux/scatterlist.h> 131c6fdbd8SKent Overstreet #include <crypto/algapi.h> 141c6fdbd8SKent Overstreet #include <crypto/chacha.h> 151c6fdbd8SKent Overstreet #include <crypto/hash.h> 161c6fdbd8SKent Overstreet #include <crypto/poly1305.h> 171c6fdbd8SKent Overstreet #include <crypto/skcipher.h> 181c6fdbd8SKent Overstreet #include <keys/user-type.h> 191c6fdbd8SKent Overstreet 2080ff5d18Sjpsollie /* 2180ff5d18Sjpsollie * bch2_checksum state is an abstraction of the checksum state calculated over different pages. 2280ff5d18Sjpsollie * it features page merging without having the checksum algorithm lose its state. 2380ff5d18Sjpsollie * for native checksum aglorithms (like crc), a default seed value will do. 2480ff5d18Sjpsollie * for hash-like algorithms, a state needs to be stored 2580ff5d18Sjpsollie */ 2680ff5d18Sjpsollie 2780ff5d18Sjpsollie struct bch2_checksum_state { 2880ff5d18Sjpsollie union { 2980ff5d18Sjpsollie u64 seed; 3041e63382Sjpsollie struct xxh64_state h64state; 3180ff5d18Sjpsollie }; 3280ff5d18Sjpsollie unsigned int type; 3380ff5d18Sjpsollie }; 3480ff5d18Sjpsollie 3580ff5d18Sjpsollie static void bch2_checksum_init(struct bch2_checksum_state *state) 361c6fdbd8SKent Overstreet { 3780ff5d18Sjpsollie switch (state->type) { 386404dcc9SKent Overstreet case BCH_CSUM_none: 396404dcc9SKent Overstreet case BCH_CSUM_crc32c: 406404dcc9SKent Overstreet case BCH_CSUM_crc64: 4180ff5d18Sjpsollie state->seed = 0; 4280ff5d18Sjpsollie break; 436404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 4480ff5d18Sjpsollie state->seed = U32_MAX; 4580ff5d18Sjpsollie break; 466404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 4780ff5d18Sjpsollie state->seed = U64_MAX; 4880ff5d18Sjpsollie break; 496404dcc9SKent Overstreet case BCH_CSUM_xxhash: 5041e63382Sjpsollie xxh64_reset(&state->h64state, 0); 5141e63382Sjpsollie break; 521c6fdbd8SKent Overstreet default: 531c6fdbd8SKent Overstreet BUG(); 541c6fdbd8SKent Overstreet } 551c6fdbd8SKent Overstreet } 561c6fdbd8SKent Overstreet 5780ff5d18Sjpsollie static u64 bch2_checksum_final(const struct bch2_checksum_state *state) 581c6fdbd8SKent Overstreet { 5980ff5d18Sjpsollie switch (state->type) { 606404dcc9SKent Overstreet case BCH_CSUM_none: 616404dcc9SKent Overstreet case BCH_CSUM_crc32c: 626404dcc9SKent Overstreet case BCH_CSUM_crc64: 6380ff5d18Sjpsollie return state->seed; 646404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 6580ff5d18Sjpsollie return state->seed ^ U32_MAX; 666404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 6780ff5d18Sjpsollie return state->seed ^ U64_MAX; 686404dcc9SKent Overstreet case BCH_CSUM_xxhash: 6941e63382Sjpsollie return xxh64_digest(&state->h64state); 701c6fdbd8SKent Overstreet default: 711c6fdbd8SKent Overstreet BUG(); 721c6fdbd8SKent Overstreet } 731c6fdbd8SKent Overstreet } 741c6fdbd8SKent Overstreet 7580ff5d18Sjpsollie static void bch2_checksum_update(struct bch2_checksum_state *state, const void *data, size_t len) 761c6fdbd8SKent Overstreet { 7780ff5d18Sjpsollie switch (state->type) { 786404dcc9SKent Overstreet case BCH_CSUM_none: 7980ff5d18Sjpsollie return; 806404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 816404dcc9SKent Overstreet case BCH_CSUM_crc32c: 8280ff5d18Sjpsollie state->seed = crc32c(state->seed, data, len); 8380ff5d18Sjpsollie break; 846404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 856404dcc9SKent Overstreet case BCH_CSUM_crc64: 8680ff5d18Sjpsollie state->seed = crc64_be(state->seed, data, len); 8780ff5d18Sjpsollie break; 886404dcc9SKent Overstreet case BCH_CSUM_xxhash: 8941e63382Sjpsollie xxh64_update(&state->h64state, data, len); 9041e63382Sjpsollie break; 911c6fdbd8SKent Overstreet default: 921c6fdbd8SKent Overstreet BUG(); 931c6fdbd8SKent Overstreet } 941c6fdbd8SKent Overstreet } 951c6fdbd8SKent Overstreet 96a9de137bSKent Overstreet static inline int do_encrypt_sg(struct crypto_sync_skcipher *tfm, 971c6fdbd8SKent Overstreet struct nonce nonce, 981c6fdbd8SKent Overstreet struct scatterlist *sg, size_t len) 991c6fdbd8SKent Overstreet { 1001c6fdbd8SKent Overstreet SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); 1011c6fdbd8SKent Overstreet int ret; 1021c6fdbd8SKent Overstreet 1031c6fdbd8SKent Overstreet skcipher_request_set_sync_tfm(req, tfm); 1041c6fdbd8SKent Overstreet skcipher_request_set_crypt(req, sg, sg, len, nonce.d); 1051c6fdbd8SKent Overstreet 1061c6fdbd8SKent Overstreet ret = crypto_skcipher_encrypt(req); 107a9de137bSKent Overstreet if (ret) 108a9de137bSKent Overstreet pr_err("got error %i from crypto_skcipher_encrypt()", ret); 109a9de137bSKent Overstreet 110a9de137bSKent Overstreet return ret; 1111c6fdbd8SKent Overstreet } 1121c6fdbd8SKent Overstreet 113a9de137bSKent Overstreet static inline int do_encrypt(struct crypto_sync_skcipher *tfm, 1141c6fdbd8SKent Overstreet struct nonce nonce, 1151c6fdbd8SKent Overstreet void *buf, size_t len) 1161c6fdbd8SKent Overstreet { 117636d4eefSKent Overstreet if (!is_vmalloc_addr(buf)) { 1181c6fdbd8SKent Overstreet struct scatterlist sg; 1191c6fdbd8SKent Overstreet 120c346def9SKent Overstreet sg_init_table(&sg, 1); 121c346def9SKent Overstreet sg_set_page(&sg, 122c346def9SKent Overstreet is_vmalloc_addr(buf) 123c346def9SKent Overstreet ? vmalloc_to_page(buf) 124c346def9SKent Overstreet : virt_to_page(buf), 125c346def9SKent Overstreet len, offset_in_page(buf)); 126a9de137bSKent Overstreet return do_encrypt_sg(tfm, nonce, &sg, len); 127636d4eefSKent Overstreet } else { 128636d4eefSKent Overstreet unsigned pages = buf_pages(buf, len); 129636d4eefSKent Overstreet struct scatterlist *sg; 130636d4eefSKent Overstreet size_t orig_len = len; 131636d4eefSKent Overstreet int ret, i; 132636d4eefSKent Overstreet 133636d4eefSKent Overstreet sg = kmalloc_array(sizeof(*sg), pages, GFP_KERNEL); 134636d4eefSKent Overstreet if (!sg) 135636d4eefSKent Overstreet return -ENOMEM; 136636d4eefSKent Overstreet 137636d4eefSKent Overstreet sg_init_table(sg, pages); 138636d4eefSKent Overstreet 139636d4eefSKent Overstreet for (i = 0; i < pages; i++) { 140636d4eefSKent Overstreet unsigned offset = offset_in_page(buf); 141636d4eefSKent Overstreet unsigned pg_len = min(len, PAGE_SIZE - offset); 142636d4eefSKent Overstreet 143636d4eefSKent Overstreet sg_set_page(sg + i, vmalloc_to_page(buf), pg_len, offset); 144636d4eefSKent Overstreet buf += pg_len; 145636d4eefSKent Overstreet len -= pg_len; 146636d4eefSKent Overstreet } 147636d4eefSKent Overstreet 148636d4eefSKent Overstreet ret = do_encrypt_sg(tfm, nonce, sg, orig_len); 149636d4eefSKent Overstreet kfree(sg); 150636d4eefSKent Overstreet return ret; 151636d4eefSKent Overstreet } 1521c6fdbd8SKent Overstreet } 1531c6fdbd8SKent Overstreet 1541c6fdbd8SKent Overstreet int bch2_chacha_encrypt_key(struct bch_key *key, struct nonce nonce, 1551c6fdbd8SKent Overstreet void *buf, size_t len) 1561c6fdbd8SKent Overstreet { 1571c6fdbd8SKent Overstreet struct crypto_sync_skcipher *chacha20 = 1581c6fdbd8SKent Overstreet crypto_alloc_sync_skcipher("chacha20", 0, 0); 1591c6fdbd8SKent Overstreet int ret; 1601c6fdbd8SKent Overstreet 1611c6fdbd8SKent Overstreet if (!chacha20) { 1621c6fdbd8SKent Overstreet pr_err("error requesting chacha20 module: %li", PTR_ERR(chacha20)); 1631c6fdbd8SKent Overstreet return PTR_ERR(chacha20); 1641c6fdbd8SKent Overstreet } 1651c6fdbd8SKent Overstreet 1661c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&chacha20->base, 1671c6fdbd8SKent Overstreet (void *) key, sizeof(*key)); 1681c6fdbd8SKent Overstreet if (ret) { 1691c6fdbd8SKent Overstreet pr_err("crypto_skcipher_setkey() error: %i", ret); 1701c6fdbd8SKent Overstreet goto err; 1711c6fdbd8SKent Overstreet } 1721c6fdbd8SKent Overstreet 173a9de137bSKent Overstreet ret = do_encrypt(chacha20, nonce, buf, len); 1741c6fdbd8SKent Overstreet err: 1751c6fdbd8SKent Overstreet crypto_free_sync_skcipher(chacha20); 1761c6fdbd8SKent Overstreet return ret; 1771c6fdbd8SKent Overstreet } 1781c6fdbd8SKent Overstreet 179a9de137bSKent Overstreet static int gen_poly_key(struct bch_fs *c, struct shash_desc *desc, 1801c6fdbd8SKent Overstreet struct nonce nonce) 1811c6fdbd8SKent Overstreet { 1821c6fdbd8SKent Overstreet u8 key[POLY1305_KEY_SIZE]; 183a9de137bSKent Overstreet int ret; 1841c6fdbd8SKent Overstreet 1851c6fdbd8SKent Overstreet nonce.d[3] ^= BCH_NONCE_POLY; 1861c6fdbd8SKent Overstreet 1871c6fdbd8SKent Overstreet memset(key, 0, sizeof(key)); 188a9de137bSKent Overstreet ret = do_encrypt(c->chacha20, nonce, key, sizeof(key)); 189a9de137bSKent Overstreet if (ret) 190a9de137bSKent Overstreet return ret; 1911c6fdbd8SKent Overstreet 1921c6fdbd8SKent Overstreet desc->tfm = c->poly1305; 1931c6fdbd8SKent Overstreet crypto_shash_init(desc); 1941c6fdbd8SKent Overstreet crypto_shash_update(desc, key, sizeof(key)); 195a9de137bSKent Overstreet return 0; 1961c6fdbd8SKent Overstreet } 1971c6fdbd8SKent Overstreet 1981c6fdbd8SKent Overstreet struct bch_csum bch2_checksum(struct bch_fs *c, unsigned type, 1991c6fdbd8SKent Overstreet struct nonce nonce, const void *data, size_t len) 2001c6fdbd8SKent Overstreet { 2011c6fdbd8SKent Overstreet switch (type) { 2026404dcc9SKent Overstreet case BCH_CSUM_none: 2036404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2046404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2056404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2066404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2076404dcc9SKent Overstreet case BCH_CSUM_crc64: { 20880ff5d18Sjpsollie struct bch2_checksum_state state; 2091c6fdbd8SKent Overstreet 21080ff5d18Sjpsollie state.type = type; 2111c6fdbd8SKent Overstreet 21280ff5d18Sjpsollie bch2_checksum_init(&state); 21380ff5d18Sjpsollie bch2_checksum_update(&state, data, len); 21480ff5d18Sjpsollie 21580ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2161c6fdbd8SKent Overstreet } 2171c6fdbd8SKent Overstreet 2186404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2196404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2201c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2211c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2221c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2231c6fdbd8SKent Overstreet 2241c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2251c6fdbd8SKent Overstreet 2261c6fdbd8SKent Overstreet crypto_shash_update(desc, data, len); 2271c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 2281c6fdbd8SKent Overstreet 2291c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 2301c6fdbd8SKent Overstreet return ret; 2311c6fdbd8SKent Overstreet } 2321c6fdbd8SKent Overstreet default: 2331c6fdbd8SKent Overstreet BUG(); 2341c6fdbd8SKent Overstreet } 2351c6fdbd8SKent Overstreet } 2361c6fdbd8SKent Overstreet 237a9de137bSKent Overstreet int bch2_encrypt(struct bch_fs *c, unsigned type, 2381c6fdbd8SKent Overstreet struct nonce nonce, void *data, size_t len) 2391c6fdbd8SKent Overstreet { 2401c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 241a9de137bSKent Overstreet return 0; 2421c6fdbd8SKent Overstreet 243a9de137bSKent Overstreet return do_encrypt(c->chacha20, nonce, data, len); 2441c6fdbd8SKent Overstreet } 2451c6fdbd8SKent Overstreet 2461c6fdbd8SKent Overstreet static struct bch_csum __bch2_checksum_bio(struct bch_fs *c, unsigned type, 2471c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio, 2481c6fdbd8SKent Overstreet struct bvec_iter *iter) 2491c6fdbd8SKent Overstreet { 2501c6fdbd8SKent Overstreet struct bio_vec bv; 2511c6fdbd8SKent Overstreet 2521c6fdbd8SKent Overstreet switch (type) { 2536404dcc9SKent Overstreet case BCH_CSUM_none: 2541c6fdbd8SKent Overstreet return (struct bch_csum) { 0 }; 2556404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2566404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2576404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2586404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2596404dcc9SKent Overstreet case BCH_CSUM_crc64: { 26080ff5d18Sjpsollie struct bch2_checksum_state state; 26180ff5d18Sjpsollie 26280ff5d18Sjpsollie state.type = type; 26380ff5d18Sjpsollie bch2_checksum_init(&state); 2641c6fdbd8SKent Overstreet 2651c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 2661c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 2671c6fdbd8SKent Overstreet void *p = kmap_atomic(bv.bv_page) + bv.bv_offset; 26880ff5d18Sjpsollie bch2_checksum_update(&state, p, bv.bv_len); 2691c6fdbd8SKent Overstreet kunmap_atomic(p); 2701c6fdbd8SKent Overstreet } 2711c6fdbd8SKent Overstreet #else 2720fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 27380ff5d18Sjpsollie bch2_checksum_update(&state, page_address(bv.bv_page) + bv.bv_offset, 2741c6fdbd8SKent Overstreet bv.bv_len); 2751c6fdbd8SKent Overstreet #endif 27680ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2771c6fdbd8SKent Overstreet } 2781c6fdbd8SKent Overstreet 2796404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2806404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2811c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2821c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2831c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2841c6fdbd8SKent Overstreet 2851c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2861c6fdbd8SKent Overstreet 2871c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 2881c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 2891c6fdbd8SKent Overstreet void *p = kmap_atomic(bv.bv_page) + bv.bv_offset; 2901c6fdbd8SKent Overstreet 2911c6fdbd8SKent Overstreet crypto_shash_update(desc, p, bv.bv_len); 2921c6fdbd8SKent Overstreet kunmap_atomic(p); 2931c6fdbd8SKent Overstreet } 2941c6fdbd8SKent Overstreet #else 2950fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 2961c6fdbd8SKent Overstreet crypto_shash_update(desc, 2971c6fdbd8SKent Overstreet page_address(bv.bv_page) + bv.bv_offset, 2981c6fdbd8SKent Overstreet bv.bv_len); 2991c6fdbd8SKent Overstreet #endif 3001c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 3011c6fdbd8SKent Overstreet 3021c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 3031c6fdbd8SKent Overstreet return ret; 3041c6fdbd8SKent Overstreet } 3051c6fdbd8SKent Overstreet default: 3061c6fdbd8SKent Overstreet BUG(); 3071c6fdbd8SKent Overstreet } 3081c6fdbd8SKent Overstreet } 3091c6fdbd8SKent Overstreet 3101c6fdbd8SKent Overstreet struct bch_csum bch2_checksum_bio(struct bch_fs *c, unsigned type, 3111c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3121c6fdbd8SKent Overstreet { 3131c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 3141c6fdbd8SKent Overstreet 3151c6fdbd8SKent Overstreet return __bch2_checksum_bio(c, type, nonce, bio, &iter); 3161c6fdbd8SKent Overstreet } 3171c6fdbd8SKent Overstreet 318a9de137bSKent Overstreet int bch2_encrypt_bio(struct bch_fs *c, unsigned type, 3191c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3201c6fdbd8SKent Overstreet { 3211c6fdbd8SKent Overstreet struct bio_vec bv; 3221c6fdbd8SKent Overstreet struct bvec_iter iter; 3231c6fdbd8SKent Overstreet struct scatterlist sgl[16], *sg = sgl; 3241c6fdbd8SKent Overstreet size_t bytes = 0; 325a9de137bSKent Overstreet int ret = 0; 3261c6fdbd8SKent Overstreet 3271c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 328a9de137bSKent Overstreet return 0; 3291c6fdbd8SKent Overstreet 3301c6fdbd8SKent Overstreet sg_init_table(sgl, ARRAY_SIZE(sgl)); 3311c6fdbd8SKent Overstreet 3321c6fdbd8SKent Overstreet bio_for_each_segment(bv, bio, iter) { 3331c6fdbd8SKent Overstreet if (sg == sgl + ARRAY_SIZE(sgl)) { 3341c6fdbd8SKent Overstreet sg_mark_end(sg - 1); 335a9de137bSKent Overstreet 336a9de137bSKent Overstreet ret = do_encrypt_sg(c->chacha20, nonce, sgl, bytes); 337a9de137bSKent Overstreet if (ret) 338a9de137bSKent Overstreet return ret; 3391c6fdbd8SKent Overstreet 3401c6fdbd8SKent Overstreet nonce = nonce_add(nonce, bytes); 3411c6fdbd8SKent Overstreet bytes = 0; 3421c6fdbd8SKent Overstreet 3431c6fdbd8SKent Overstreet sg_init_table(sgl, ARRAY_SIZE(sgl)); 3441c6fdbd8SKent Overstreet sg = sgl; 3451c6fdbd8SKent Overstreet } 3461c6fdbd8SKent Overstreet 3471c6fdbd8SKent Overstreet sg_set_page(sg++, bv.bv_page, bv.bv_len, bv.bv_offset); 3481c6fdbd8SKent Overstreet bytes += bv.bv_len; 3491c6fdbd8SKent Overstreet } 3501c6fdbd8SKent Overstreet 3511c6fdbd8SKent Overstreet sg_mark_end(sg - 1); 352a9de137bSKent Overstreet return do_encrypt_sg(c->chacha20, nonce, sgl, bytes); 3531c6fdbd8SKent Overstreet } 3541c6fdbd8SKent Overstreet 3556009b4e5SKent Overstreet struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, 3561c6fdbd8SKent Overstreet struct bch_csum b, size_t b_len) 3571c6fdbd8SKent Overstreet { 35880ff5d18Sjpsollie struct bch2_checksum_state state; 35980ff5d18Sjpsollie 36080ff5d18Sjpsollie state.type = type; 36180ff5d18Sjpsollie bch2_checksum_init(&state); 36280ff5d18Sjpsollie state.seed = a.lo; 36380ff5d18Sjpsollie 3641c6fdbd8SKent Overstreet BUG_ON(!bch2_checksum_mergeable(type)); 3651c6fdbd8SKent Overstreet 3661c6fdbd8SKent Overstreet while (b_len) { 3671c6fdbd8SKent Overstreet unsigned b = min_t(unsigned, b_len, PAGE_SIZE); 3681c6fdbd8SKent Overstreet 36980ff5d18Sjpsollie bch2_checksum_update(&state, 3701c6fdbd8SKent Overstreet page_address(ZERO_PAGE(0)), b); 3711c6fdbd8SKent Overstreet b_len -= b; 3721c6fdbd8SKent Overstreet } 37380ff5d18Sjpsollie a.lo = bch2_checksum_final(&state); 3741c6fdbd8SKent Overstreet a.lo ^= b.lo; 3751c6fdbd8SKent Overstreet a.hi ^= b.hi; 3761c6fdbd8SKent Overstreet return a; 3771c6fdbd8SKent Overstreet } 3781c6fdbd8SKent Overstreet 3791c6fdbd8SKent Overstreet int bch2_rechecksum_bio(struct bch_fs *c, struct bio *bio, 3801c6fdbd8SKent Overstreet struct bversion version, 3811c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked crc_old, 3821c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_a, 3831c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_b, 3841c6fdbd8SKent Overstreet unsigned len_a, unsigned len_b, 3851c6fdbd8SKent Overstreet unsigned new_csum_type) 3861c6fdbd8SKent Overstreet { 3871c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 3881c6fdbd8SKent Overstreet struct nonce nonce = extent_nonce(version, crc_old); 3891c6fdbd8SKent Overstreet struct bch_csum merged = { 0 }; 3901c6fdbd8SKent Overstreet struct crc_split { 3911c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc; 3921c6fdbd8SKent Overstreet unsigned len; 3931c6fdbd8SKent Overstreet unsigned csum_type; 3941c6fdbd8SKent Overstreet struct bch_csum csum; 3951c6fdbd8SKent Overstreet } splits[3] = { 3961c6fdbd8SKent Overstreet { crc_a, len_a, new_csum_type }, 3971c6fdbd8SKent Overstreet { crc_b, len_b, new_csum_type }, 3981c6fdbd8SKent Overstreet { NULL, bio_sectors(bio) - len_a - len_b, new_csum_type }, 3991c6fdbd8SKent Overstreet }, *i; 4001c6fdbd8SKent Overstreet bool mergeable = crc_old.csum_type == new_csum_type && 4011c6fdbd8SKent Overstreet bch2_checksum_mergeable(new_csum_type); 4021c6fdbd8SKent Overstreet unsigned crc_nonce = crc_old.nonce; 4031c6fdbd8SKent Overstreet 4041c6fdbd8SKent Overstreet BUG_ON(len_a + len_b > bio_sectors(bio)); 4051c6fdbd8SKent Overstreet BUG_ON(crc_old.uncompressed_size != bio_sectors(bio)); 406ab05de4cSKent Overstreet BUG_ON(crc_is_compressed(crc_old)); 4071c6fdbd8SKent Overstreet BUG_ON(bch2_csum_type_is_encryption(crc_old.csum_type) != 4081c6fdbd8SKent Overstreet bch2_csum_type_is_encryption(new_csum_type)); 4091c6fdbd8SKent Overstreet 4101c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4111c6fdbd8SKent Overstreet iter.bi_size = i->len << 9; 4121c6fdbd8SKent Overstreet if (mergeable || i->crc) 4131c6fdbd8SKent Overstreet i->csum = __bch2_checksum_bio(c, i->csum_type, 4141c6fdbd8SKent Overstreet nonce, bio, &iter); 4151c6fdbd8SKent Overstreet else 4161c6fdbd8SKent Overstreet bio_advance_iter(bio, &iter, i->len << 9); 4171c6fdbd8SKent Overstreet nonce = nonce_add(nonce, i->len << 9); 4181c6fdbd8SKent Overstreet } 4191c6fdbd8SKent Overstreet 4201c6fdbd8SKent Overstreet if (mergeable) 4211c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) 4221c6fdbd8SKent Overstreet merged = bch2_checksum_merge(new_csum_type, merged, 4231c6fdbd8SKent Overstreet i->csum, i->len << 9); 4241c6fdbd8SKent Overstreet else 4251c6fdbd8SKent Overstreet merged = bch2_checksum_bio(c, crc_old.csum_type, 4261c6fdbd8SKent Overstreet extent_nonce(version, crc_old), bio); 4271c6fdbd8SKent Overstreet 4281c6fdbd8SKent Overstreet if (bch2_crc_cmp(merged, crc_old.csum)) 4291c6fdbd8SKent Overstreet return -EIO; 4301c6fdbd8SKent Overstreet 4311c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4321c6fdbd8SKent Overstreet if (i->crc) 4331c6fdbd8SKent Overstreet *i->crc = (struct bch_extent_crc_unpacked) { 4341c6fdbd8SKent Overstreet .csum_type = i->csum_type, 435ab05de4cSKent Overstreet .compression_type = crc_old.compression_type, 4361c6fdbd8SKent Overstreet .compressed_size = i->len, 4371c6fdbd8SKent Overstreet .uncompressed_size = i->len, 4381c6fdbd8SKent Overstreet .offset = 0, 4391c6fdbd8SKent Overstreet .live_size = i->len, 4401c6fdbd8SKent Overstreet .nonce = crc_nonce, 4411c6fdbd8SKent Overstreet .csum = i->csum, 4421c6fdbd8SKent Overstreet }; 4431c6fdbd8SKent Overstreet 4441c6fdbd8SKent Overstreet if (bch2_csum_type_is_encryption(new_csum_type)) 4451c6fdbd8SKent Overstreet crc_nonce += i->len; 4461c6fdbd8SKent Overstreet } 4471c6fdbd8SKent Overstreet 4481c6fdbd8SKent Overstreet return 0; 4491c6fdbd8SKent Overstreet } 4501c6fdbd8SKent Overstreet 4511c6fdbd8SKent Overstreet #ifdef __KERNEL__ 45203ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 4531c6fdbd8SKent Overstreet { 4541c6fdbd8SKent Overstreet struct key *keyring_key; 4551c6fdbd8SKent Overstreet const struct user_key_payload *ukp; 4561c6fdbd8SKent Overstreet int ret; 4571c6fdbd8SKent Overstreet 458232697abSKent Overstreet keyring_key = request_key(&key_type_user, key_description, NULL); 4591c6fdbd8SKent Overstreet if (IS_ERR(keyring_key)) 4601c6fdbd8SKent Overstreet return PTR_ERR(keyring_key); 4611c6fdbd8SKent Overstreet 4621c6fdbd8SKent Overstreet down_read(&keyring_key->sem); 4631c6fdbd8SKent Overstreet ukp = dereference_key_locked(keyring_key); 4641c6fdbd8SKent Overstreet if (ukp->datalen == sizeof(*key)) { 4651c6fdbd8SKent Overstreet memcpy(key, ukp->data, ukp->datalen); 4661c6fdbd8SKent Overstreet ret = 0; 4671c6fdbd8SKent Overstreet } else { 4681c6fdbd8SKent Overstreet ret = -EINVAL; 4691c6fdbd8SKent Overstreet } 4701c6fdbd8SKent Overstreet up_read(&keyring_key->sem); 4711c6fdbd8SKent Overstreet key_put(keyring_key); 4721c6fdbd8SKent Overstreet 4731c6fdbd8SKent Overstreet return ret; 4741c6fdbd8SKent Overstreet } 4751c6fdbd8SKent Overstreet #else 4761c6fdbd8SKent Overstreet #include <keyutils.h> 4771c6fdbd8SKent Overstreet 47803ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 4791c6fdbd8SKent Overstreet { 4801c6fdbd8SKent Overstreet key_serial_t key_id; 4811c6fdbd8SKent Overstreet 4821c6fdbd8SKent Overstreet key_id = request_key("user", key_description, NULL, 4831c6fdbd8SKent Overstreet KEY_SPEC_USER_KEYRING); 4841c6fdbd8SKent Overstreet if (key_id < 0) 4851c6fdbd8SKent Overstreet return -errno; 4861c6fdbd8SKent Overstreet 4871c6fdbd8SKent Overstreet if (keyctl_read(key_id, (void *) key, sizeof(*key)) != sizeof(*key)) 4881c6fdbd8SKent Overstreet return -1; 4891c6fdbd8SKent Overstreet 4901c6fdbd8SKent Overstreet return 0; 4911c6fdbd8SKent Overstreet } 4921c6fdbd8SKent Overstreet #endif 4931c6fdbd8SKent Overstreet 49403ea3962SKent Overstreet int bch2_request_key(struct bch_sb *sb, struct bch_key *key) 49503ea3962SKent Overstreet { 496*401ec4dbSKent Overstreet struct printbuf key_description = PRINTBUF; 497*401ec4dbSKent Overstreet int ret; 49803ea3962SKent Overstreet 499*401ec4dbSKent Overstreet prt_printf(&key_description, "bcachefs:"); 500*401ec4dbSKent Overstreet pr_uuid(&key_description, sb->user_uuid.b); 50103ea3962SKent Overstreet 502*401ec4dbSKent Overstreet ret = __bch2_request_key(key_description.buf, key); 503*401ec4dbSKent Overstreet printbuf_exit(&key_description); 504*401ec4dbSKent Overstreet return ret; 50503ea3962SKent Overstreet } 50603ea3962SKent Overstreet 5071c6fdbd8SKent Overstreet int bch2_decrypt_sb_key(struct bch_fs *c, 5081c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt, 5091c6fdbd8SKent Overstreet struct bch_key *key) 5101c6fdbd8SKent Overstreet { 5111c6fdbd8SKent Overstreet struct bch_encrypted_key sb_key = crypt->key; 5121c6fdbd8SKent Overstreet struct bch_key user_key; 5131c6fdbd8SKent Overstreet int ret = 0; 5141c6fdbd8SKent Overstreet 5151c6fdbd8SKent Overstreet /* is key encrypted? */ 5161c6fdbd8SKent Overstreet if (!bch2_key_is_encrypted(&sb_key)) 5171c6fdbd8SKent Overstreet goto out; 5181c6fdbd8SKent Overstreet 5191c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 5201c6fdbd8SKent Overstreet if (ret) { 5211c6fdbd8SKent Overstreet bch_err(c, "error requesting encryption key: %i", ret); 5221c6fdbd8SKent Overstreet goto err; 5231c6fdbd8SKent Overstreet } 5241c6fdbd8SKent Overstreet 5251c6fdbd8SKent Overstreet /* decrypt real key: */ 5261c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 5271c6fdbd8SKent Overstreet &sb_key, sizeof(sb_key)); 5281c6fdbd8SKent Overstreet if (ret) 5291c6fdbd8SKent Overstreet goto err; 5301c6fdbd8SKent Overstreet 5311c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&sb_key)) { 5321c6fdbd8SKent Overstreet bch_err(c, "incorrect encryption key"); 5331c6fdbd8SKent Overstreet ret = -EINVAL; 5341c6fdbd8SKent Overstreet goto err; 5351c6fdbd8SKent Overstreet } 5361c6fdbd8SKent Overstreet out: 5371c6fdbd8SKent Overstreet *key = sb_key.key; 5381c6fdbd8SKent Overstreet err: 5391c6fdbd8SKent Overstreet memzero_explicit(&sb_key, sizeof(sb_key)); 5401c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 5411c6fdbd8SKent Overstreet return ret; 5421c6fdbd8SKent Overstreet } 5431c6fdbd8SKent Overstreet 5441c6fdbd8SKent Overstreet static int bch2_alloc_ciphers(struct bch_fs *c) 5451c6fdbd8SKent Overstreet { 5461c6fdbd8SKent Overstreet if (!c->chacha20) 5471c6fdbd8SKent Overstreet c->chacha20 = crypto_alloc_sync_skcipher("chacha20", 0, 0); 5481c6fdbd8SKent Overstreet if (IS_ERR(c->chacha20)) { 5491c6fdbd8SKent Overstreet bch_err(c, "error requesting chacha20 module: %li", 5501c6fdbd8SKent Overstreet PTR_ERR(c->chacha20)); 5511c6fdbd8SKent Overstreet return PTR_ERR(c->chacha20); 5521c6fdbd8SKent Overstreet } 5531c6fdbd8SKent Overstreet 5541c6fdbd8SKent Overstreet if (!c->poly1305) 5551c6fdbd8SKent Overstreet c->poly1305 = crypto_alloc_shash("poly1305", 0, 0); 5561c6fdbd8SKent Overstreet if (IS_ERR(c->poly1305)) { 5571c6fdbd8SKent Overstreet bch_err(c, "error requesting poly1305 module: %li", 5581c6fdbd8SKent Overstreet PTR_ERR(c->poly1305)); 5591c6fdbd8SKent Overstreet return PTR_ERR(c->poly1305); 5601c6fdbd8SKent Overstreet } 5611c6fdbd8SKent Overstreet 5621c6fdbd8SKent Overstreet return 0; 5631c6fdbd8SKent Overstreet } 5641c6fdbd8SKent Overstreet 5651c6fdbd8SKent Overstreet int bch2_disable_encryption(struct bch_fs *c) 5661c6fdbd8SKent Overstreet { 5671c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 5681c6fdbd8SKent Overstreet struct bch_key key; 5691c6fdbd8SKent Overstreet int ret = -EINVAL; 5701c6fdbd8SKent Overstreet 5711c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 5721c6fdbd8SKent Overstreet 5731c6fdbd8SKent Overstreet crypt = bch2_sb_get_crypt(c->disk_sb.sb); 5741c6fdbd8SKent Overstreet if (!crypt) 5751c6fdbd8SKent Overstreet goto out; 5761c6fdbd8SKent Overstreet 5771c6fdbd8SKent Overstreet /* is key encrypted? */ 5781c6fdbd8SKent Overstreet ret = 0; 5791c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&crypt->key)) 5801c6fdbd8SKent Overstreet goto out; 5811c6fdbd8SKent Overstreet 5821c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 5831c6fdbd8SKent Overstreet if (ret) 5841c6fdbd8SKent Overstreet goto out; 5851c6fdbd8SKent Overstreet 5861c6fdbd8SKent Overstreet crypt->key.magic = BCH_KEY_MAGIC; 5871c6fdbd8SKent Overstreet crypt->key.key = key; 5881c6fdbd8SKent Overstreet 5891c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 0); 5901c6fdbd8SKent Overstreet bch2_write_super(c); 5911c6fdbd8SKent Overstreet out: 5921c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 5931c6fdbd8SKent Overstreet 5941c6fdbd8SKent Overstreet return ret; 5951c6fdbd8SKent Overstreet } 5961c6fdbd8SKent Overstreet 5971c6fdbd8SKent Overstreet int bch2_enable_encryption(struct bch_fs *c, bool keyed) 5981c6fdbd8SKent Overstreet { 5991c6fdbd8SKent Overstreet struct bch_encrypted_key key; 6001c6fdbd8SKent Overstreet struct bch_key user_key; 6011c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 6021c6fdbd8SKent Overstreet int ret = -EINVAL; 6031c6fdbd8SKent Overstreet 6041c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 6051c6fdbd8SKent Overstreet 6061c6fdbd8SKent Overstreet /* Do we already have an encryption key? */ 6071c6fdbd8SKent Overstreet if (bch2_sb_get_crypt(c->disk_sb.sb)) 6081c6fdbd8SKent Overstreet goto err; 6091c6fdbd8SKent Overstreet 6101c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 6111c6fdbd8SKent Overstreet if (ret) 6121c6fdbd8SKent Overstreet goto err; 6131c6fdbd8SKent Overstreet 6141c6fdbd8SKent Overstreet key.magic = BCH_KEY_MAGIC; 6151c6fdbd8SKent Overstreet get_random_bytes(&key.key, sizeof(key.key)); 6161c6fdbd8SKent Overstreet 6171c6fdbd8SKent Overstreet if (keyed) { 6181c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 6191c6fdbd8SKent Overstreet if (ret) { 6201c6fdbd8SKent Overstreet bch_err(c, "error requesting encryption key: %i", ret); 6211c6fdbd8SKent Overstreet goto err; 6221c6fdbd8SKent Overstreet } 6231c6fdbd8SKent Overstreet 6241c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 6251c6fdbd8SKent Overstreet &key, sizeof(key)); 6261c6fdbd8SKent Overstreet if (ret) 6271c6fdbd8SKent Overstreet goto err; 6281c6fdbd8SKent Overstreet } 6291c6fdbd8SKent Overstreet 6301c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 6311c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 6321c6fdbd8SKent Overstreet if (ret) 6331c6fdbd8SKent Overstreet goto err; 6341c6fdbd8SKent Overstreet 6351c6fdbd8SKent Overstreet crypt = bch2_sb_resize_crypt(&c->disk_sb, sizeof(*crypt) / sizeof(u64)); 6361c6fdbd8SKent Overstreet if (!crypt) { 6371c6fdbd8SKent Overstreet ret = -ENOMEM; /* XXX this technically could be -ENOSPC */ 6381c6fdbd8SKent Overstreet goto err; 6391c6fdbd8SKent Overstreet } 6401c6fdbd8SKent Overstreet 6411c6fdbd8SKent Overstreet crypt->key = key; 6421c6fdbd8SKent Overstreet 6431c6fdbd8SKent Overstreet /* write superblock */ 6441c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 1); 6451c6fdbd8SKent Overstreet bch2_write_super(c); 6461c6fdbd8SKent Overstreet err: 6471c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 6481c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 6491c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 6501c6fdbd8SKent Overstreet return ret; 6511c6fdbd8SKent Overstreet } 6521c6fdbd8SKent Overstreet 6531c6fdbd8SKent Overstreet void bch2_fs_encryption_exit(struct bch_fs *c) 6541c6fdbd8SKent Overstreet { 6551c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->poly1305)) 6561c6fdbd8SKent Overstreet crypto_free_shash(c->poly1305); 6571c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->chacha20)) 6581c6fdbd8SKent Overstreet crypto_free_sync_skcipher(c->chacha20); 6591c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->sha256)) 6601c6fdbd8SKent Overstreet crypto_free_shash(c->sha256); 6611c6fdbd8SKent Overstreet } 6621c6fdbd8SKent Overstreet 6631c6fdbd8SKent Overstreet int bch2_fs_encryption_init(struct bch_fs *c) 6641c6fdbd8SKent Overstreet { 6651c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 6661c6fdbd8SKent Overstreet struct bch_key key; 6671c6fdbd8SKent Overstreet int ret = 0; 6681c6fdbd8SKent Overstreet 6691c6fdbd8SKent Overstreet pr_verbose_init(c->opts, ""); 6701c6fdbd8SKent Overstreet 6711c6fdbd8SKent Overstreet c->sha256 = crypto_alloc_shash("sha256", 0, 0); 6721c6fdbd8SKent Overstreet if (IS_ERR(c->sha256)) { 6731c6fdbd8SKent Overstreet bch_err(c, "error requesting sha256 module"); 6741c6fdbd8SKent Overstreet ret = PTR_ERR(c->sha256); 6751c6fdbd8SKent Overstreet goto out; 6761c6fdbd8SKent Overstreet } 6771c6fdbd8SKent Overstreet 6781c6fdbd8SKent Overstreet crypt = bch2_sb_get_crypt(c->disk_sb.sb); 6791c6fdbd8SKent Overstreet if (!crypt) 6801c6fdbd8SKent Overstreet goto out; 6811c6fdbd8SKent Overstreet 6821c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 6831c6fdbd8SKent Overstreet if (ret) 6841c6fdbd8SKent Overstreet goto out; 6851c6fdbd8SKent Overstreet 6861c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 6871c6fdbd8SKent Overstreet if (ret) 6881c6fdbd8SKent Overstreet goto out; 6891c6fdbd8SKent Overstreet 6901c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 6911c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 6921c6fdbd8SKent Overstreet if (ret) 6931c6fdbd8SKent Overstreet goto out; 6941c6fdbd8SKent Overstreet out: 6951c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 6961c6fdbd8SKent Overstreet pr_verbose_init(c->opts, "ret %i", ret); 6971c6fdbd8SKent Overstreet return ret; 6981c6fdbd8SKent Overstreet } 699