⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 crypto.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University * Copyright (C) 2004-2007 International Business Machines Corp. *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> *   		Michael C. Thompson <mcthomps@us.ibm.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <linux/fs.h>#include <linux/mount.h>#include <linux/pagemap.h>#include <linux/random.h>#include <linux/compiler.h>#include <linux/key.h>#include <linux/namei.h>#include <linux/crypto.h>#include <linux/file.h>#include <linux/scatterlist.h>#include "ecryptfs_kernel.h"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);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);/** * ecryptfs_to_hex * @dst: Buffer to take hex character representation of contents of *       src; must be at least of size (src_size * 2) * @src: Buffer to be converted to a hex string respresentation * @src_size: number of bytes to convert */void ecryptfs_to_hex(char *dst, char *src, size_t src_size){	int x;	for (x = 0; x < src_size; x++)		sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);}/** * ecryptfs_from_hex * @dst: Buffer to take the bytes from src hex; must be at least of *       size (src_size / 2) * @src: Buffer to be converted from a hex string respresentation to raw value * @dst_size: size of dst buffer, or number of hex characters pairs to convert */void ecryptfs_from_hex(char *dst, char *src, int dst_size){	int x;	char tmp[3] = { 0, };	for (x = 0; x < dst_size; x++) {		tmp[0] = src[x * 2];		tmp[1] = src[x * 2 + 1];		dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);	}}/** * ecryptfs_calculate_md5 - calculates the md5 of @src * @dst: Pointer to 16 bytes of allocated memory * @crypt_stat: Pointer to crypt_stat struct for the current inode * @src: Data to be md5'd * @len: Length of @src * * Uses the allocated crypto context that crypt_stat references to * generate the MD5 sum of the contents of src. */static int ecryptfs_calculate_md5(char *dst,				  struct ecryptfs_crypt_stat *crypt_stat,				  char *src, int len){	struct scatterlist sg;	struct hash_desc desc = {		.tfm = crypt_stat->hash_tfm,		.flags = CRYPTO_TFM_REQ_MAY_SLEEP	};	int rc = 0;	mutex_lock(&crypt_stat->cs_hash_tfm_mutex);	sg_init_one(&sg, (u8 *)src, len);	if (!desc.tfm) {		desc.tfm = crypto_alloc_hash(ECRYPTFS_DEFAULT_HASH, 0,					     CRYPTO_ALG_ASYNC);		if (IS_ERR(desc.tfm)) {			rc = PTR_ERR(desc.tfm);			ecryptfs_printk(KERN_ERR, "Error attempting to "					"allocate crypto context; rc = [%d]\n",					rc);			goto out;		}		crypt_stat->hash_tfm = desc.tfm;	}	rc = crypto_hash_init(&desc);	if (rc) {		printk(KERN_ERR		       "%s: Error initializing crypto hash; rc = [%d]\n",		       __FUNCTION__, rc);		goto out;	}	rc = crypto_hash_update(&desc, &sg, len);	if (rc) {		printk(KERN_ERR		       "%s: Error updating crypto hash; rc = [%d]\n",		       __FUNCTION__, rc);		goto out;	}	rc = crypto_hash_final(&desc, dst);	if (rc) {		printk(KERN_ERR		       "%s: Error finalizing crypto hash; rc = [%d]\n",		       __FUNCTION__, rc);		goto out;	}out:	mutex_unlock(&crypt_stat->cs_hash_tfm_mutex);	return rc;}static int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,						  char *cipher_name,						  char *chaining_modifier){	int cipher_name_len = strlen(cipher_name);	int chaining_modifier_len = strlen(chaining_modifier);	int algified_name_len;	int rc;	algified_name_len = (chaining_modifier_len + cipher_name_len + 3);	(*algified_name) = kmalloc(algified_name_len, GFP_KERNEL);	if (!(*algified_name)) {		rc = -ENOMEM;		goto out;	}	snprintf((*algified_name), algified_name_len, "%s(%s)",		 chaining_modifier, cipher_name);	rc = 0;out:	return rc;}/** * ecryptfs_derive_iv * @iv: destination for the derived iv vale * @crypt_stat: Pointer to crypt_stat struct for the current inode * @offset: Offset of the extent whose IV we are to derive * * Generate the initialization vector from the given root IV and page * offset. * * Returns zero on success; non-zero on error. */static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,			      loff_t offset){	int rc = 0;	char dst[MD5_DIGEST_SIZE];	char src[ECRYPTFS_MAX_IV_BYTES + 16];	if (unlikely(ecryptfs_verbosity > 0)) {		ecryptfs_printk(KERN_DEBUG, "root iv:\n");		ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);	}	/* TODO: It is probably secure to just cast the least	 * significant bits of the root IV into an unsigned long and	 * add the offset to that rather than go through all this	 * hashing business. -Halcrow */	memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);	memset((src + crypt_stat->iv_bytes), 0, 16);	snprintf((src + crypt_stat->iv_bytes), 16, "%lld", offset);	if (unlikely(ecryptfs_verbosity > 0)) {		ecryptfs_printk(KERN_DEBUG, "source:\n");		ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));	}	rc = ecryptfs_calculate_md5(dst, crypt_stat, src,				    (crypt_stat->iv_bytes + 16));	if (rc) {		ecryptfs_printk(KERN_WARNING, "Error attempting to compute "				"MD5 while generating IV for a page\n");		goto out;	}	memcpy(iv, dst, crypt_stat->iv_bytes);	if (unlikely(ecryptfs_verbosity > 0)) {		ecryptfs_printk(KERN_DEBUG, "derived iv:\n");		ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);	}out:	return rc;}/** * ecryptfs_init_crypt_stat * @crypt_stat: Pointer to the crypt_stat struct to initialize. * * Initialize the crypt_stat structure. */voidecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat){	memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));	INIT_LIST_HEAD(&crypt_stat->keysig_list);	mutex_init(&crypt_stat->keysig_list_mutex);	mutex_init(&crypt_stat->cs_mutex);	mutex_init(&crypt_stat->cs_tfm_mutex);	mutex_init(&crypt_stat->cs_hash_tfm_mutex);	crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED;}/** * ecryptfs_destroy_crypt_stat * @crypt_stat: Pointer to the crypt_stat struct to initialize. * * Releases all memory associated with a crypt_stat struct. */void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat){	struct ecryptfs_key_sig *key_sig, *key_sig_tmp;	if (crypt_stat->tfm)		crypto_free_blkcipher(crypt_stat->tfm);	if (crypt_stat->hash_tfm)		crypto_free_hash(crypt_stat->hash_tfm);	mutex_lock(&crypt_stat->keysig_list_mutex);	list_for_each_entry_safe(key_sig, key_sig_tmp,				 &crypt_stat->keysig_list, crypt_stat_list) {		list_del(&key_sig->crypt_stat_list);		kmem_cache_free(ecryptfs_key_sig_cache, key_sig);	}	mutex_unlock(&crypt_stat->keysig_list_mutex);	memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));}void ecryptfs_destroy_mount_crypt_stat(	struct ecryptfs_mount_crypt_stat *mount_crypt_stat){	struct ecryptfs_global_auth_tok *auth_tok, *auth_tok_tmp;	if (!(mount_crypt_stat->flags & ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED))		return;	mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex);	list_for_each_entry_safe(auth_tok, auth_tok_tmp,				 &mount_crypt_stat->global_auth_tok_list,				 mount_crypt_stat_list) {		list_del(&auth_tok->mount_crypt_stat_list);		mount_crypt_stat->num_global_auth_toks--;		if (auth_tok->global_auth_tok_key		    && !(auth_tok->flags & ECRYPTFS_AUTH_TOK_INVALID))			key_put(auth_tok->global_auth_tok_key);		kmem_cache_free(ecryptfs_global_auth_tok_cache, auth_tok);	}	mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex);	memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));}/** * virt_to_scatterlist * @addr: Virtual address * @size: Size of data; should be an even multiple of the block size * @sg: Pointer to scatterlist array; set to NULL to obtain only *      the number of scatterlist structs required in array * @sg_size: Max array size * * Fills in a scatterlist array with page references for a passed * virtual address. * * Returns the number of scatterlist structs in array used */int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,			int sg_size){	int i = 0;	struct page *pg;	int offset;	int remainder_of_page;	sg_init_table(sg, sg_size);	while (size > 0 && i < sg_size) {		pg = virt_to_page(addr);		offset = offset_in_page(addr);		if (sg)			sg_set_page(&sg[i], pg, 0, offset);		remainder_of_page = PAGE_CACHE_SIZE - offset;		if (size >= remainder_of_page) {			if (sg)				sg[i].length = remainder_of_page;			addr += remainder_of_page;			size -= remainder_of_page;		} else {			if (sg)				sg[i].length = size;			addr += size;			size = 0;		}		i++;	}	if (size > 0)		return -ENOMEM;	return i;}/** * encrypt_scatterlist * @crypt_stat: Pointer to the crypt_stat struct to initialize. * @dest_sg: Destination of encrypted data * @src_sg: Data to be encrypted * @size: Length of data to be encrypted * @iv: iv to use during encryption * * Returns the number of bytes encrypted; negative value on error */static int encrypt_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;	BUG_ON(!crypt_stat || !crypt_stat->tfm	       || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));	if (unlikely(ecryptfs_verbosity > 0)) {		ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",				crypt_stat->key_size);		ecryptfs_dump_hex(crypt_stat->key,				  crypt_stat->key_size);	}	/* 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, "Encrypting [%d] bytes.\n", size);	crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size);	mutex_unlock(&crypt_stat->cs_tfm_mutex);out:	return rc;}/** * ecryptfs_lower_offset_for_extent * * Convert an eCryptfs page index into a lower byte offset */void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,				      struct ecryptfs_crypt_stat *crypt_stat){	(*offset) = ((crypt_stat->extent_size		      * crypt_stat->num_header_extents_at_front)		     + (crypt_stat->extent_size * extent_num));}/** * ecryptfs_encrypt_extent * @enc_extent_page: Allocated page into which to encrypt the data in *                   @page * @crypt_stat: crypt_stat containing cryptographic context for the *              encryption operation * @page: Page containing plaintext data extent to encrypt * @extent_offset: Page extent offset for use in generating IV * * Encrypts one extent of data. * * Return zero on success; non-zero otherwise */static int ecryptfs_encrypt_extent(struct page *enc_extent_page,				   struct ecryptfs_crypt_stat *crypt_stat,				   struct page *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, "Encrypting extent "				"with iv:\n");		ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);		ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "				"encryption:\n");		ecryptfs_dump_hex((char *)				  (page_address(page)				   + (extent_offset * crypt_stat->extent_size)),				  8);	}	rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,					  page, (extent_offset						 * crypt_stat->extent_size),					  crypt_stat->extent_size, extent_iv);	if (rc < 0) {		printk(KERN_ERR "%s: Error attempting to encrypt 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, "Encrypt extent [0x%.16x]; "				"rc = [%d]\n", (extent_base + extent_offset),				rc);		ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "				"encryption:\n");		ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);	}out:	return rc;}/** * ecryptfs_encrypt_page * @page: Page mapped from the eCryptfs inode for the file; contains *        decrypted content that needs to be encrypted (to a temporary *        page; not in place) and written out to the lower file * * Encrypt 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_encrypt_page(struct page *page){	struct inode *ecryptfs_inode;	struct ecryptfs_crypt_stat *crypt_stat;	char *enc_extent_virt = NULL;	struct page *enc_extent_page;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -