11c6fdbd8SKent Overstreet // SPDX-License-Identifier: GPL-2.0 21c6fdbd8SKent Overstreet #include "bcachefs.h" 31c6fdbd8SKent Overstreet #include "checksum.h" 4d4bf5eecSKent Overstreet #include "errcode.h" 51c6fdbd8SKent Overstreet #include "super.h" 61c6fdbd8SKent Overstreet #include "super-io.h" 71c6fdbd8SKent Overstreet 81c6fdbd8SKent Overstreet #include <linux/crc32c.h> 91c6fdbd8SKent Overstreet #include <linux/crypto.h> 1041e63382Sjpsollie #include <linux/xxhash.h> 111c6fdbd8SKent Overstreet #include <linux/key.h> 121c6fdbd8SKent Overstreet #include <linux/random.h> 131c6fdbd8SKent Overstreet #include <linux/scatterlist.h> 141c6fdbd8SKent Overstreet #include <crypto/algapi.h> 151c6fdbd8SKent Overstreet #include <crypto/chacha.h> 161c6fdbd8SKent Overstreet #include <crypto/hash.h> 171c6fdbd8SKent Overstreet #include <crypto/poly1305.h> 181c6fdbd8SKent Overstreet #include <crypto/skcipher.h> 191c6fdbd8SKent Overstreet #include <keys/user-type.h> 201c6fdbd8SKent Overstreet 2180ff5d18Sjpsollie /* 2280ff5d18Sjpsollie * bch2_checksum state is an abstraction of the checksum state calculated over different pages. 2380ff5d18Sjpsollie * it features page merging without having the checksum algorithm lose its state. 2480ff5d18Sjpsollie * for native checksum aglorithms (like crc), a default seed value will do. 2580ff5d18Sjpsollie * for hash-like algorithms, a state needs to be stored 2680ff5d18Sjpsollie */ 2780ff5d18Sjpsollie 2880ff5d18Sjpsollie struct bch2_checksum_state { 2980ff5d18Sjpsollie union { 3080ff5d18Sjpsollie u64 seed; 3141e63382Sjpsollie struct xxh64_state h64state; 3280ff5d18Sjpsollie }; 3380ff5d18Sjpsollie unsigned int type; 3480ff5d18Sjpsollie }; 3580ff5d18Sjpsollie 3680ff5d18Sjpsollie static void bch2_checksum_init(struct bch2_checksum_state *state) 371c6fdbd8SKent Overstreet { 3880ff5d18Sjpsollie switch (state->type) { 396404dcc9SKent Overstreet case BCH_CSUM_none: 406404dcc9SKent Overstreet case BCH_CSUM_crc32c: 416404dcc9SKent Overstreet case BCH_CSUM_crc64: 4280ff5d18Sjpsollie state->seed = 0; 4380ff5d18Sjpsollie break; 446404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 4580ff5d18Sjpsollie state->seed = U32_MAX; 4680ff5d18Sjpsollie break; 476404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 4880ff5d18Sjpsollie state->seed = U64_MAX; 4980ff5d18Sjpsollie break; 506404dcc9SKent Overstreet case BCH_CSUM_xxhash: 5141e63382Sjpsollie xxh64_reset(&state->h64state, 0); 5241e63382Sjpsollie break; 531c6fdbd8SKent Overstreet default: 541c6fdbd8SKent Overstreet BUG(); 551c6fdbd8SKent Overstreet } 561c6fdbd8SKent Overstreet } 571c6fdbd8SKent Overstreet 5880ff5d18Sjpsollie static u64 bch2_checksum_final(const struct bch2_checksum_state *state) 591c6fdbd8SKent Overstreet { 6080ff5d18Sjpsollie switch (state->type) { 616404dcc9SKent Overstreet case BCH_CSUM_none: 626404dcc9SKent Overstreet case BCH_CSUM_crc32c: 636404dcc9SKent Overstreet case BCH_CSUM_crc64: 6480ff5d18Sjpsollie return state->seed; 656404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 6680ff5d18Sjpsollie return state->seed ^ U32_MAX; 676404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 6880ff5d18Sjpsollie return state->seed ^ U64_MAX; 696404dcc9SKent Overstreet case BCH_CSUM_xxhash: 7041e63382Sjpsollie return xxh64_digest(&state->h64state); 711c6fdbd8SKent Overstreet default: 721c6fdbd8SKent Overstreet BUG(); 731c6fdbd8SKent Overstreet } 741c6fdbd8SKent Overstreet } 751c6fdbd8SKent Overstreet 7680ff5d18Sjpsollie static void bch2_checksum_update(struct bch2_checksum_state *state, const void *data, size_t len) 771c6fdbd8SKent Overstreet { 7880ff5d18Sjpsollie switch (state->type) { 796404dcc9SKent Overstreet case BCH_CSUM_none: 8080ff5d18Sjpsollie return; 816404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 826404dcc9SKent Overstreet case BCH_CSUM_crc32c: 8380ff5d18Sjpsollie state->seed = crc32c(state->seed, data, len); 8480ff5d18Sjpsollie break; 856404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 866404dcc9SKent Overstreet case BCH_CSUM_crc64: 8780ff5d18Sjpsollie state->seed = crc64_be(state->seed, data, len); 8880ff5d18Sjpsollie break; 896404dcc9SKent Overstreet case BCH_CSUM_xxhash: 9041e63382Sjpsollie xxh64_update(&state->h64state, data, len); 9141e63382Sjpsollie break; 921c6fdbd8SKent Overstreet default: 931c6fdbd8SKent Overstreet BUG(); 941c6fdbd8SKent Overstreet } 951c6fdbd8SKent Overstreet } 961c6fdbd8SKent Overstreet 97a9de137bSKent Overstreet static inline int do_encrypt_sg(struct crypto_sync_skcipher *tfm, 981c6fdbd8SKent Overstreet struct nonce nonce, 991c6fdbd8SKent Overstreet struct scatterlist *sg, size_t len) 1001c6fdbd8SKent Overstreet { 1011c6fdbd8SKent Overstreet SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); 1021c6fdbd8SKent Overstreet int ret; 1031c6fdbd8SKent Overstreet 1041c6fdbd8SKent Overstreet skcipher_request_set_sync_tfm(req, tfm); 1051c6fdbd8SKent Overstreet skcipher_request_set_crypt(req, sg, sg, len, nonce.d); 1061c6fdbd8SKent Overstreet 1071c6fdbd8SKent Overstreet ret = crypto_skcipher_encrypt(req); 108a9de137bSKent Overstreet if (ret) 109a9de137bSKent Overstreet pr_err("got error %i from crypto_skcipher_encrypt()", ret); 110a9de137bSKent Overstreet 111a9de137bSKent Overstreet return ret; 1121c6fdbd8SKent Overstreet } 1131c6fdbd8SKent Overstreet 114a9de137bSKent Overstreet static inline int do_encrypt(struct crypto_sync_skcipher *tfm, 1151c6fdbd8SKent Overstreet struct nonce nonce, 1161c6fdbd8SKent Overstreet void *buf, size_t len) 1171c6fdbd8SKent Overstreet { 118636d4eefSKent Overstreet if (!is_vmalloc_addr(buf)) { 1191c6fdbd8SKent Overstreet struct scatterlist sg; 1201c6fdbd8SKent Overstreet 121c346def9SKent Overstreet sg_init_table(&sg, 1); 122c346def9SKent Overstreet sg_set_page(&sg, 123c346def9SKent Overstreet is_vmalloc_addr(buf) 124c346def9SKent Overstreet ? vmalloc_to_page(buf) 125c346def9SKent Overstreet : virt_to_page(buf), 126c346def9SKent Overstreet len, offset_in_page(buf)); 127a9de137bSKent Overstreet return do_encrypt_sg(tfm, nonce, &sg, len); 128636d4eefSKent Overstreet } else { 129636d4eefSKent Overstreet unsigned pages = buf_pages(buf, len); 130636d4eefSKent Overstreet struct scatterlist *sg; 131636d4eefSKent Overstreet size_t orig_len = len; 132636d4eefSKent Overstreet int ret, i; 133636d4eefSKent Overstreet 1343e3e02e6SKent Overstreet sg = kmalloc_array(pages, sizeof(*sg), GFP_KERNEL); 135636d4eefSKent Overstreet if (!sg) 13665d48e35SKent Overstreet return -BCH_ERR_ENOMEM_do_encrypt; 137636d4eefSKent Overstreet 138636d4eefSKent Overstreet sg_init_table(sg, pages); 139636d4eefSKent Overstreet 140636d4eefSKent Overstreet for (i = 0; i < pages; i++) { 141636d4eefSKent Overstreet unsigned offset = offset_in_page(buf); 142636d4eefSKent Overstreet unsigned pg_len = min(len, PAGE_SIZE - offset); 143636d4eefSKent Overstreet 144636d4eefSKent Overstreet sg_set_page(sg + i, vmalloc_to_page(buf), pg_len, offset); 145636d4eefSKent Overstreet buf += pg_len; 146636d4eefSKent Overstreet len -= pg_len; 147636d4eefSKent Overstreet } 148636d4eefSKent Overstreet 149636d4eefSKent Overstreet ret = do_encrypt_sg(tfm, nonce, sg, orig_len); 150636d4eefSKent Overstreet kfree(sg); 151636d4eefSKent Overstreet return ret; 152636d4eefSKent Overstreet } 1531c6fdbd8SKent Overstreet } 1541c6fdbd8SKent Overstreet 1551c6fdbd8SKent Overstreet int bch2_chacha_encrypt_key(struct bch_key *key, struct nonce nonce, 1561c6fdbd8SKent Overstreet void *buf, size_t len) 1571c6fdbd8SKent Overstreet { 1581c6fdbd8SKent Overstreet struct crypto_sync_skcipher *chacha20 = 1591c6fdbd8SKent Overstreet crypto_alloc_sync_skcipher("chacha20", 0, 0); 1601c6fdbd8SKent Overstreet int ret; 1611c6fdbd8SKent Overstreet 1621c6fdbd8SKent Overstreet if (!chacha20) { 1631c6fdbd8SKent Overstreet pr_err("error requesting chacha20 module: %li", PTR_ERR(chacha20)); 1641c6fdbd8SKent Overstreet return PTR_ERR(chacha20); 1651c6fdbd8SKent Overstreet } 1661c6fdbd8SKent Overstreet 1671c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&chacha20->base, 1681c6fdbd8SKent Overstreet (void *) key, sizeof(*key)); 1691c6fdbd8SKent Overstreet if (ret) { 1701c6fdbd8SKent Overstreet pr_err("crypto_skcipher_setkey() error: %i", ret); 1711c6fdbd8SKent Overstreet goto err; 1721c6fdbd8SKent Overstreet } 1731c6fdbd8SKent Overstreet 174a9de137bSKent Overstreet ret = do_encrypt(chacha20, nonce, buf, len); 1751c6fdbd8SKent Overstreet err: 1761c6fdbd8SKent Overstreet crypto_free_sync_skcipher(chacha20); 1771c6fdbd8SKent Overstreet return ret; 1781c6fdbd8SKent Overstreet } 1791c6fdbd8SKent Overstreet 180a9de137bSKent Overstreet static int gen_poly_key(struct bch_fs *c, struct shash_desc *desc, 1811c6fdbd8SKent Overstreet struct nonce nonce) 1821c6fdbd8SKent Overstreet { 1831c6fdbd8SKent Overstreet u8 key[POLY1305_KEY_SIZE]; 184a9de137bSKent Overstreet int ret; 1851c6fdbd8SKent Overstreet 1861c6fdbd8SKent Overstreet nonce.d[3] ^= BCH_NONCE_POLY; 1871c6fdbd8SKent Overstreet 1881c6fdbd8SKent Overstreet memset(key, 0, sizeof(key)); 189a9de137bSKent Overstreet ret = do_encrypt(c->chacha20, nonce, key, sizeof(key)); 190a9de137bSKent Overstreet if (ret) 191a9de137bSKent Overstreet return ret; 1921c6fdbd8SKent Overstreet 1931c6fdbd8SKent Overstreet desc->tfm = c->poly1305; 1941c6fdbd8SKent Overstreet crypto_shash_init(desc); 1951c6fdbd8SKent Overstreet crypto_shash_update(desc, key, sizeof(key)); 196a9de137bSKent Overstreet return 0; 1971c6fdbd8SKent Overstreet } 1981c6fdbd8SKent Overstreet 1991c6fdbd8SKent Overstreet struct bch_csum bch2_checksum(struct bch_fs *c, unsigned type, 2001c6fdbd8SKent Overstreet struct nonce nonce, const void *data, size_t len) 2011c6fdbd8SKent Overstreet { 2021c6fdbd8SKent Overstreet switch (type) { 2036404dcc9SKent Overstreet case BCH_CSUM_none: 2046404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2056404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2066404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2076404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2086404dcc9SKent Overstreet case BCH_CSUM_crc64: { 20980ff5d18Sjpsollie struct bch2_checksum_state state; 2101c6fdbd8SKent Overstreet 21180ff5d18Sjpsollie state.type = type; 2121c6fdbd8SKent Overstreet 21380ff5d18Sjpsollie bch2_checksum_init(&state); 21480ff5d18Sjpsollie bch2_checksum_update(&state, data, len); 21580ff5d18Sjpsollie 21680ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2171c6fdbd8SKent Overstreet } 2181c6fdbd8SKent Overstreet 2196404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2206404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2211c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2221c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2231c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2241c6fdbd8SKent Overstreet 2251c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2261c6fdbd8SKent Overstreet 2271c6fdbd8SKent Overstreet crypto_shash_update(desc, data, len); 2281c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 2291c6fdbd8SKent Overstreet 2301c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 2311c6fdbd8SKent Overstreet return ret; 2321c6fdbd8SKent Overstreet } 2331c6fdbd8SKent Overstreet default: 2341c6fdbd8SKent Overstreet BUG(); 2351c6fdbd8SKent Overstreet } 2361c6fdbd8SKent Overstreet } 2371c6fdbd8SKent Overstreet 238a9de137bSKent Overstreet int bch2_encrypt(struct bch_fs *c, unsigned type, 2391c6fdbd8SKent Overstreet struct nonce nonce, void *data, size_t len) 2401c6fdbd8SKent Overstreet { 2411c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 242a9de137bSKent Overstreet return 0; 2431c6fdbd8SKent Overstreet 244a9de137bSKent Overstreet return do_encrypt(c->chacha20, nonce, data, len); 2451c6fdbd8SKent Overstreet } 2461c6fdbd8SKent Overstreet 2471c6fdbd8SKent Overstreet static struct bch_csum __bch2_checksum_bio(struct bch_fs *c, unsigned type, 2481c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio, 2491c6fdbd8SKent Overstreet struct bvec_iter *iter) 2501c6fdbd8SKent Overstreet { 2511c6fdbd8SKent Overstreet struct bio_vec bv; 2521c6fdbd8SKent Overstreet 2531c6fdbd8SKent Overstreet switch (type) { 2546404dcc9SKent Overstreet case BCH_CSUM_none: 2551c6fdbd8SKent Overstreet return (struct bch_csum) { 0 }; 2566404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2576404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2586404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2596404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2606404dcc9SKent Overstreet case BCH_CSUM_crc64: { 26180ff5d18Sjpsollie struct bch2_checksum_state state; 26280ff5d18Sjpsollie 26380ff5d18Sjpsollie state.type = type; 26480ff5d18Sjpsollie bch2_checksum_init(&state); 2651c6fdbd8SKent Overstreet 2661c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 2671c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 2681c6fdbd8SKent Overstreet void *p = kmap_atomic(bv.bv_page) + bv.bv_offset; 26980ff5d18Sjpsollie bch2_checksum_update(&state, p, bv.bv_len); 2701c6fdbd8SKent Overstreet kunmap_atomic(p); 2711c6fdbd8SKent Overstreet } 2721c6fdbd8SKent Overstreet #else 2730fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 27480ff5d18Sjpsollie bch2_checksum_update(&state, page_address(bv.bv_page) + bv.bv_offset, 2751c6fdbd8SKent Overstreet bv.bv_len); 2761c6fdbd8SKent Overstreet #endif 27780ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2781c6fdbd8SKent Overstreet } 2791c6fdbd8SKent Overstreet 2806404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2816404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2821c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2831c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2841c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2851c6fdbd8SKent Overstreet 2861c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2871c6fdbd8SKent Overstreet 2881c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 2891c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 2901c6fdbd8SKent Overstreet void *p = kmap_atomic(bv.bv_page) + bv.bv_offset; 2911c6fdbd8SKent Overstreet 2921c6fdbd8SKent Overstreet crypto_shash_update(desc, p, bv.bv_len); 2931c6fdbd8SKent Overstreet kunmap_atomic(p); 2941c6fdbd8SKent Overstreet } 2951c6fdbd8SKent Overstreet #else 2960fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 2971c6fdbd8SKent Overstreet crypto_shash_update(desc, 2981c6fdbd8SKent Overstreet page_address(bv.bv_page) + bv.bv_offset, 2991c6fdbd8SKent Overstreet bv.bv_len); 3001c6fdbd8SKent Overstreet #endif 3011c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 3021c6fdbd8SKent Overstreet 3031c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 3041c6fdbd8SKent Overstreet return ret; 3051c6fdbd8SKent Overstreet } 3061c6fdbd8SKent Overstreet default: 3071c6fdbd8SKent Overstreet BUG(); 3081c6fdbd8SKent Overstreet } 3091c6fdbd8SKent Overstreet } 3101c6fdbd8SKent Overstreet 3111c6fdbd8SKent Overstreet struct bch_csum bch2_checksum_bio(struct bch_fs *c, unsigned type, 3121c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3131c6fdbd8SKent Overstreet { 3141c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 3151c6fdbd8SKent Overstreet 3161c6fdbd8SKent Overstreet return __bch2_checksum_bio(c, type, nonce, bio, &iter); 3171c6fdbd8SKent Overstreet } 3181c6fdbd8SKent Overstreet 3190cc455b3SKent Overstreet int __bch2_encrypt_bio(struct bch_fs *c, unsigned type, 3201c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3211c6fdbd8SKent Overstreet { 3221c6fdbd8SKent Overstreet struct bio_vec bv; 3231c6fdbd8SKent Overstreet struct bvec_iter iter; 3241c6fdbd8SKent Overstreet struct scatterlist sgl[16], *sg = sgl; 3251c6fdbd8SKent Overstreet size_t bytes = 0; 326a9de137bSKent Overstreet int ret = 0; 3271c6fdbd8SKent Overstreet 3281c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 329a9de137bSKent Overstreet return 0; 3301c6fdbd8SKent Overstreet 3311c6fdbd8SKent Overstreet sg_init_table(sgl, ARRAY_SIZE(sgl)); 3321c6fdbd8SKent Overstreet 3331c6fdbd8SKent Overstreet bio_for_each_segment(bv, bio, iter) { 3341c6fdbd8SKent Overstreet if (sg == sgl + ARRAY_SIZE(sgl)) { 3351c6fdbd8SKent Overstreet sg_mark_end(sg - 1); 336a9de137bSKent Overstreet 337a9de137bSKent Overstreet ret = do_encrypt_sg(c->chacha20, nonce, sgl, bytes); 338a9de137bSKent Overstreet if (ret) 339a9de137bSKent Overstreet return ret; 3401c6fdbd8SKent Overstreet 3411c6fdbd8SKent Overstreet nonce = nonce_add(nonce, bytes); 3421c6fdbd8SKent Overstreet bytes = 0; 3431c6fdbd8SKent Overstreet 3441c6fdbd8SKent Overstreet sg_init_table(sgl, ARRAY_SIZE(sgl)); 3451c6fdbd8SKent Overstreet sg = sgl; 3461c6fdbd8SKent Overstreet } 3471c6fdbd8SKent Overstreet 3481c6fdbd8SKent Overstreet sg_set_page(sg++, bv.bv_page, bv.bv_len, bv.bv_offset); 3491c6fdbd8SKent Overstreet bytes += bv.bv_len; 3501c6fdbd8SKent Overstreet } 3511c6fdbd8SKent Overstreet 3521c6fdbd8SKent Overstreet sg_mark_end(sg - 1); 353a9de137bSKent Overstreet return do_encrypt_sg(c->chacha20, nonce, sgl, bytes); 3541c6fdbd8SKent Overstreet } 3551c6fdbd8SKent Overstreet 3566009b4e5SKent Overstreet struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, 3571c6fdbd8SKent Overstreet struct bch_csum b, size_t b_len) 3581c6fdbd8SKent Overstreet { 35980ff5d18Sjpsollie struct bch2_checksum_state state; 36080ff5d18Sjpsollie 36180ff5d18Sjpsollie state.type = type; 36280ff5d18Sjpsollie bch2_checksum_init(&state); 363*73bd774dSKent Overstreet state.seed = (u64 __force) a.lo; 36480ff5d18Sjpsollie 3651c6fdbd8SKent Overstreet BUG_ON(!bch2_checksum_mergeable(type)); 3661c6fdbd8SKent Overstreet 3671c6fdbd8SKent Overstreet while (b_len) { 3681c6fdbd8SKent Overstreet unsigned b = min_t(unsigned, b_len, PAGE_SIZE); 3691c6fdbd8SKent Overstreet 37080ff5d18Sjpsollie bch2_checksum_update(&state, 3711c6fdbd8SKent Overstreet page_address(ZERO_PAGE(0)), b); 3721c6fdbd8SKent Overstreet b_len -= b; 3731c6fdbd8SKent Overstreet } 374*73bd774dSKent Overstreet a.lo = (__le64 __force) bch2_checksum_final(&state); 3751c6fdbd8SKent Overstreet a.lo ^= b.lo; 3761c6fdbd8SKent Overstreet a.hi ^= b.hi; 3771c6fdbd8SKent Overstreet return a; 3781c6fdbd8SKent Overstreet } 3791c6fdbd8SKent Overstreet 3801c6fdbd8SKent Overstreet int bch2_rechecksum_bio(struct bch_fs *c, struct bio *bio, 3811c6fdbd8SKent Overstreet struct bversion version, 3821c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked crc_old, 3831c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_a, 3841c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_b, 3851c6fdbd8SKent Overstreet unsigned len_a, unsigned len_b, 3861c6fdbd8SKent Overstreet unsigned new_csum_type) 3871c6fdbd8SKent Overstreet { 3881c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 3891c6fdbd8SKent Overstreet struct nonce nonce = extent_nonce(version, crc_old); 3901c6fdbd8SKent Overstreet struct bch_csum merged = { 0 }; 3911c6fdbd8SKent Overstreet struct crc_split { 3921c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc; 3931c6fdbd8SKent Overstreet unsigned len; 3941c6fdbd8SKent Overstreet unsigned csum_type; 3951c6fdbd8SKent Overstreet struct bch_csum csum; 3961c6fdbd8SKent Overstreet } splits[3] = { 3971c6fdbd8SKent Overstreet { crc_a, len_a, new_csum_type }, 3981c6fdbd8SKent Overstreet { crc_b, len_b, new_csum_type }, 3991c6fdbd8SKent Overstreet { NULL, bio_sectors(bio) - len_a - len_b, new_csum_type }, 4001c6fdbd8SKent Overstreet }, *i; 4011c6fdbd8SKent Overstreet bool mergeable = crc_old.csum_type == new_csum_type && 4021c6fdbd8SKent Overstreet bch2_checksum_mergeable(new_csum_type); 4031c6fdbd8SKent Overstreet unsigned crc_nonce = crc_old.nonce; 4041c6fdbd8SKent Overstreet 4051c6fdbd8SKent Overstreet BUG_ON(len_a + len_b > bio_sectors(bio)); 4061c6fdbd8SKent Overstreet BUG_ON(crc_old.uncompressed_size != bio_sectors(bio)); 407ab05de4cSKent Overstreet BUG_ON(crc_is_compressed(crc_old)); 4081c6fdbd8SKent Overstreet BUG_ON(bch2_csum_type_is_encryption(crc_old.csum_type) != 4091c6fdbd8SKent Overstreet bch2_csum_type_is_encryption(new_csum_type)); 4101c6fdbd8SKent Overstreet 4111c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4121c6fdbd8SKent Overstreet iter.bi_size = i->len << 9; 4131c6fdbd8SKent Overstreet if (mergeable || i->crc) 4141c6fdbd8SKent Overstreet i->csum = __bch2_checksum_bio(c, i->csum_type, 4151c6fdbd8SKent Overstreet nonce, bio, &iter); 4161c6fdbd8SKent Overstreet else 4171c6fdbd8SKent Overstreet bio_advance_iter(bio, &iter, i->len << 9); 4181c6fdbd8SKent Overstreet nonce = nonce_add(nonce, i->len << 9); 4191c6fdbd8SKent Overstreet } 4201c6fdbd8SKent Overstreet 4211c6fdbd8SKent Overstreet if (mergeable) 4221c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) 4231c6fdbd8SKent Overstreet merged = bch2_checksum_merge(new_csum_type, merged, 4241c6fdbd8SKent Overstreet i->csum, i->len << 9); 4251c6fdbd8SKent Overstreet else 4261c6fdbd8SKent Overstreet merged = bch2_checksum_bio(c, crc_old.csum_type, 4271c6fdbd8SKent Overstreet extent_nonce(version, crc_old), bio); 4281c6fdbd8SKent Overstreet 42923189da9SKent Overstreet if (bch2_crc_cmp(merged, crc_old.csum)) { 43023189da9SKent Overstreet bch_err(c, "checksum error in bch2_rechecksum_bio() (memory corruption or bug?)\n" 43123189da9SKent Overstreet "expected %0llx:%0llx got %0llx:%0llx (old type %s new type %s)", 43223189da9SKent Overstreet crc_old.csum.hi, 43323189da9SKent Overstreet crc_old.csum.lo, 43423189da9SKent Overstreet merged.hi, 43523189da9SKent Overstreet merged.lo, 43623189da9SKent Overstreet bch2_csum_types[crc_old.csum_type], 43723189da9SKent Overstreet bch2_csum_types[new_csum_type]); 4381c6fdbd8SKent Overstreet return -EIO; 43923189da9SKent Overstreet } 4401c6fdbd8SKent Overstreet 4411c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4421c6fdbd8SKent Overstreet if (i->crc) 4431c6fdbd8SKent Overstreet *i->crc = (struct bch_extent_crc_unpacked) { 4441c6fdbd8SKent Overstreet .csum_type = i->csum_type, 445ab05de4cSKent Overstreet .compression_type = crc_old.compression_type, 4461c6fdbd8SKent Overstreet .compressed_size = i->len, 4471c6fdbd8SKent Overstreet .uncompressed_size = i->len, 4481c6fdbd8SKent Overstreet .offset = 0, 4491c6fdbd8SKent Overstreet .live_size = i->len, 4501c6fdbd8SKent Overstreet .nonce = crc_nonce, 4511c6fdbd8SKent Overstreet .csum = i->csum, 4521c6fdbd8SKent Overstreet }; 4531c6fdbd8SKent Overstreet 4541c6fdbd8SKent Overstreet if (bch2_csum_type_is_encryption(new_csum_type)) 4551c6fdbd8SKent Overstreet crc_nonce += i->len; 4561c6fdbd8SKent Overstreet } 4571c6fdbd8SKent Overstreet 4581c6fdbd8SKent Overstreet return 0; 4591c6fdbd8SKent Overstreet } 4601c6fdbd8SKent Overstreet 4611c6fdbd8SKent Overstreet #ifdef __KERNEL__ 46203ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 4631c6fdbd8SKent Overstreet { 4641c6fdbd8SKent Overstreet struct key *keyring_key; 4651c6fdbd8SKent Overstreet const struct user_key_payload *ukp; 4661c6fdbd8SKent Overstreet int ret; 4671c6fdbd8SKent Overstreet 468232697abSKent Overstreet keyring_key = request_key(&key_type_user, key_description, NULL); 4691c6fdbd8SKent Overstreet if (IS_ERR(keyring_key)) 4701c6fdbd8SKent Overstreet return PTR_ERR(keyring_key); 4711c6fdbd8SKent Overstreet 4721c6fdbd8SKent Overstreet down_read(&keyring_key->sem); 4731c6fdbd8SKent Overstreet ukp = dereference_key_locked(keyring_key); 4741c6fdbd8SKent Overstreet if (ukp->datalen == sizeof(*key)) { 4751c6fdbd8SKent Overstreet memcpy(key, ukp->data, ukp->datalen); 4761c6fdbd8SKent Overstreet ret = 0; 4771c6fdbd8SKent Overstreet } else { 4781c6fdbd8SKent Overstreet ret = -EINVAL; 4791c6fdbd8SKent Overstreet } 4801c6fdbd8SKent Overstreet up_read(&keyring_key->sem); 4811c6fdbd8SKent Overstreet key_put(keyring_key); 4821c6fdbd8SKent Overstreet 4831c6fdbd8SKent Overstreet return ret; 4841c6fdbd8SKent Overstreet } 4851c6fdbd8SKent Overstreet #else 4861c6fdbd8SKent Overstreet #include <keyutils.h> 4871c6fdbd8SKent Overstreet 48803ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 4891c6fdbd8SKent Overstreet { 4901c6fdbd8SKent Overstreet key_serial_t key_id; 4911c6fdbd8SKent Overstreet 4921c6fdbd8SKent Overstreet key_id = request_key("user", key_description, NULL, 4931c6fdbd8SKent Overstreet KEY_SPEC_USER_KEYRING); 4941c6fdbd8SKent Overstreet if (key_id < 0) 4951c6fdbd8SKent Overstreet return -errno; 4961c6fdbd8SKent Overstreet 4971c6fdbd8SKent Overstreet if (keyctl_read(key_id, (void *) key, sizeof(*key)) != sizeof(*key)) 4981c6fdbd8SKent Overstreet return -1; 4991c6fdbd8SKent Overstreet 5001c6fdbd8SKent Overstreet return 0; 5011c6fdbd8SKent Overstreet } 5021c6fdbd8SKent Overstreet #endif 5031c6fdbd8SKent Overstreet 50403ea3962SKent Overstreet int bch2_request_key(struct bch_sb *sb, struct bch_key *key) 50503ea3962SKent Overstreet { 506401ec4dbSKent Overstreet struct printbuf key_description = PRINTBUF; 507401ec4dbSKent Overstreet int ret; 50803ea3962SKent Overstreet 509401ec4dbSKent Overstreet prt_printf(&key_description, "bcachefs:"); 510401ec4dbSKent Overstreet pr_uuid(&key_description, sb->user_uuid.b); 51103ea3962SKent Overstreet 512401ec4dbSKent Overstreet ret = __bch2_request_key(key_description.buf, key); 513401ec4dbSKent Overstreet printbuf_exit(&key_description); 514401ec4dbSKent Overstreet return ret; 51503ea3962SKent Overstreet } 51603ea3962SKent Overstreet 5171c6fdbd8SKent Overstreet int bch2_decrypt_sb_key(struct bch_fs *c, 5181c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt, 5191c6fdbd8SKent Overstreet struct bch_key *key) 5201c6fdbd8SKent Overstreet { 5211c6fdbd8SKent Overstreet struct bch_encrypted_key sb_key = crypt->key; 5221c6fdbd8SKent Overstreet struct bch_key user_key; 5231c6fdbd8SKent Overstreet int ret = 0; 5241c6fdbd8SKent Overstreet 5251c6fdbd8SKent Overstreet /* is key encrypted? */ 5261c6fdbd8SKent Overstreet if (!bch2_key_is_encrypted(&sb_key)) 5271c6fdbd8SKent Overstreet goto out; 5281c6fdbd8SKent Overstreet 5291c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 5301c6fdbd8SKent Overstreet if (ret) { 531d4bf5eecSKent Overstreet bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret)); 5321c6fdbd8SKent Overstreet goto err; 5331c6fdbd8SKent Overstreet } 5341c6fdbd8SKent Overstreet 5351c6fdbd8SKent Overstreet /* decrypt real key: */ 5361c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 5371c6fdbd8SKent Overstreet &sb_key, sizeof(sb_key)); 5381c6fdbd8SKent Overstreet if (ret) 5391c6fdbd8SKent Overstreet goto err; 5401c6fdbd8SKent Overstreet 5411c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&sb_key)) { 5421c6fdbd8SKent Overstreet bch_err(c, "incorrect encryption key"); 5431c6fdbd8SKent Overstreet ret = -EINVAL; 5441c6fdbd8SKent Overstreet goto err; 5451c6fdbd8SKent Overstreet } 5461c6fdbd8SKent Overstreet out: 5471c6fdbd8SKent Overstreet *key = sb_key.key; 5481c6fdbd8SKent Overstreet err: 5491c6fdbd8SKent Overstreet memzero_explicit(&sb_key, sizeof(sb_key)); 5501c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 5511c6fdbd8SKent Overstreet return ret; 5521c6fdbd8SKent Overstreet } 5531c6fdbd8SKent Overstreet 5541c6fdbd8SKent Overstreet static int bch2_alloc_ciphers(struct bch_fs *c) 5551c6fdbd8SKent Overstreet { 556d4bf5eecSKent Overstreet int ret; 557d4bf5eecSKent Overstreet 5581c6fdbd8SKent Overstreet if (!c->chacha20) 5591c6fdbd8SKent Overstreet c->chacha20 = crypto_alloc_sync_skcipher("chacha20", 0, 0); 560d4bf5eecSKent Overstreet ret = PTR_ERR_OR_ZERO(c->chacha20); 561d4bf5eecSKent Overstreet 562d4bf5eecSKent Overstreet if (ret) { 563d4bf5eecSKent Overstreet bch_err(c, "error requesting chacha20 module: %s", bch2_err_str(ret)); 564d4bf5eecSKent Overstreet return ret; 5651c6fdbd8SKent Overstreet } 5661c6fdbd8SKent Overstreet 5671c6fdbd8SKent Overstreet if (!c->poly1305) 5681c6fdbd8SKent Overstreet c->poly1305 = crypto_alloc_shash("poly1305", 0, 0); 569d4bf5eecSKent Overstreet ret = PTR_ERR_OR_ZERO(c->poly1305); 570d4bf5eecSKent Overstreet 571d4bf5eecSKent Overstreet if (ret) { 572d4bf5eecSKent Overstreet bch_err(c, "error requesting poly1305 module: %s", bch2_err_str(ret)); 573d4bf5eecSKent Overstreet return ret; 5741c6fdbd8SKent Overstreet } 5751c6fdbd8SKent Overstreet 5761c6fdbd8SKent Overstreet return 0; 5771c6fdbd8SKent Overstreet } 5781c6fdbd8SKent Overstreet 5791c6fdbd8SKent Overstreet int bch2_disable_encryption(struct bch_fs *c) 5801c6fdbd8SKent Overstreet { 5811c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 5821c6fdbd8SKent Overstreet struct bch_key key; 5831c6fdbd8SKent Overstreet int ret = -EINVAL; 5841c6fdbd8SKent Overstreet 5851c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 5861c6fdbd8SKent Overstreet 5871c6fdbd8SKent Overstreet crypt = bch2_sb_get_crypt(c->disk_sb.sb); 5881c6fdbd8SKent Overstreet if (!crypt) 5891c6fdbd8SKent Overstreet goto out; 5901c6fdbd8SKent Overstreet 5911c6fdbd8SKent Overstreet /* is key encrypted? */ 5921c6fdbd8SKent Overstreet ret = 0; 5931c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&crypt->key)) 5941c6fdbd8SKent Overstreet goto out; 5951c6fdbd8SKent Overstreet 5961c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 5971c6fdbd8SKent Overstreet if (ret) 5981c6fdbd8SKent Overstreet goto out; 5991c6fdbd8SKent Overstreet 600*73bd774dSKent Overstreet crypt->key.magic = cpu_to_le64(BCH_KEY_MAGIC); 6011c6fdbd8SKent Overstreet crypt->key.key = key; 6021c6fdbd8SKent Overstreet 6031c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 0); 6041c6fdbd8SKent Overstreet bch2_write_super(c); 6051c6fdbd8SKent Overstreet out: 6061c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 6071c6fdbd8SKent Overstreet 6081c6fdbd8SKent Overstreet return ret; 6091c6fdbd8SKent Overstreet } 6101c6fdbd8SKent Overstreet 6111c6fdbd8SKent Overstreet int bch2_enable_encryption(struct bch_fs *c, bool keyed) 6121c6fdbd8SKent Overstreet { 6131c6fdbd8SKent Overstreet struct bch_encrypted_key key; 6141c6fdbd8SKent Overstreet struct bch_key user_key; 6151c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 6161c6fdbd8SKent Overstreet int ret = -EINVAL; 6171c6fdbd8SKent Overstreet 6181c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 6191c6fdbd8SKent Overstreet 6201c6fdbd8SKent Overstreet /* Do we already have an encryption key? */ 6211c6fdbd8SKent Overstreet if (bch2_sb_get_crypt(c->disk_sb.sb)) 6221c6fdbd8SKent Overstreet goto err; 6231c6fdbd8SKent Overstreet 6241c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 6251c6fdbd8SKent Overstreet if (ret) 6261c6fdbd8SKent Overstreet goto err; 6271c6fdbd8SKent Overstreet 628*73bd774dSKent Overstreet key.magic = cpu_to_le64(BCH_KEY_MAGIC); 6291c6fdbd8SKent Overstreet get_random_bytes(&key.key, sizeof(key.key)); 6301c6fdbd8SKent Overstreet 6311c6fdbd8SKent Overstreet if (keyed) { 6321c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 6331c6fdbd8SKent Overstreet if (ret) { 634d4bf5eecSKent Overstreet bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret)); 6351c6fdbd8SKent Overstreet goto err; 6361c6fdbd8SKent Overstreet } 6371c6fdbd8SKent Overstreet 6381c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 6391c6fdbd8SKent Overstreet &key, sizeof(key)); 6401c6fdbd8SKent Overstreet if (ret) 6411c6fdbd8SKent Overstreet goto err; 6421c6fdbd8SKent Overstreet } 6431c6fdbd8SKent Overstreet 6441c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 6451c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 6461c6fdbd8SKent Overstreet if (ret) 6471c6fdbd8SKent Overstreet goto err; 6481c6fdbd8SKent Overstreet 6491c6fdbd8SKent Overstreet crypt = bch2_sb_resize_crypt(&c->disk_sb, sizeof(*crypt) / sizeof(u64)); 6501c6fdbd8SKent Overstreet if (!crypt) { 65165d48e35SKent Overstreet ret = -BCH_ERR_ENOSPC_sb_crypt; 6521c6fdbd8SKent Overstreet goto err; 6531c6fdbd8SKent Overstreet } 6541c6fdbd8SKent Overstreet 6551c6fdbd8SKent Overstreet crypt->key = key; 6561c6fdbd8SKent Overstreet 6571c6fdbd8SKent Overstreet /* write superblock */ 6581c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 1); 6591c6fdbd8SKent Overstreet bch2_write_super(c); 6601c6fdbd8SKent Overstreet err: 6611c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 6621c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 6631c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 6641c6fdbd8SKent Overstreet return ret; 6651c6fdbd8SKent Overstreet } 6661c6fdbd8SKent Overstreet 6671c6fdbd8SKent Overstreet void bch2_fs_encryption_exit(struct bch_fs *c) 6681c6fdbd8SKent Overstreet { 6691c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->poly1305)) 6701c6fdbd8SKent Overstreet crypto_free_shash(c->poly1305); 6711c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->chacha20)) 6721c6fdbd8SKent Overstreet crypto_free_sync_skcipher(c->chacha20); 6731c6fdbd8SKent Overstreet if (!IS_ERR_OR_NULL(c->sha256)) 6741c6fdbd8SKent Overstreet crypto_free_shash(c->sha256); 6751c6fdbd8SKent Overstreet } 6761c6fdbd8SKent Overstreet 6771c6fdbd8SKent Overstreet int bch2_fs_encryption_init(struct bch_fs *c) 6781c6fdbd8SKent Overstreet { 6791c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 6801c6fdbd8SKent Overstreet struct bch_key key; 6811c6fdbd8SKent Overstreet int ret = 0; 6821c6fdbd8SKent Overstreet 6831c6fdbd8SKent Overstreet pr_verbose_init(c->opts, ""); 6841c6fdbd8SKent Overstreet 6851c6fdbd8SKent Overstreet c->sha256 = crypto_alloc_shash("sha256", 0, 0); 686d4bf5eecSKent Overstreet ret = PTR_ERR_OR_ZERO(c->sha256); 687d4bf5eecSKent Overstreet if (ret) { 688d4bf5eecSKent Overstreet bch_err(c, "error requesting sha256 module: %s", bch2_err_str(ret)); 6891c6fdbd8SKent Overstreet goto out; 6901c6fdbd8SKent Overstreet } 6911c6fdbd8SKent Overstreet 6921c6fdbd8SKent Overstreet crypt = bch2_sb_get_crypt(c->disk_sb.sb); 6931c6fdbd8SKent Overstreet if (!crypt) 6941c6fdbd8SKent Overstreet goto out; 6951c6fdbd8SKent Overstreet 6961c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 6971c6fdbd8SKent Overstreet if (ret) 6981c6fdbd8SKent Overstreet goto out; 6991c6fdbd8SKent Overstreet 7001c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 7011c6fdbd8SKent Overstreet if (ret) 7021c6fdbd8SKent Overstreet goto out; 7031c6fdbd8SKent Overstreet 7041c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 7051c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 7061c6fdbd8SKent Overstreet if (ret) 7071c6fdbd8SKent Overstreet goto out; 7081c6fdbd8SKent Overstreet out: 7091c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 7101c6fdbd8SKent Overstreet pr_verbose_init(c->opts, "ret %i", ret); 7111c6fdbd8SKent Overstreet return ret; 7121c6fdbd8SKent Overstreet } 713