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

📄 crypto.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#define ECRYPTFS_DONT_VALIDATE_HEADER_SIZE 0#define ECRYPTFS_VALIDATE_HEADER_SIZE 1static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,				 char *virt, int *bytes_read,				 int validate_header_size){	int rc = 0;	u32 header_extent_size;	u16 num_header_extents_at_front;	memcpy(&header_extent_size, virt, sizeof(u32));	header_extent_size = be32_to_cpu(header_extent_size);	virt += sizeof(u32);	memcpy(&num_header_extents_at_front, virt, sizeof(u16));	num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);	crypt_stat->num_header_extents_at_front =		(int)num_header_extents_at_front;	(*bytes_read) = (sizeof(u32) + sizeof(u16));	if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)	    && ((crypt_stat->extent_size		 * crypt_stat->num_header_extents_at_front)		< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {		rc = -EINVAL;		printk(KERN_WARNING "Invalid number of header extents: [%zd]\n",		       crypt_stat->num_header_extents_at_front);	}	return rc;}/** * set_default_header_data * @crypt_stat: The cryptographic context * * For version 0 file format; this function is only for backwards * compatibility for files created with the prior versions of * eCryptfs. */static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat){	crypt_stat->num_header_extents_at_front = 2;}/** * ecryptfs_read_headers_virt * @page_virt: The virtual address into which to read the headers * @crypt_stat: The cryptographic context * @ecryptfs_dentry: The eCryptfs dentry * @validate_header_size: Whether to validate the header size while reading * * Read/parse the header data. The header format is detailed in the * comment block for the ecryptfs_write_headers_virt() function. * * Returns zero on success */static int ecryptfs_read_headers_virt(char *page_virt,				      struct ecryptfs_crypt_stat *crypt_stat,				      struct dentry *ecryptfs_dentry,				      int validate_header_size){	int rc = 0;	int offset;	int bytes_read;	ecryptfs_set_default_sizes(crypt_stat);	crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(		ecryptfs_dentry->d_sb)->mount_crypt_stat;	offset = ECRYPTFS_FILE_SIZE_BYTES;	rc = contains_ecryptfs_marker(page_virt + offset);	if (rc == 0) {		rc = -EINVAL;		goto out;	}	offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;	rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),				    &bytes_read);	if (rc) {		ecryptfs_printk(KERN_WARNING, "Error processing flags\n");		goto out;	}	if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {		ecryptfs_printk(KERN_WARNING, "File version is [%d]; only "				"file version [%d] is supported by this "				"version of eCryptfs\n",				crypt_stat->file_version,				ECRYPTFS_SUPPORTED_FILE_VERSION);		rc = -EINVAL;		goto out;	}	offset += bytes_read;	if (crypt_stat->file_version >= 1) {		rc = parse_header_metadata(crypt_stat, (page_virt + offset),					   &bytes_read, validate_header_size);		if (rc) {			ecryptfs_printk(KERN_WARNING, "Error reading header "					"metadata; rc = [%d]\n", rc);		}		offset += bytes_read;	} else		set_default_header_data(crypt_stat);	rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),				       ecryptfs_dentry);out:	return rc;}/** * ecryptfs_read_xattr_region * @page_virt: The vitual address into which to read the xattr data * @ecryptfs_inode: The eCryptfs inode * * Attempts to read the crypto metadata from the extended attribute * region of the lower file. * * Returns zero on success; non-zero on error */int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode){	struct dentry *lower_dentry =		ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;	ssize_t size;	int rc = 0;	size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,				       page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);	if (size < 0) {		printk(KERN_ERR "Error attempting to read the [%s] "		       "xattr from the lower file; return value = [%zd]\n",		       ECRYPTFS_XATTR_NAME, size);		rc = -EINVAL;		goto out;	}out:	return rc;}int ecryptfs_read_and_validate_xattr_region(char *page_virt,					    struct dentry *ecryptfs_dentry){	int rc;	rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry->d_inode);	if (rc)		goto out;	if (!contains_ecryptfs_marker(page_virt	+ ECRYPTFS_FILE_SIZE_BYTES)) {		printk(KERN_WARNING "Valid data found in [%s] xattr, but "			"the marker is invalid\n", ECRYPTFS_XATTR_NAME);		rc = -EINVAL;	}out:	return rc;}/** * ecryptfs_read_metadata * * Common entry point for reading file metadata. From here, we could * retrieve the header information from the header region of the file, * the xattr region of the file, or some other repostory that is * stored separately from the file itself. The current implementation * supports retrieving the metadata information from the file contents * and from the xattr region. * * Returns zero if valid headers found and parsed; non-zero otherwise */int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry){	int rc = 0;	char *page_virt = NULL;	struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;	struct ecryptfs_crypt_stat *crypt_stat =	    &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =		&ecryptfs_superblock_to_private(			ecryptfs_dentry->d_sb)->mount_crypt_stat;	ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,						      mount_crypt_stat);	/* Read the first page from the underlying file */	page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER);	if (!page_virt) {		rc = -ENOMEM;		printk(KERN_ERR "%s: Unable to allocate page_virt\n",		       __FUNCTION__);		goto out;	}	rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size,				 ecryptfs_inode);	if (!rc)		rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,						ecryptfs_dentry,						ECRYPTFS_VALIDATE_HEADER_SIZE);	if (rc) {		rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);		if (rc) {			printk(KERN_DEBUG "Valid eCryptfs headers not found in "			       "file header region or xattr region\n");			rc = -EINVAL;			goto out;		}		rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,						ecryptfs_dentry,						ECRYPTFS_DONT_VALIDATE_HEADER_SIZE);		if (rc) {			printk(KERN_DEBUG "Valid eCryptfs headers not found in "			       "file xattr region either\n");			rc = -EINVAL;		}		if (crypt_stat->mount_crypt_stat->flags		    & ECRYPTFS_XATTR_METADATA_ENABLED) {			crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;		} else {			printk(KERN_WARNING "Attempt to access file with "			       "crypto metadata only in the extended attribute "			       "region, but eCryptfs was mounted without "			       "xattr support enabled. eCryptfs will not treat "			       "this like an encrypted file.\n");			rc = -EINVAL;		}	}out:	if (page_virt) {		memset(page_virt, 0, PAGE_CACHE_SIZE);		kmem_cache_free(ecryptfs_header_cache_1, page_virt);	}	return rc;}/** * ecryptfs_encode_filename - converts a plaintext file name to cipher text * @crypt_stat: The crypt_stat struct associated with the file anem to encode * @name: The plaintext name * @length: The length of the plaintext * @encoded_name: The encypted name * * Encrypts and encodes a filename into something that constitutes a * valid filename for a filesystem, with printable characters. * * We assume that we have a properly initialized crypto context, * pointed to by crypt_stat->tfm. * * TODO: Implement filename decoding and decryption here, in place of * memcpy. We are keeping the framework around for now to (1) * facilitate testing of the components needed to implement filename * encryption and (2) to provide a code base from which other * developers in the community can easily implement this feature. * * Returns the length of encoded filename; negative if error */intecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,			 const char *name, int length, char **encoded_name){	int error = 0;	(*encoded_name) = kmalloc(length + 2, GFP_KERNEL);	if (!(*encoded_name)) {		error = -ENOMEM;		goto out;	}	/* TODO: Filename encryption is a scheduled feature for a	 * future version of eCryptfs. This function is here only for	 * the purpose of providing a framework for other developers	 * to easily implement filename encryption. Hint: Replace this	 * memcpy() with a call to encrypt and encode the	 * filename, the set the length accordingly. */	memcpy((void *)(*encoded_name), (void *)name, length);	(*encoded_name)[length] = '\0';	error = length + 1;out:	return error;}/** * ecryptfs_decode_filename - converts the cipher text name to plaintext * @crypt_stat: The crypt_stat struct associated with the file * @name: The filename in cipher text * @length: The length of the cipher text name * @decrypted_name: The plaintext name * * Decodes and decrypts the filename. * * We assume that we have a properly initialized crypto context, * pointed to by crypt_stat->tfm. * * TODO: Implement filename decoding and decryption here, in place of * memcpy. We are keeping the framework around for now to (1) * facilitate testing of the components needed to implement filename * encryption and (2) to provide a code base from which other * developers in the community can easily implement this feature. * * Returns the length of decoded filename; negative if error */intecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,			 const char *name, int length, char **decrypted_name){	int error = 0;	(*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);	if (!(*decrypted_name)) {		error = -ENOMEM;		goto out;	}	/* TODO: Filename encryption is a scheduled feature for a	 * future version of eCryptfs. This function is here only for	 * the purpose of providing a framework for other developers	 * to easily implement filename encryption. Hint: Replace this	 * memcpy() with a call to decode and decrypt the	 * filename, the set the length accordingly. */	memcpy((void *)(*decrypted_name), (void *)name, length);	(*decrypted_name)[length + 1] = '\0';	/* Only for convenience						 * in printing out the						 * string in debug						 * messages */	error = length;out:	return error;}/** * ecryptfs_process_key_cipher - Perform key cipher initialization. * @key_tfm: Crypto context for key material, set by this function * @cipher_name: Name of the cipher * @key_size: Size of the key in bytes * * Returns zero on success. Any crypto_tfm structs allocated here * should be released by other functions, such as on a superblock put * event, regardless of whether this function succeeds for fails. */static intecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm,			    char *cipher_name, size_t *key_size){	char dummy_key[ECRYPTFS_MAX_KEY_BYTES];	char *full_alg_name;	int rc;	*key_tfm = NULL;	if (*key_size > ECRYPTFS_MAX_KEY_BYTES) {		rc = -EINVAL;		printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum "		      "allowable is [%d]\n", *key_size, ECRYPTFS_MAX_KEY_BYTES);		goto out;	}	rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, cipher_name,						    "ecb");	if (rc)		goto out;	*key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC);	kfree(full_alg_name);	if (IS_ERR(*key_tfm)) {		rc = PTR_ERR(*key_tfm);		printk(KERN_ERR "Unable to allocate crypto cipher with name "		       "[%s]; rc = [%d]\n", cipher_name, rc);		goto out;	}	crypto_blkcipher_set_flags(*key_tfm, CRYPTO_TFM_REQ_WEAK_KEY);	if (*key_size == 0) {		struct blkcipher_alg *alg = crypto_blkcipher_alg(*key_tfm);		*key_size = alg->max_keysize;	}	get_random_bytes(dummy_key, *key_size);	rc = crypto_blkcipher_setkey(*key_tfm, dummy_key, *key_size);	if (rc) {		printk(KERN_ERR "Error attempting to set key of size [%Zd] for "		       "cipher [%s]; rc = [%d]\n", *key_size, cipher_name, rc);		rc = -EINVAL;		goto out;	}out:	return rc;}struct kmem_cache *ecryptfs_key_tfm_cache;struct list_head key_tfm_list;struct mutex key_tfm_list_mutex;int ecryptfs_init_crypto(void){	mutex_init(&key_tfm_list_mutex);	INIT_LIST_HEAD(&key_tfm_list);	return 0;}int ecryptfs_destroy_crypto(void){	struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;	mutex_lock(&key_tfm_list_mutex);	list_for_each_entry_safe(key_tfm, key_tfm_tmp, &key_tfm_list,				 key_tfm_list) {		list_del(&key_tfm->key_tfm_list);		if (key_tfm->key_tfm)			crypto_free_blkcipher(key_tfm->key_tfm);		kmem_cache_free(ecryptfs_key_tfm_cache, key_tfm);	}	mutex_unlock(&key_tfm_list_mutex);	return 0;}intecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,			 size_t key_size){	struct ecryptfs_key_tfm *tmp_tfm;	int rc = 0;	tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);	if (key_tfm != NULL)		(*key_tfm) = tmp_tfm;	if (!tmp_tfm) {		rc = -ENOMEM;		printk(KERN_ERR "Error attempting to allocate from "		       "ecryptfs_key_tfm_cache\n");		goto out;	}	mutex_init(&tmp_tfm->key_tfm_mutex);	strncpy(tmp_tfm->cipher_name, cipher_name,		ECRYPTFS_MAX_CIPHER_NAME_SIZE);	tmp_tfm->cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';	tmp_tfm->key_size = key_size;	rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm,					 tmp_tfm->cipher_name,					 &tmp_tfm->key_size);	if (rc) {		printk(KERN_ERR "Error attempting to initialize key TFM "		       "cipher with name = [%s]; rc = [%d]\n",		       tmp_tfm->cipher_name, rc);		kmem_cache_free(ecryptfs_key_tfm_cache, tmp_tfm);		if (key_tfm != NULL)			(*key_tfm) = NULL;		goto out;	}	mutex_lock(&key_tfm_list_mutex);	list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);	mutex_unlock(&key_tfm_list_mutex);out:	return rc;}int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,					       struct mutex **tfm_mutex,					       char *cipher_name){	struct ecryptfs_key_tfm *key_tfm;	int rc = 0;	(*tfm) = NULL;	(*tfm_mutex) = NULL;	mutex_lock(&key_tfm_list_mutex);	list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) {		if (strcmp(key_tfm->cipher_name, cipher_name) == 0) {			(*tfm) = key_tfm->key_tfm;			(*tfm_mutex) = &key_tfm->key_tfm_mutex;			mutex_unlock(&key_tfm_list_mutex);			goto out;		}	}	mutex_unlock(&key_tfm_list_mutex);	rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0);	if (rc) {		printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n",		       rc);		goto out;	}	(*tfm) = key_tfm->key_tfm;	(*tfm_mutex) = &key_tfm->key_tfm_mutex;out:	return rc;}

⌨️ 快捷键说明

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