📄 crypto.c
字号:
loff_t extent_offset; int rc = 0; ecryptfs_inode = page->mapping->host; crypt_stat = &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0, PAGE_CACHE_SIZE); if (rc) printk(KERN_ERR "%s: Error attempting to copy " "page at index [%ld]\n", __FUNCTION__, page->index); goto out; } enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); if (!enc_extent_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Error allocating memory for " "encrypted extent\n"); goto out; } enc_extent_page = virt_to_page(enc_extent_virt); for (extent_offset = 0; extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); extent_offset++) { loff_t offset; rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page, extent_offset); if (rc) { printk(KERN_ERR "%s: Error encrypting extent; " "rc = [%d]\n", __FUNCTION__, rc); goto out; } ecryptfs_lower_offset_for_extent( &offset, ((((loff_t)page->index) * (PAGE_CACHE_SIZE / crypt_stat->extent_size)) + extent_offset), crypt_stat); rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt, offset, crypt_stat->extent_size); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting " "to write lower page; rc = [%d]" "\n", rc); goto out; } }out: kfree(enc_extent_virt); return rc;}static int ecryptfs_decrypt_extent(struct page *page, struct ecryptfs_crypt_stat *crypt_stat, struct page *enc_extent_page, unsigned long extent_offset){ loff_t extent_base; char extent_iv[ECRYPTFS_MAX_IV_BYTES]; int rc; extent_base = (((loff_t)page->index) * (PAGE_CACHE_SIZE / crypt_stat->extent_size)); rc = ecryptfs_derive_iv(extent_iv, crypt_stat, (extent_base + extent_offset)); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting to " "derive IV for extent [0x%.16x]; " "rc = [%d]\n", (extent_base + extent_offset), rc); goto out; } if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Decrypting extent " "with iv:\n"); ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " "decryption:\n"); ecryptfs_dump_hex((char *) (page_address(enc_extent_page) + (extent_offset * crypt_stat->extent_size)), 8); } rc = ecryptfs_decrypt_page_offset(crypt_stat, page, (extent_offset * crypt_stat->extent_size), enc_extent_page, 0, crypt_stat->extent_size, extent_iv); if (rc < 0) { printk(KERN_ERR "%s: Error attempting to decrypt to page with " "page->index = [%ld], extent_offset = [%ld]; " "rc = [%d]\n", __FUNCTION__, page->index, extent_offset, rc); goto out; } rc = 0; if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; " "rc = [%d]\n", (extent_base + extent_offset), rc); ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " "decryption:\n"); ecryptfs_dump_hex((char *)(page_address(page) + (extent_offset * crypt_stat->extent_size)), 8); }out: return rc;}/** * ecryptfs_decrypt_page * @page: Page mapped from the eCryptfs inode for the file; data read * and decrypted from the lower file will be written into this * page * * Decrypt an eCryptfs page. This is done on a per-extent basis. Note * that eCryptfs pages may straddle the lower pages -- for instance, * if the file was created on a machine with an 8K page size * (resulting in an 8K header), and then the file is copied onto a * host with a 32K page size, then when reading page 0 of the eCryptfs * file, 24K of page 0 of the lower file will be read and decrypted, * and then 8K of page 1 of the lower file will be read and decrypted. * * Returns zero on success; negative on error */int ecryptfs_decrypt_page(struct page *page){ struct inode *ecryptfs_inode; struct ecryptfs_crypt_stat *crypt_stat; char *enc_extent_virt = NULL; struct page *enc_extent_page; unsigned long extent_offset; int rc = 0; ecryptfs_inode = page->mapping->host; crypt_stat = &(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment(page, page->index, 0, PAGE_CACHE_SIZE, ecryptfs_inode); if (rc) printk(KERN_ERR "%s: Error attempting to copy " "page at index [%ld]\n", __FUNCTION__, page->index); goto out; } enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); if (!enc_extent_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Error allocating memory for " "encrypted extent\n"); goto out; } enc_extent_page = virt_to_page(enc_extent_virt); for (extent_offset = 0; extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); extent_offset++) { loff_t offset; ecryptfs_lower_offset_for_extent( &offset, ((page->index * (PAGE_CACHE_SIZE / crypt_stat->extent_size)) + extent_offset), crypt_stat); rc = ecryptfs_read_lower(enc_extent_virt, offset, crypt_stat->extent_size, ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting " "to read lower page; rc = [%d]" "\n", rc); goto out; } rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page, extent_offset); if (rc) { printk(KERN_ERR "%s: Error encrypting extent; " "rc = [%d]\n", __FUNCTION__, rc); goto out; } }out: kfree(enc_extent_virt); return rc;}/** * decrypt_scatterlist * @crypt_stat: Cryptographic context * @dest_sg: The destination scatterlist to decrypt into * @src_sg: The source scatterlist to decrypt from * @size: The number of bytes to decrypt * @iv: The initialization vector to use for the decryption * * Returns the number of bytes decrypted; negative value on error */static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, struct scatterlist *dest_sg, struct scatterlist *src_sg, int size, unsigned char *iv){ struct blkcipher_desc desc = { .tfm = crypt_stat->tfm, .info = iv, .flags = CRYPTO_TFM_REQ_MAY_SLEEP }; int rc = 0; /* Consider doing this once, when the file is opened */ mutex_lock(&crypt_stat->cs_tfm_mutex); rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, crypt_stat->key_size); if (rc) { ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", rc); mutex_unlock(&crypt_stat->cs_tfm_mutex); rc = -EINVAL; goto out; } ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); mutex_unlock(&crypt_stat->cs_tfm_mutex); if (rc) { ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", rc); goto out; } rc = size;out: return rc;}/** * ecryptfs_encrypt_page_offset * @crypt_stat: The cryptographic context * @dst_page: The page to encrypt into * @dst_offset: The offset in the page to encrypt into * @src_page: The page to encrypt from * @src_offset: The offset in the page to encrypt from * @size: The number of bytes to encrypt * @iv: The initialization vector to use for the encryption * * Returns the number of bytes encrypted */static intecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, struct page *dst_page, int dst_offset, struct page *src_page, int src_offset, int size, unsigned char *iv){ struct scatterlist src_sg, dst_sg; sg_init_table(&src_sg, 1); sg_init_table(&dst_sg, 1); sg_set_page(&src_sg, src_page, size, src_offset); sg_set_page(&dst_sg, dst_page, size, dst_offset); return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);}/** * ecryptfs_decrypt_page_offset * @crypt_stat: The cryptographic context * @dst_page: The page to decrypt into * @dst_offset: The offset in the page to decrypt into * @src_page: The page to decrypt from * @src_offset: The offset in the page to decrypt from * @size: The number of bytes to decrypt * @iv: The initialization vector to use for the decryption * * Returns the number of bytes decrypted */static intecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat, struct page *dst_page, int dst_offset, struct page *src_page, int src_offset, int size, unsigned char *iv){ struct scatterlist src_sg, dst_sg; sg_init_table(&src_sg, 1); sg_set_page(&src_sg, src_page, size, src_offset); sg_init_table(&dst_sg, 1); sg_set_page(&dst_sg, dst_page, size, dst_offset); return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);}#define ECRYPTFS_MAX_SCATTERLIST_LEN 4/** * ecryptfs_init_crypt_ctx * @crypt_stat: Uninitilized crypt stats structure * * Initialize the crypto context. * * TODO: Performance: Keep a cache of initialized cipher contexts; * only init if needed */int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat){ char *full_alg_name; int rc = -EINVAL; if (!crypt_stat->cipher) { ecryptfs_printk(KERN_ERR, "No cipher specified\n"); goto out; } ecryptfs_printk(KERN_DEBUG, "Initializing cipher [%s]; strlen = [%d]; " "key_size_bits = [%d]\n", crypt_stat->cipher, (int)strlen(crypt_stat->cipher), crypt_stat->key_size << 3); if (crypt_stat->tfm) { rc = 0; goto out; } mutex_lock(&crypt_stat->cs_tfm_mutex); rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, crypt_stat->cipher, "cbc"); if (rc) goto out_unlock; crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC); kfree(full_alg_name); if (IS_ERR(crypt_stat->tfm)) { rc = PTR_ERR(crypt_stat->tfm); ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): " "Error initializing cipher [%s]\n", crypt_stat->cipher); goto out_unlock; } crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); rc = 0;out_unlock: mutex_unlock(&crypt_stat->cs_tfm_mutex);out: return rc;}static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat){ int extent_size_tmp; crypt_stat->extent_mask = 0xFFFFFFFF; crypt_stat->extent_shift = 0; if (crypt_stat->extent_size == 0) return; extent_size_tmp = crypt_stat->extent_size; while ((extent_size_tmp & 0x01) == 0) { extent_size_tmp >>= 1; crypt_stat->extent_mask <<= 1; crypt_stat->extent_shift++; }}void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat){ /* Default values; may be overwritten as we are parsing the * packets. */ crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE; set_extent_mask_and_shift(crypt_stat); crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) crypt_stat->num_header_extents_at_front = 0; else { if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) crypt_stat->num_header_extents_at_front = (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE / crypt_stat->extent_size); else crypt_stat->num_header_extents_at_front = (PAGE_CACHE_SIZE / crypt_stat->extent_size); }}/** * ecryptfs_compute_root_iv * @crypt_stats * * On error, sets the root IV to all 0's. */int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat){ int rc = 0; char dst[MD5_DIGEST_SIZE]; BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE); BUG_ON(crypt_stat->iv_bytes <= 0); if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Session key not valid; " "cannot generate root IV\n"); goto out; } rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key, crypt_stat->key_size); if (rc) { ecryptfs_printk(KERN_WARNING, "Error attempting to compute " "MD5 while generating root IV\n"); goto out; } memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);out: if (rc) { memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes); crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING; } return rc;}static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat){ get_random_bytes(crypt_stat->key, crypt_stat->key_size); crypt_stat->flags |= ECRYPTFS_KEY_VALID; ecryptfs_compute_root_iv(crypt_stat); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n"); ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); }}/** * ecryptfs_copy_mount_wide_flags_to_inode_flags * @crypt_stat: The inode's cryptographic context * @mount_crypt_stat: The mount point's cryptographic context * * This function propagates the mount-wide flags to individual inode * flags. */static void ecryptfs_copy_mount_wide_flags_to_inode_flags( struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_mount_crypt_stat *mount_crypt_stat){ if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED;}static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs( struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_mount_crypt_stat *mount_crypt_stat){ struct ecryptfs_global_auth_tok *global_auth_tok; int rc = 0; mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); list_for_each_entry(global_auth_tok, &mount_crypt_stat->global_auth_tok_list, mount_crypt_stat_list) { rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig); if (rc) { printk(KERN_ERR "Error adding keysig; rc = [%d]\n", rc); mutex_unlock( &mount_crypt_stat->global_auth_tok_list_mutex); goto out; } } mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);out: return rc;}/** * ecryptfs_set_default_crypt_stat_vals * @crypt_stat: The inode's cryptographic context * @mount_crypt_stat: The mount point's cryptographic context * * Default values in the event that policy does not override them. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -