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> 135e3c2083SKent Overstreet #include <linux/ratelimit.h> 141c6fdbd8SKent Overstreet #include <linux/scatterlist.h> 151c6fdbd8SKent Overstreet #include <crypto/algapi.h> 161c6fdbd8SKent Overstreet #include <crypto/chacha.h> 171c6fdbd8SKent Overstreet #include <crypto/hash.h> 181c6fdbd8SKent Overstreet #include <crypto/poly1305.h> 191c6fdbd8SKent Overstreet #include <crypto/skcipher.h> 201c6fdbd8SKent Overstreet #include <keys/user-type.h> 211c6fdbd8SKent Overstreet 2280ff5d18Sjpsollie /* 2380ff5d18Sjpsollie * bch2_checksum state is an abstraction of the checksum state calculated over different pages. 2480ff5d18Sjpsollie * it features page merging without having the checksum algorithm lose its state. 2580ff5d18Sjpsollie * for native checksum aglorithms (like crc), a default seed value will do. 2680ff5d18Sjpsollie * for hash-like algorithms, a state needs to be stored 2780ff5d18Sjpsollie */ 2880ff5d18Sjpsollie 2980ff5d18Sjpsollie struct bch2_checksum_state { 3080ff5d18Sjpsollie union { 3180ff5d18Sjpsollie u64 seed; 3241e63382Sjpsollie struct xxh64_state h64state; 3380ff5d18Sjpsollie }; 3480ff5d18Sjpsollie unsigned int type; 3580ff5d18Sjpsollie }; 3680ff5d18Sjpsollie 3780ff5d18Sjpsollie static void bch2_checksum_init(struct bch2_checksum_state *state) 381c6fdbd8SKent Overstreet { 3980ff5d18Sjpsollie switch (state->type) { 406404dcc9SKent Overstreet case BCH_CSUM_none: 416404dcc9SKent Overstreet case BCH_CSUM_crc32c: 426404dcc9SKent Overstreet case BCH_CSUM_crc64: 4380ff5d18Sjpsollie state->seed = 0; 4480ff5d18Sjpsollie break; 456404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 4680ff5d18Sjpsollie state->seed = U32_MAX; 4780ff5d18Sjpsollie break; 486404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 4980ff5d18Sjpsollie state->seed = U64_MAX; 5080ff5d18Sjpsollie break; 516404dcc9SKent Overstreet case BCH_CSUM_xxhash: 5241e63382Sjpsollie xxh64_reset(&state->h64state, 0); 5341e63382Sjpsollie break; 541c6fdbd8SKent Overstreet default: 551c6fdbd8SKent Overstreet BUG(); 561c6fdbd8SKent Overstreet } 571c6fdbd8SKent Overstreet } 581c6fdbd8SKent Overstreet 5980ff5d18Sjpsollie static u64 bch2_checksum_final(const struct bch2_checksum_state *state) 601c6fdbd8SKent Overstreet { 6180ff5d18Sjpsollie switch (state->type) { 626404dcc9SKent Overstreet case BCH_CSUM_none: 636404dcc9SKent Overstreet case BCH_CSUM_crc32c: 646404dcc9SKent Overstreet case BCH_CSUM_crc64: 6580ff5d18Sjpsollie return state->seed; 666404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 6780ff5d18Sjpsollie return state->seed ^ U32_MAX; 686404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 6980ff5d18Sjpsollie return state->seed ^ U64_MAX; 706404dcc9SKent Overstreet case BCH_CSUM_xxhash: 7141e63382Sjpsollie return xxh64_digest(&state->h64state); 721c6fdbd8SKent Overstreet default: 731c6fdbd8SKent Overstreet BUG(); 741c6fdbd8SKent Overstreet } 751c6fdbd8SKent Overstreet } 761c6fdbd8SKent Overstreet 7780ff5d18Sjpsollie static void bch2_checksum_update(struct bch2_checksum_state *state, const void *data, size_t len) 781c6fdbd8SKent Overstreet { 7980ff5d18Sjpsollie switch (state->type) { 806404dcc9SKent Overstreet case BCH_CSUM_none: 8180ff5d18Sjpsollie return; 826404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 836404dcc9SKent Overstreet case BCH_CSUM_crc32c: 8480ff5d18Sjpsollie state->seed = crc32c(state->seed, data, len); 8580ff5d18Sjpsollie break; 866404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 876404dcc9SKent Overstreet case BCH_CSUM_crc64: 8880ff5d18Sjpsollie state->seed = crc64_be(state->seed, data, len); 8980ff5d18Sjpsollie break; 906404dcc9SKent Overstreet case BCH_CSUM_xxhash: 9141e63382Sjpsollie xxh64_update(&state->h64state, data, len); 9241e63382Sjpsollie break; 931c6fdbd8SKent Overstreet default: 941c6fdbd8SKent Overstreet BUG(); 951c6fdbd8SKent Overstreet } 961c6fdbd8SKent Overstreet } 971c6fdbd8SKent Overstreet 98a9de137bSKent Overstreet static inline int do_encrypt_sg(struct crypto_sync_skcipher *tfm, 991c6fdbd8SKent Overstreet struct nonce nonce, 1001c6fdbd8SKent Overstreet struct scatterlist *sg, size_t len) 1011c6fdbd8SKent Overstreet { 1021c6fdbd8SKent Overstreet SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); 1031c6fdbd8SKent Overstreet 1041c6fdbd8SKent Overstreet skcipher_request_set_sync_tfm(req, tfm); 10588ab1018SKent Overstreet skcipher_request_set_callback(req, 0, NULL, NULL); 1061c6fdbd8SKent Overstreet skcipher_request_set_crypt(req, sg, sg, len, nonce.d); 1071c6fdbd8SKent Overstreet 108b7d8092aSKent Overstreet int ret = crypto_skcipher_encrypt(req); 109a9de137bSKent Overstreet if (ret) 110a9de137bSKent Overstreet pr_err("got error %i from crypto_skcipher_encrypt()", ret); 111a9de137bSKent Overstreet 112a9de137bSKent Overstreet return ret; 1131c6fdbd8SKent Overstreet } 1141c6fdbd8SKent Overstreet 115a9de137bSKent Overstreet static inline int do_encrypt(struct crypto_sync_skcipher *tfm, 1161c6fdbd8SKent Overstreet struct nonce nonce, 1171c6fdbd8SKent Overstreet void *buf, size_t len) 1181c6fdbd8SKent Overstreet { 119636d4eefSKent Overstreet if (!is_vmalloc_addr(buf)) { 120*da2d20c9SKent Overstreet struct scatterlist sg = {}; 1211c6fdbd8SKent Overstreet 122*da2d20c9SKent Overstreet sg_mark_end(&sg); 123*da2d20c9SKent Overstreet sg_set_page(&sg, virt_to_page(buf), len, offset_in_page(buf)); 124a9de137bSKent Overstreet return do_encrypt_sg(tfm, nonce, &sg, len); 125636d4eefSKent Overstreet } else { 126b7d8092aSKent Overstreet DARRAY_PREALLOCATED(struct scatterlist, 4) sgl; 127b7d8092aSKent Overstreet size_t sgl_len = 0; 128b7d8092aSKent Overstreet int ret; 129636d4eefSKent Overstreet 130b7d8092aSKent Overstreet darray_init(&sgl); 131636d4eefSKent Overstreet 132b7d8092aSKent Overstreet while (len) { 133636d4eefSKent Overstreet unsigned offset = offset_in_page(buf); 134b7d8092aSKent Overstreet struct scatterlist sg = { 135b7d8092aSKent Overstreet .page_link = (unsigned long) vmalloc_to_page(buf), 136b7d8092aSKent Overstreet .offset = offset, 137b7d8092aSKent Overstreet .length = min(len, PAGE_SIZE - offset), 138b7d8092aSKent Overstreet }; 139636d4eefSKent Overstreet 140b7d8092aSKent Overstreet if (darray_push(&sgl, sg)) { 141b7d8092aSKent Overstreet sg_mark_end(&darray_last(sgl)); 142b7d8092aSKent Overstreet ret = do_encrypt_sg(tfm, nonce, sgl.data, sgl_len); 143b7d8092aSKent Overstreet if (ret) 144b7d8092aSKent Overstreet goto err; 145b7d8092aSKent Overstreet 146b7d8092aSKent Overstreet nonce = nonce_add(nonce, sgl_len); 147b7d8092aSKent Overstreet sgl_len = 0; 148b7d8092aSKent Overstreet sgl.nr = 0; 149b7d8092aSKent Overstreet BUG_ON(darray_push(&sgl, sg)); 150636d4eefSKent Overstreet } 151636d4eefSKent Overstreet 152b7d8092aSKent Overstreet buf += sg.length; 153b7d8092aSKent Overstreet len -= sg.length; 154b7d8092aSKent Overstreet sgl_len += sg.length; 155b7d8092aSKent Overstreet } 156b7d8092aSKent Overstreet 157b7d8092aSKent Overstreet sg_mark_end(&darray_last(sgl)); 158b7d8092aSKent Overstreet ret = do_encrypt_sg(tfm, nonce, sgl.data, sgl_len); 159b7d8092aSKent Overstreet err: 160b7d8092aSKent Overstreet darray_exit(&sgl); 161636d4eefSKent Overstreet return ret; 162636d4eefSKent Overstreet } 1631c6fdbd8SKent Overstreet } 1641c6fdbd8SKent Overstreet 1651c6fdbd8SKent Overstreet int bch2_chacha_encrypt_key(struct bch_key *key, struct nonce nonce, 1661c6fdbd8SKent Overstreet void *buf, size_t len) 1671c6fdbd8SKent Overstreet { 1681c6fdbd8SKent Overstreet struct crypto_sync_skcipher *chacha20 = 1691c6fdbd8SKent Overstreet crypto_alloc_sync_skcipher("chacha20", 0, 0); 1701c6fdbd8SKent Overstreet int ret; 1711c6fdbd8SKent Overstreet 17275e0c478SKent Overstreet ret = PTR_ERR_OR_ZERO(chacha20); 17375e0c478SKent Overstreet if (ret) { 17475e0c478SKent Overstreet pr_err("error requesting chacha20 cipher: %s", bch2_err_str(ret)); 17575e0c478SKent Overstreet return ret; 1761c6fdbd8SKent Overstreet } 1771c6fdbd8SKent Overstreet 1781c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&chacha20->base, 1791c6fdbd8SKent Overstreet (void *) key, sizeof(*key)); 1801c6fdbd8SKent Overstreet if (ret) { 18175e0c478SKent Overstreet pr_err("error from crypto_skcipher_setkey(): %s", bch2_err_str(ret)); 1821c6fdbd8SKent Overstreet goto err; 1831c6fdbd8SKent Overstreet } 1841c6fdbd8SKent Overstreet 185a9de137bSKent Overstreet ret = do_encrypt(chacha20, nonce, buf, len); 1861c6fdbd8SKent Overstreet err: 1871c6fdbd8SKent Overstreet crypto_free_sync_skcipher(chacha20); 1881c6fdbd8SKent Overstreet return ret; 1891c6fdbd8SKent Overstreet } 1901c6fdbd8SKent Overstreet 191a9de137bSKent Overstreet static int gen_poly_key(struct bch_fs *c, struct shash_desc *desc, 1921c6fdbd8SKent Overstreet struct nonce nonce) 1931c6fdbd8SKent Overstreet { 1941c6fdbd8SKent Overstreet u8 key[POLY1305_KEY_SIZE]; 195a9de137bSKent Overstreet int ret; 1961c6fdbd8SKent Overstreet 1971c6fdbd8SKent Overstreet nonce.d[3] ^= BCH_NONCE_POLY; 1981c6fdbd8SKent Overstreet 1991c6fdbd8SKent Overstreet memset(key, 0, sizeof(key)); 200a9de137bSKent Overstreet ret = do_encrypt(c->chacha20, nonce, key, sizeof(key)); 201a9de137bSKent Overstreet if (ret) 202a9de137bSKent Overstreet return ret; 2031c6fdbd8SKent Overstreet 2041c6fdbd8SKent Overstreet desc->tfm = c->poly1305; 2051c6fdbd8SKent Overstreet crypto_shash_init(desc); 2061c6fdbd8SKent Overstreet crypto_shash_update(desc, key, sizeof(key)); 207a9de137bSKent Overstreet return 0; 2081c6fdbd8SKent Overstreet } 2091c6fdbd8SKent Overstreet 2101c6fdbd8SKent Overstreet struct bch_csum bch2_checksum(struct bch_fs *c, unsigned type, 2111c6fdbd8SKent Overstreet struct nonce nonce, const void *data, size_t len) 2121c6fdbd8SKent Overstreet { 2131c6fdbd8SKent Overstreet switch (type) { 2146404dcc9SKent Overstreet case BCH_CSUM_none: 2156404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2166404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2176404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2186404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2196404dcc9SKent Overstreet case BCH_CSUM_crc64: { 22080ff5d18Sjpsollie struct bch2_checksum_state state; 2211c6fdbd8SKent Overstreet 22280ff5d18Sjpsollie state.type = type; 2231c6fdbd8SKent Overstreet 22480ff5d18Sjpsollie bch2_checksum_init(&state); 22580ff5d18Sjpsollie bch2_checksum_update(&state, data, len); 22680ff5d18Sjpsollie 22780ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2281c6fdbd8SKent Overstreet } 2291c6fdbd8SKent Overstreet 2306404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2316404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2321c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2331c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2341c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2351c6fdbd8SKent Overstreet 2361c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2371c6fdbd8SKent Overstreet 2381c6fdbd8SKent Overstreet crypto_shash_update(desc, data, len); 2391c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 2401c6fdbd8SKent Overstreet 2411c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 2421c6fdbd8SKent Overstreet return ret; 2431c6fdbd8SKent Overstreet } 2441c6fdbd8SKent Overstreet default: 2456b74fdccSKent Overstreet return (struct bch_csum) {}; 2461c6fdbd8SKent Overstreet } 2471c6fdbd8SKent Overstreet } 2481c6fdbd8SKent Overstreet 249a9de137bSKent Overstreet int bch2_encrypt(struct bch_fs *c, unsigned type, 2501c6fdbd8SKent Overstreet struct nonce nonce, void *data, size_t len) 2511c6fdbd8SKent Overstreet { 2521c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 253a9de137bSKent Overstreet return 0; 2541c6fdbd8SKent Overstreet 255a9de137bSKent Overstreet return do_encrypt(c->chacha20, nonce, data, len); 2561c6fdbd8SKent Overstreet } 2571c6fdbd8SKent Overstreet 2581c6fdbd8SKent Overstreet static struct bch_csum __bch2_checksum_bio(struct bch_fs *c, unsigned type, 2591c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio, 2601c6fdbd8SKent Overstreet struct bvec_iter *iter) 2611c6fdbd8SKent Overstreet { 2621c6fdbd8SKent Overstreet struct bio_vec bv; 2631c6fdbd8SKent Overstreet 2641c6fdbd8SKent Overstreet switch (type) { 2656404dcc9SKent Overstreet case BCH_CSUM_none: 2661c6fdbd8SKent Overstreet return (struct bch_csum) { 0 }; 2676404dcc9SKent Overstreet case BCH_CSUM_crc32c_nonzero: 2686404dcc9SKent Overstreet case BCH_CSUM_crc64_nonzero: 2696404dcc9SKent Overstreet case BCH_CSUM_crc32c: 2706404dcc9SKent Overstreet case BCH_CSUM_xxhash: 2716404dcc9SKent Overstreet case BCH_CSUM_crc64: { 27280ff5d18Sjpsollie struct bch2_checksum_state state; 27380ff5d18Sjpsollie 27480ff5d18Sjpsollie state.type = type; 27580ff5d18Sjpsollie bch2_checksum_init(&state); 2761c6fdbd8SKent Overstreet 2771c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 2781c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 2791e81f89bSKent Overstreet void *p = kmap_local_page(bv.bv_page) + bv.bv_offset; 2801e81f89bSKent Overstreet 28180ff5d18Sjpsollie bch2_checksum_update(&state, p, bv.bv_len); 2821e81f89bSKent Overstreet kunmap_local(p); 2831c6fdbd8SKent Overstreet } 2841c6fdbd8SKent Overstreet #else 2850fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 28680ff5d18Sjpsollie bch2_checksum_update(&state, page_address(bv.bv_page) + bv.bv_offset, 2871c6fdbd8SKent Overstreet bv.bv_len); 2881c6fdbd8SKent Overstreet #endif 28980ff5d18Sjpsollie return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) }; 2901c6fdbd8SKent Overstreet } 2911c6fdbd8SKent Overstreet 2926404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_80: 2936404dcc9SKent Overstreet case BCH_CSUM_chacha20_poly1305_128: { 2941c6fdbd8SKent Overstreet SHASH_DESC_ON_STACK(desc, c->poly1305); 2951c6fdbd8SKent Overstreet u8 digest[POLY1305_DIGEST_SIZE]; 2961c6fdbd8SKent Overstreet struct bch_csum ret = { 0 }; 2971c6fdbd8SKent Overstreet 2981c6fdbd8SKent Overstreet gen_poly_key(c, desc, nonce); 2991c6fdbd8SKent Overstreet 3001c6fdbd8SKent Overstreet #ifdef CONFIG_HIGHMEM 3011c6fdbd8SKent Overstreet __bio_for_each_segment(bv, bio, *iter, *iter) { 3021e81f89bSKent Overstreet void *p = kmap_local_page(bv.bv_page) + bv.bv_offset; 3031c6fdbd8SKent Overstreet 3041c6fdbd8SKent Overstreet crypto_shash_update(desc, p, bv.bv_len); 3051e81f89bSKent Overstreet kunmap_local(p); 3061c6fdbd8SKent Overstreet } 3071c6fdbd8SKent Overstreet #else 3080fd7263eSKent Overstreet __bio_for_each_bvec(bv, bio, *iter, *iter) 3091c6fdbd8SKent Overstreet crypto_shash_update(desc, 3101c6fdbd8SKent Overstreet page_address(bv.bv_page) + bv.bv_offset, 3111c6fdbd8SKent Overstreet bv.bv_len); 3121c6fdbd8SKent Overstreet #endif 3131c6fdbd8SKent Overstreet crypto_shash_final(desc, digest); 3141c6fdbd8SKent Overstreet 3151c6fdbd8SKent Overstreet memcpy(&ret, digest, bch_crc_bytes[type]); 3161c6fdbd8SKent Overstreet return ret; 3171c6fdbd8SKent Overstreet } 3181c6fdbd8SKent Overstreet default: 3196b74fdccSKent Overstreet return (struct bch_csum) {}; 3201c6fdbd8SKent Overstreet } 3211c6fdbd8SKent Overstreet } 3221c6fdbd8SKent Overstreet 3231c6fdbd8SKent Overstreet struct bch_csum bch2_checksum_bio(struct bch_fs *c, unsigned type, 3241c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3251c6fdbd8SKent Overstreet { 3261c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 3271c6fdbd8SKent Overstreet 3281c6fdbd8SKent Overstreet return __bch2_checksum_bio(c, type, nonce, bio, &iter); 3291c6fdbd8SKent Overstreet } 3301c6fdbd8SKent Overstreet 3310cc455b3SKent Overstreet int __bch2_encrypt_bio(struct bch_fs *c, unsigned type, 3321c6fdbd8SKent Overstreet struct nonce nonce, struct bio *bio) 3331c6fdbd8SKent Overstreet { 3341c6fdbd8SKent Overstreet struct bio_vec bv; 3351c6fdbd8SKent Overstreet struct bvec_iter iter; 336af05633dSKent Overstreet DARRAY_PREALLOCATED(struct scatterlist, 4) sgl; 337af05633dSKent Overstreet size_t sgl_len = 0; 338a9de137bSKent Overstreet int ret = 0; 3391c6fdbd8SKent Overstreet 3401c6fdbd8SKent Overstreet if (!bch2_csum_type_is_encryption(type)) 341a9de137bSKent Overstreet return 0; 3421c6fdbd8SKent Overstreet 343af05633dSKent Overstreet darray_init(&sgl); 3441c6fdbd8SKent Overstreet 3451c6fdbd8SKent Overstreet bio_for_each_segment(bv, bio, iter) { 346af05633dSKent Overstreet struct scatterlist sg = { 347af05633dSKent Overstreet .page_link = (unsigned long) bv.bv_page, 348af05633dSKent Overstreet .offset = bv.bv_offset, 349af05633dSKent Overstreet .length = bv.bv_len, 350af05633dSKent Overstreet }; 351a9de137bSKent Overstreet 352af05633dSKent Overstreet if (darray_push(&sgl, sg)) { 353af05633dSKent Overstreet sg_mark_end(&darray_last(sgl)); 354af05633dSKent Overstreet ret = do_encrypt_sg(c->chacha20, nonce, sgl.data, sgl_len); 355a9de137bSKent Overstreet if (ret) 356af05633dSKent Overstreet goto err; 3571c6fdbd8SKent Overstreet 358af05633dSKent Overstreet nonce = nonce_add(nonce, sgl_len); 359af05633dSKent Overstreet sgl_len = 0; 360af05633dSKent Overstreet sgl.nr = 0; 3611c6fdbd8SKent Overstreet 362af05633dSKent Overstreet BUG_ON(darray_push(&sgl, sg)); 3631c6fdbd8SKent Overstreet } 3641c6fdbd8SKent Overstreet 365af05633dSKent Overstreet sgl_len += sg.length; 3661c6fdbd8SKent Overstreet } 3671c6fdbd8SKent Overstreet 368af05633dSKent Overstreet sg_mark_end(&darray_last(sgl)); 369af05633dSKent Overstreet ret = do_encrypt_sg(c->chacha20, nonce, sgl.data, sgl_len); 370af05633dSKent Overstreet err: 371af05633dSKent Overstreet darray_exit(&sgl); 3722ba24864SKent Overstreet return ret; 3732ba24864SKent Overstreet } 3742ba24864SKent Overstreet 3756009b4e5SKent Overstreet struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, 3761c6fdbd8SKent Overstreet struct bch_csum b, size_t b_len) 3771c6fdbd8SKent Overstreet { 37880ff5d18Sjpsollie struct bch2_checksum_state state; 37980ff5d18Sjpsollie 38080ff5d18Sjpsollie state.type = type; 38180ff5d18Sjpsollie bch2_checksum_init(&state); 3823c40841cSBrian Foster state.seed = le64_to_cpu(a.lo); 38380ff5d18Sjpsollie 3841c6fdbd8SKent Overstreet BUG_ON(!bch2_checksum_mergeable(type)); 3851c6fdbd8SKent Overstreet 3861c6fdbd8SKent Overstreet while (b_len) { 38796dea3d5SKent Overstreet unsigned page_len = min_t(unsigned, b_len, PAGE_SIZE); 3881c6fdbd8SKent Overstreet 38980ff5d18Sjpsollie bch2_checksum_update(&state, 39096dea3d5SKent Overstreet page_address(ZERO_PAGE(0)), page_len); 39196dea3d5SKent Overstreet b_len -= page_len; 3921c6fdbd8SKent Overstreet } 3933c40841cSBrian Foster a.lo = cpu_to_le64(bch2_checksum_final(&state)); 3941c6fdbd8SKent Overstreet a.lo ^= b.lo; 3951c6fdbd8SKent Overstreet a.hi ^= b.hi; 3961c6fdbd8SKent Overstreet return a; 3971c6fdbd8SKent Overstreet } 3981c6fdbd8SKent Overstreet 3991c6fdbd8SKent Overstreet int bch2_rechecksum_bio(struct bch_fs *c, struct bio *bio, 4001c6fdbd8SKent Overstreet struct bversion version, 4011c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked crc_old, 4021c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_a, 4031c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc_b, 4041c6fdbd8SKent Overstreet unsigned len_a, unsigned len_b, 4051c6fdbd8SKent Overstreet unsigned new_csum_type) 4061c6fdbd8SKent Overstreet { 4071c6fdbd8SKent Overstreet struct bvec_iter iter = bio->bi_iter; 4081c6fdbd8SKent Overstreet struct nonce nonce = extent_nonce(version, crc_old); 4091c6fdbd8SKent Overstreet struct bch_csum merged = { 0 }; 4101c6fdbd8SKent Overstreet struct crc_split { 4111c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked *crc; 4121c6fdbd8SKent Overstreet unsigned len; 4131c6fdbd8SKent Overstreet unsigned csum_type; 4141c6fdbd8SKent Overstreet struct bch_csum csum; 4151c6fdbd8SKent Overstreet } splits[3] = { 41696dea3d5SKent Overstreet { crc_a, len_a, new_csum_type, { 0 }}, 41796dea3d5SKent Overstreet { crc_b, len_b, new_csum_type, { 0 } }, 41896dea3d5SKent Overstreet { NULL, bio_sectors(bio) - len_a - len_b, new_csum_type, { 0 } }, 4191c6fdbd8SKent Overstreet }, *i; 4201c6fdbd8SKent Overstreet bool mergeable = crc_old.csum_type == new_csum_type && 4211c6fdbd8SKent Overstreet bch2_checksum_mergeable(new_csum_type); 4221c6fdbd8SKent Overstreet unsigned crc_nonce = crc_old.nonce; 4231c6fdbd8SKent Overstreet 4241c6fdbd8SKent Overstreet BUG_ON(len_a + len_b > bio_sectors(bio)); 4251c6fdbd8SKent Overstreet BUG_ON(crc_old.uncompressed_size != bio_sectors(bio)); 426ab05de4cSKent Overstreet BUG_ON(crc_is_compressed(crc_old)); 4271c6fdbd8SKent Overstreet BUG_ON(bch2_csum_type_is_encryption(crc_old.csum_type) != 4281c6fdbd8SKent Overstreet bch2_csum_type_is_encryption(new_csum_type)); 4291c6fdbd8SKent Overstreet 4301c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4311c6fdbd8SKent Overstreet iter.bi_size = i->len << 9; 4321c6fdbd8SKent Overstreet if (mergeable || i->crc) 4331c6fdbd8SKent Overstreet i->csum = __bch2_checksum_bio(c, i->csum_type, 4341c6fdbd8SKent Overstreet nonce, bio, &iter); 4351c6fdbd8SKent Overstreet else 4361c6fdbd8SKent Overstreet bio_advance_iter(bio, &iter, i->len << 9); 4371c6fdbd8SKent Overstreet nonce = nonce_add(nonce, i->len << 9); 4381c6fdbd8SKent Overstreet } 4391c6fdbd8SKent Overstreet 4401c6fdbd8SKent Overstreet if (mergeable) 4411c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) 4421c6fdbd8SKent Overstreet merged = bch2_checksum_merge(new_csum_type, merged, 4431c6fdbd8SKent Overstreet i->csum, i->len << 9); 4441c6fdbd8SKent Overstreet else 4451c6fdbd8SKent Overstreet merged = bch2_checksum_bio(c, crc_old.csum_type, 4461c6fdbd8SKent Overstreet extent_nonce(version, crc_old), bio); 4471c6fdbd8SKent Overstreet 448970a5096SKent Overstreet if (bch2_crc_cmp(merged, crc_old.csum) && !c->opts.no_data_io) { 4499abb6dd7SKent Overstreet struct printbuf buf = PRINTBUF; 4509abb6dd7SKent Overstreet prt_printf(&buf, "checksum error in %s() (memory corruption or bug?)\n" 4519abb6dd7SKent Overstreet " expected %0llx:%0llx got %0llx:%0llx (old type ", 4521e81f89bSKent Overstreet __func__, 45323189da9SKent Overstreet crc_old.csum.hi, 45423189da9SKent Overstreet crc_old.csum.lo, 45523189da9SKent Overstreet merged.hi, 4569abb6dd7SKent Overstreet merged.lo); 4579abb6dd7SKent Overstreet bch2_prt_csum_type(&buf, crc_old.csum_type); 4589abb6dd7SKent Overstreet prt_str(&buf, " new type "); 4599abb6dd7SKent Overstreet bch2_prt_csum_type(&buf, new_csum_type); 4609abb6dd7SKent Overstreet prt_str(&buf, ")"); 4615e3c2083SKent Overstreet WARN_RATELIMIT(1, "%s", buf.buf); 4629abb6dd7SKent Overstreet printbuf_exit(&buf); 4631c6fdbd8SKent Overstreet return -EIO; 46423189da9SKent Overstreet } 4651c6fdbd8SKent Overstreet 4661c6fdbd8SKent Overstreet for (i = splits; i < splits + ARRAY_SIZE(splits); i++) { 4671c6fdbd8SKent Overstreet if (i->crc) 4681c6fdbd8SKent Overstreet *i->crc = (struct bch_extent_crc_unpacked) { 4691c6fdbd8SKent Overstreet .csum_type = i->csum_type, 470ab05de4cSKent Overstreet .compression_type = crc_old.compression_type, 4711c6fdbd8SKent Overstreet .compressed_size = i->len, 4721c6fdbd8SKent Overstreet .uncompressed_size = i->len, 4731c6fdbd8SKent Overstreet .offset = 0, 4741c6fdbd8SKent Overstreet .live_size = i->len, 4751c6fdbd8SKent Overstreet .nonce = crc_nonce, 4761c6fdbd8SKent Overstreet .csum = i->csum, 4771c6fdbd8SKent Overstreet }; 4781c6fdbd8SKent Overstreet 4791c6fdbd8SKent Overstreet if (bch2_csum_type_is_encryption(new_csum_type)) 4801c6fdbd8SKent Overstreet crc_nonce += i->len; 4811c6fdbd8SKent Overstreet } 4821c6fdbd8SKent Overstreet 4831c6fdbd8SKent Overstreet return 0; 4841c6fdbd8SKent Overstreet } 4851c6fdbd8SKent Overstreet 4860ec39856SKent Overstreet /* BCH_SB_FIELD_crypt: */ 4870ec39856SKent Overstreet 488a5c3e265SKent Overstreet static int bch2_sb_crypt_validate(struct bch_sb *sb, struct bch_sb_field *f, 489a5c3e265SKent Overstreet enum bch_validate_flags flags, struct printbuf *err) 4900ec39856SKent Overstreet { 4910ec39856SKent Overstreet struct bch_sb_field_crypt *crypt = field_to_type(f, crypt); 4920ec39856SKent Overstreet 4930ec39856SKent Overstreet if (vstruct_bytes(&crypt->field) < sizeof(*crypt)) { 4940ec39856SKent Overstreet prt_printf(err, "wrong size (got %zu should be %zu)", 4950ec39856SKent Overstreet vstruct_bytes(&crypt->field), sizeof(*crypt)); 4960ec39856SKent Overstreet return -BCH_ERR_invalid_sb_crypt; 4970ec39856SKent Overstreet } 4980ec39856SKent Overstreet 4990ec39856SKent Overstreet if (BCH_CRYPT_KDF_TYPE(crypt)) { 5000ec39856SKent Overstreet prt_printf(err, "bad kdf type %llu", BCH_CRYPT_KDF_TYPE(crypt)); 5010ec39856SKent Overstreet return -BCH_ERR_invalid_sb_crypt; 5020ec39856SKent Overstreet } 5030ec39856SKent Overstreet 5040ec39856SKent Overstreet return 0; 5050ec39856SKent Overstreet } 5060ec39856SKent Overstreet 5070ec39856SKent Overstreet static void bch2_sb_crypt_to_text(struct printbuf *out, struct bch_sb *sb, 5080ec39856SKent Overstreet struct bch_sb_field *f) 5090ec39856SKent Overstreet { 5100ec39856SKent Overstreet struct bch_sb_field_crypt *crypt = field_to_type(f, crypt); 5110ec39856SKent Overstreet 5127423330eSKent Overstreet prt_printf(out, "KFD: %llu\n", BCH_CRYPT_KDF_TYPE(crypt)); 5137423330eSKent Overstreet prt_printf(out, "scrypt n: %llu\n", BCH_KDF_SCRYPT_N(crypt)); 5147423330eSKent Overstreet prt_printf(out, "scrypt r: %llu\n", BCH_KDF_SCRYPT_R(crypt)); 5157423330eSKent Overstreet prt_printf(out, "scrypt p: %llu\n", BCH_KDF_SCRYPT_P(crypt)); 5160ec39856SKent Overstreet } 5170ec39856SKent Overstreet 5180ec39856SKent Overstreet const struct bch_sb_field_ops bch_sb_field_ops_crypt = { 5190ec39856SKent Overstreet .validate = bch2_sb_crypt_validate, 5200ec39856SKent Overstreet .to_text = bch2_sb_crypt_to_text, 5210ec39856SKent Overstreet }; 5220ec39856SKent Overstreet 5231c6fdbd8SKent Overstreet #ifdef __KERNEL__ 52403ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 5251c6fdbd8SKent Overstreet { 5261c6fdbd8SKent Overstreet struct key *keyring_key; 5271c6fdbd8SKent Overstreet const struct user_key_payload *ukp; 5281c6fdbd8SKent Overstreet int ret; 5291c6fdbd8SKent Overstreet 530232697abSKent Overstreet keyring_key = request_key(&key_type_user, key_description, NULL); 5311c6fdbd8SKent Overstreet if (IS_ERR(keyring_key)) 5321c6fdbd8SKent Overstreet return PTR_ERR(keyring_key); 5331c6fdbd8SKent Overstreet 5341c6fdbd8SKent Overstreet down_read(&keyring_key->sem); 5351c6fdbd8SKent Overstreet ukp = dereference_key_locked(keyring_key); 5361c6fdbd8SKent Overstreet if (ukp->datalen == sizeof(*key)) { 5371c6fdbd8SKent Overstreet memcpy(key, ukp->data, ukp->datalen); 5381c6fdbd8SKent Overstreet ret = 0; 5391c6fdbd8SKent Overstreet } else { 5401c6fdbd8SKent Overstreet ret = -EINVAL; 5411c6fdbd8SKent Overstreet } 5421c6fdbd8SKent Overstreet up_read(&keyring_key->sem); 5431c6fdbd8SKent Overstreet key_put(keyring_key); 5441c6fdbd8SKent Overstreet 5451c6fdbd8SKent Overstreet return ret; 5461c6fdbd8SKent Overstreet } 5471c6fdbd8SKent Overstreet #else 5481c6fdbd8SKent Overstreet #include <keyutils.h> 5491c6fdbd8SKent Overstreet 55003ea3962SKent Overstreet static int __bch2_request_key(char *key_description, struct bch_key *key) 5511c6fdbd8SKent Overstreet { 5521c6fdbd8SKent Overstreet key_serial_t key_id; 5531c6fdbd8SKent Overstreet 5541c6fdbd8SKent Overstreet key_id = request_key("user", key_description, NULL, 5551ee608c6SKent Overstreet KEY_SPEC_SESSION_KEYRING); 5561ee608c6SKent Overstreet if (key_id >= 0) 5571ee608c6SKent Overstreet goto got_key; 5581ee608c6SKent Overstreet 5591ee608c6SKent Overstreet key_id = request_key("user", key_description, NULL, 5601c6fdbd8SKent Overstreet KEY_SPEC_USER_KEYRING); 5611ee608c6SKent Overstreet if (key_id >= 0) 5621ee608c6SKent Overstreet goto got_key; 5631ee608c6SKent Overstreet 5641ee608c6SKent Overstreet key_id = request_key("user", key_description, NULL, 5651ee608c6SKent Overstreet KEY_SPEC_USER_SESSION_KEYRING); 5661ee608c6SKent Overstreet if (key_id >= 0) 5671ee608c6SKent Overstreet goto got_key; 5681ee608c6SKent Overstreet 5691c6fdbd8SKent Overstreet return -errno; 5701ee608c6SKent Overstreet got_key: 5711c6fdbd8SKent Overstreet 5721c6fdbd8SKent Overstreet if (keyctl_read(key_id, (void *) key, sizeof(*key)) != sizeof(*key)) 5731c6fdbd8SKent Overstreet return -1; 5741c6fdbd8SKent Overstreet 5751c6fdbd8SKent Overstreet return 0; 5761c6fdbd8SKent Overstreet } 5771ee608c6SKent Overstreet 5787b05ecbaSKent Overstreet #include "crypto.h" 5791c6fdbd8SKent Overstreet #endif 5801c6fdbd8SKent Overstreet 58103ea3962SKent Overstreet int bch2_request_key(struct bch_sb *sb, struct bch_key *key) 58203ea3962SKent Overstreet { 583401ec4dbSKent Overstreet struct printbuf key_description = PRINTBUF; 584401ec4dbSKent Overstreet int ret; 58503ea3962SKent Overstreet 586401ec4dbSKent Overstreet prt_printf(&key_description, "bcachefs:"); 587401ec4dbSKent Overstreet pr_uuid(&key_description, sb->user_uuid.b); 58803ea3962SKent Overstreet 589401ec4dbSKent Overstreet ret = __bch2_request_key(key_description.buf, key); 590401ec4dbSKent Overstreet printbuf_exit(&key_description); 5911ee608c6SKent Overstreet 5921ee608c6SKent Overstreet #ifndef __KERNEL__ 5931ee608c6SKent Overstreet if (ret) { 5941ee608c6SKent Overstreet char *passphrase = read_passphrase("Enter passphrase: "); 5951ee608c6SKent Overstreet struct bch_encrypted_key sb_key; 5961ee608c6SKent Overstreet 5971ee608c6SKent Overstreet bch2_passphrase_check(sb, passphrase, 5981ee608c6SKent Overstreet key, &sb_key); 5991ee608c6SKent Overstreet ret = 0; 6001ee608c6SKent Overstreet } 6011ee608c6SKent Overstreet #endif 6021ee608c6SKent Overstreet 6031ee608c6SKent Overstreet /* stash with memfd, pass memfd fd to mount */ 6041ee608c6SKent Overstreet 605401ec4dbSKent Overstreet return ret; 60603ea3962SKent Overstreet } 60703ea3962SKent Overstreet 608793a06d9SKent Overstreet #ifndef __KERNEL__ 609793a06d9SKent Overstreet int bch2_revoke_key(struct bch_sb *sb) 610793a06d9SKent Overstreet { 611793a06d9SKent Overstreet key_serial_t key_id; 612793a06d9SKent Overstreet struct printbuf key_description = PRINTBUF; 613793a06d9SKent Overstreet 614793a06d9SKent Overstreet prt_printf(&key_description, "bcachefs:"); 615793a06d9SKent Overstreet pr_uuid(&key_description, sb->user_uuid.b); 616793a06d9SKent Overstreet 617793a06d9SKent Overstreet key_id = request_key("user", key_description.buf, NULL, KEY_SPEC_USER_KEYRING); 618793a06d9SKent Overstreet printbuf_exit(&key_description); 619793a06d9SKent Overstreet if (key_id < 0) 620793a06d9SKent Overstreet return errno; 621793a06d9SKent Overstreet 622793a06d9SKent Overstreet keyctl_revoke(key_id); 623793a06d9SKent Overstreet 624793a06d9SKent Overstreet return 0; 625793a06d9SKent Overstreet } 626793a06d9SKent Overstreet #endif 627793a06d9SKent Overstreet 6281c6fdbd8SKent Overstreet int bch2_decrypt_sb_key(struct bch_fs *c, 6291c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt, 6301c6fdbd8SKent Overstreet struct bch_key *key) 6311c6fdbd8SKent Overstreet { 6321c6fdbd8SKent Overstreet struct bch_encrypted_key sb_key = crypt->key; 6331c6fdbd8SKent Overstreet struct bch_key user_key; 6341c6fdbd8SKent Overstreet int ret = 0; 6351c6fdbd8SKent Overstreet 6361c6fdbd8SKent Overstreet /* is key encrypted? */ 6371c6fdbd8SKent Overstreet if (!bch2_key_is_encrypted(&sb_key)) 6381c6fdbd8SKent Overstreet goto out; 6391c6fdbd8SKent Overstreet 6401c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 6411c6fdbd8SKent Overstreet if (ret) { 642d4bf5eecSKent Overstreet bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret)); 6431c6fdbd8SKent Overstreet goto err; 6441c6fdbd8SKent Overstreet } 6451c6fdbd8SKent Overstreet 6461c6fdbd8SKent Overstreet /* decrypt real key: */ 6471c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 6481c6fdbd8SKent Overstreet &sb_key, sizeof(sb_key)); 6491c6fdbd8SKent Overstreet if (ret) 6501c6fdbd8SKent Overstreet goto err; 6511c6fdbd8SKent Overstreet 6521c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&sb_key)) { 6531c6fdbd8SKent Overstreet bch_err(c, "incorrect encryption key"); 6541c6fdbd8SKent Overstreet ret = -EINVAL; 6551c6fdbd8SKent Overstreet goto err; 6561c6fdbd8SKent Overstreet } 6571c6fdbd8SKent Overstreet out: 6581c6fdbd8SKent Overstreet *key = sb_key.key; 6591c6fdbd8SKent Overstreet err: 6601c6fdbd8SKent Overstreet memzero_explicit(&sb_key, sizeof(sb_key)); 6611c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 6621c6fdbd8SKent Overstreet return ret; 6631c6fdbd8SKent Overstreet } 6641c6fdbd8SKent Overstreet 6651c6fdbd8SKent Overstreet static int bch2_alloc_ciphers(struct bch_fs *c) 6661c6fdbd8SKent Overstreet { 667c06a8b75SKent Overstreet if (c->chacha20) 668c06a8b75SKent Overstreet return 0; 669d4bf5eecSKent Overstreet 670c06a8b75SKent Overstreet struct crypto_sync_skcipher *chacha20 = crypto_alloc_sync_skcipher("chacha20", 0, 0); 671c06a8b75SKent Overstreet int ret = PTR_ERR_OR_ZERO(chacha20); 672d4bf5eecSKent Overstreet if (ret) { 673d4bf5eecSKent Overstreet bch_err(c, "error requesting chacha20 module: %s", bch2_err_str(ret)); 674d4bf5eecSKent Overstreet return ret; 6751c6fdbd8SKent Overstreet } 6761c6fdbd8SKent Overstreet 677c06a8b75SKent Overstreet struct crypto_shash *poly1305 = crypto_alloc_shash("poly1305", 0, 0); 678c06a8b75SKent Overstreet ret = PTR_ERR_OR_ZERO(poly1305); 679d4bf5eecSKent Overstreet if (ret) { 680d4bf5eecSKent Overstreet bch_err(c, "error requesting poly1305 module: %s", bch2_err_str(ret)); 681c06a8b75SKent Overstreet crypto_free_sync_skcipher(chacha20); 682d4bf5eecSKent Overstreet return ret; 6831c6fdbd8SKent Overstreet } 6841c6fdbd8SKent Overstreet 685c06a8b75SKent Overstreet c->chacha20 = chacha20; 686c06a8b75SKent Overstreet c->poly1305 = poly1305; 6871c6fdbd8SKent Overstreet return 0; 6881c6fdbd8SKent Overstreet } 6891c6fdbd8SKent Overstreet 6901c6fdbd8SKent Overstreet int bch2_disable_encryption(struct bch_fs *c) 6911c6fdbd8SKent Overstreet { 6921c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 6931c6fdbd8SKent Overstreet struct bch_key key; 6941c6fdbd8SKent Overstreet int ret = -EINVAL; 6951c6fdbd8SKent Overstreet 6961c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 6971c6fdbd8SKent Overstreet 6984637429eSKent Overstreet crypt = bch2_sb_field_get(c->disk_sb.sb, crypt); 6991c6fdbd8SKent Overstreet if (!crypt) 7001c6fdbd8SKent Overstreet goto out; 7011c6fdbd8SKent Overstreet 7021c6fdbd8SKent Overstreet /* is key encrypted? */ 7031c6fdbd8SKent Overstreet ret = 0; 7041c6fdbd8SKent Overstreet if (bch2_key_is_encrypted(&crypt->key)) 7051c6fdbd8SKent Overstreet goto out; 7061c6fdbd8SKent Overstreet 7071c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 7081c6fdbd8SKent Overstreet if (ret) 7091c6fdbd8SKent Overstreet goto out; 7101c6fdbd8SKent Overstreet 71173bd774dSKent Overstreet crypt->key.magic = cpu_to_le64(BCH_KEY_MAGIC); 7121c6fdbd8SKent Overstreet crypt->key.key = key; 7131c6fdbd8SKent Overstreet 7141c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 0); 7151c6fdbd8SKent Overstreet bch2_write_super(c); 7161c6fdbd8SKent Overstreet out: 7171c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 7181c6fdbd8SKent Overstreet 7191c6fdbd8SKent Overstreet return ret; 7201c6fdbd8SKent Overstreet } 7211c6fdbd8SKent Overstreet 7221c6fdbd8SKent Overstreet int bch2_enable_encryption(struct bch_fs *c, bool keyed) 7231c6fdbd8SKent Overstreet { 7241c6fdbd8SKent Overstreet struct bch_encrypted_key key; 7251c6fdbd8SKent Overstreet struct bch_key user_key; 7261c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 7271c6fdbd8SKent Overstreet int ret = -EINVAL; 7281c6fdbd8SKent Overstreet 7291c6fdbd8SKent Overstreet mutex_lock(&c->sb_lock); 7301c6fdbd8SKent Overstreet 7311c6fdbd8SKent Overstreet /* Do we already have an encryption key? */ 7324637429eSKent Overstreet if (bch2_sb_field_get(c->disk_sb.sb, crypt)) 7331c6fdbd8SKent Overstreet goto err; 7341c6fdbd8SKent Overstreet 7351c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 7361c6fdbd8SKent Overstreet if (ret) 7371c6fdbd8SKent Overstreet goto err; 7381c6fdbd8SKent Overstreet 73973bd774dSKent Overstreet key.magic = cpu_to_le64(BCH_KEY_MAGIC); 7401c6fdbd8SKent Overstreet get_random_bytes(&key.key, sizeof(key.key)); 7411c6fdbd8SKent Overstreet 7421c6fdbd8SKent Overstreet if (keyed) { 7431c6fdbd8SKent Overstreet ret = bch2_request_key(c->disk_sb.sb, &user_key); 7441c6fdbd8SKent Overstreet if (ret) { 745d4bf5eecSKent Overstreet bch_err(c, "error requesting encryption key: %s", bch2_err_str(ret)); 7461c6fdbd8SKent Overstreet goto err; 7471c6fdbd8SKent Overstreet } 7481c6fdbd8SKent Overstreet 7491c6fdbd8SKent Overstreet ret = bch2_chacha_encrypt_key(&user_key, bch2_sb_key_nonce(c), 7501c6fdbd8SKent Overstreet &key, sizeof(key)); 7511c6fdbd8SKent Overstreet if (ret) 7521c6fdbd8SKent Overstreet goto err; 7531c6fdbd8SKent Overstreet } 7541c6fdbd8SKent Overstreet 7551c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 7561c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 7571c6fdbd8SKent Overstreet if (ret) 7581c6fdbd8SKent Overstreet goto err; 7591c6fdbd8SKent Overstreet 7604637429eSKent Overstreet crypt = bch2_sb_field_resize(&c->disk_sb, crypt, 7614637429eSKent Overstreet sizeof(*crypt) / sizeof(u64)); 7621c6fdbd8SKent Overstreet if (!crypt) { 76365d48e35SKent Overstreet ret = -BCH_ERR_ENOSPC_sb_crypt; 7641c6fdbd8SKent Overstreet goto err; 7651c6fdbd8SKent Overstreet } 7661c6fdbd8SKent Overstreet 7671c6fdbd8SKent Overstreet crypt->key = key; 7681c6fdbd8SKent Overstreet 7691c6fdbd8SKent Overstreet /* write superblock */ 7701c6fdbd8SKent Overstreet SET_BCH_SB_ENCRYPTION_TYPE(c->disk_sb.sb, 1); 7711c6fdbd8SKent Overstreet bch2_write_super(c); 7721c6fdbd8SKent Overstreet err: 7731c6fdbd8SKent Overstreet mutex_unlock(&c->sb_lock); 7741c6fdbd8SKent Overstreet memzero_explicit(&user_key, sizeof(user_key)); 7751c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 7761c6fdbd8SKent Overstreet return ret; 7771c6fdbd8SKent Overstreet } 7781c6fdbd8SKent Overstreet 7791c6fdbd8SKent Overstreet void bch2_fs_encryption_exit(struct bch_fs *c) 7801c6fdbd8SKent Overstreet { 781c06a8b75SKent Overstreet if (c->poly1305) 7821c6fdbd8SKent Overstreet crypto_free_shash(c->poly1305); 783c06a8b75SKent Overstreet if (c->chacha20) 7841c6fdbd8SKent Overstreet crypto_free_sync_skcipher(c->chacha20); 785c06a8b75SKent Overstreet if (c->sha256) 7861c6fdbd8SKent Overstreet crypto_free_shash(c->sha256); 7871c6fdbd8SKent Overstreet } 7881c6fdbd8SKent Overstreet 7891c6fdbd8SKent Overstreet int bch2_fs_encryption_init(struct bch_fs *c) 7901c6fdbd8SKent Overstreet { 7911c6fdbd8SKent Overstreet struct bch_sb_field_crypt *crypt; 7921c6fdbd8SKent Overstreet struct bch_key key; 7931c6fdbd8SKent Overstreet int ret = 0; 7941c6fdbd8SKent Overstreet 7951c6fdbd8SKent Overstreet c->sha256 = crypto_alloc_shash("sha256", 0, 0); 796d4bf5eecSKent Overstreet ret = PTR_ERR_OR_ZERO(c->sha256); 797d4bf5eecSKent Overstreet if (ret) { 798c06a8b75SKent Overstreet c->sha256 = NULL; 799d4bf5eecSKent Overstreet bch_err(c, "error requesting sha256 module: %s", bch2_err_str(ret)); 8001c6fdbd8SKent Overstreet goto out; 8011c6fdbd8SKent Overstreet } 8021c6fdbd8SKent Overstreet 8034637429eSKent Overstreet crypt = bch2_sb_field_get(c->disk_sb.sb, crypt); 8041c6fdbd8SKent Overstreet if (!crypt) 8051c6fdbd8SKent Overstreet goto out; 8061c6fdbd8SKent Overstreet 8071c6fdbd8SKent Overstreet ret = bch2_alloc_ciphers(c); 8081c6fdbd8SKent Overstreet if (ret) 8091c6fdbd8SKent Overstreet goto out; 8101c6fdbd8SKent Overstreet 8111c6fdbd8SKent Overstreet ret = bch2_decrypt_sb_key(c, crypt, &key); 8121c6fdbd8SKent Overstreet if (ret) 8131c6fdbd8SKent Overstreet goto out; 8141c6fdbd8SKent Overstreet 8151c6fdbd8SKent Overstreet ret = crypto_skcipher_setkey(&c->chacha20->base, 8161c6fdbd8SKent Overstreet (void *) &key.key, sizeof(key.key)); 8171c6fdbd8SKent Overstreet if (ret) 8181c6fdbd8SKent Overstreet goto out; 8191c6fdbd8SKent Overstreet out: 8201c6fdbd8SKent Overstreet memzero_explicit(&key, sizeof(key)); 8211c6fdbd8SKent Overstreet return ret; 8221c6fdbd8SKent Overstreet } 823