Skip to content
Snippets Groups Projects
crypto.c 56.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    	ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
    
    	crypt_stat->flags |= (ECRYPTFS_ENCRYPTED | ECRYPTFS_KEY_VALID);
    
    	ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,
    						      mount_crypt_stat);
    	rc = ecryptfs_copy_mount_wide_sigs_to_inode_sigs(crypt_stat,
    							 mount_crypt_stat);
    	if (rc) {
    		printk(KERN_ERR "Error attempting to copy mount-wide key sigs "
    		       "to the inode key sigs; rc = [%d]\n", rc);
    		goto out;
    	}
    	cipher_name_len =
    		strlen(mount_crypt_stat->global_default_cipher_name);
    	memcpy(crypt_stat->cipher,
    	       mount_crypt_stat->global_default_cipher_name,
    	       cipher_name_len);
    	crypt_stat->cipher[cipher_name_len] = '\0';
    	crypt_stat->key_size =
    		mount_crypt_stat->global_default_cipher_key_size;
    	ecryptfs_generate_new_key(crypt_stat);
    
    	rc = ecryptfs_init_crypt_ctx(crypt_stat);
    	if (rc)
    		ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
    				"context for cipher [%s]: rc = [%d]\n",
    				crypt_stat->cipher, rc);
    
    	return rc;
    }
    
    /**
     * contains_ecryptfs_marker - check for the ecryptfs marker
     * @data: The data block in which to check
     *
     * Returns one if marker found; zero if not found
     */
    
    static int contains_ecryptfs_marker(char *data)
    
    	m_1 = get_unaligned_be32(data);
    	m_2 = get_unaligned_be32(data + 4);
    
    	if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
    		return 1;
    	ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
    			"MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
    			MAGIC_ECRYPTFS_MARKER);
    	ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
    			"[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
    	return 0;
    }
    
    struct ecryptfs_flag_map_elem {
    	u32 file_flag;
    	u32 local_flag;
    };
    
    /* Add support for additional flags by adding elements here. */
    static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
    	{0x00000001, ECRYPTFS_ENABLE_HMAC},
    
    	{0x00000002, ECRYPTFS_ENCRYPTED},
    	{0x00000004, ECRYPTFS_METADATA_IN_XATTR}
    
     * @crypt_stat: The cryptographic context
    
     * @page_virt: Source data to be parsed
     * @bytes_read: Updated with the number of bytes read
     *
     * Returns zero on success; non-zero if the flag set is invalid
     */
    static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,
    				  char *page_virt, int *bytes_read)
    {
    	int rc = 0;
    	int i;
    	u32 flags;
    
    
    	flags = get_unaligned_be32(page_virt);
    
    	for (i = 0; i < ((sizeof(ecryptfs_flag_map)
    			  / sizeof(struct ecryptfs_flag_map_elem))); i++)
    		if (flags & ecryptfs_flag_map[i].file_flag) {
    
    			crypt_stat->flags |= ecryptfs_flag_map[i].local_flag;
    
    			crypt_stat->flags &= ~(ecryptfs_flag_map[i].local_flag);
    
    	/* Version is in top 8 bits of the 32-bit flag vector */
    	crypt_stat->file_version = ((flags >> 24) & 0xFF);
    	(*bytes_read) = 4;
    	return rc;
    }
    
    /**
     * write_ecryptfs_marker
     * @page_virt: The pointer to in a page to begin writing the marker
     * @written: Number of bytes written
     *
     * Marker = 0x3c81b7f5
     */
    static void write_ecryptfs_marker(char *page_virt, size_t *written)
    {
    	u32 m_1, m_2;
    
    	get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
    	m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);
    
    	put_unaligned_be32(m_1, page_virt);
    	page_virt += (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2);
    	put_unaligned_be32(m_2, page_virt);
    
    	(*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
    }
    
    static void
    write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
    		     size_t *written)
    {
    	u32 flags = 0;
    	int i;
    
    	for (i = 0; i < ((sizeof(ecryptfs_flag_map)
    			  / sizeof(struct ecryptfs_flag_map_elem))); i++)
    
    		if (crypt_stat->flags & ecryptfs_flag_map[i].local_flag)
    
    			flags |= ecryptfs_flag_map[i].file_flag;
    	/* Version is in top 8 bits of the 32-bit flag vector */
    	flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000);
    
    	put_unaligned_be32(flags, page_virt);
    
    	(*written) = 4;
    }
    
    struct ecryptfs_cipher_code_str_map_elem {
    	char cipher_str[16];
    
    };
    
    /* Add support for additional ciphers by adding elements here. The
     * cipher_code is whatever OpenPGP applicatoins use to identify the
     * ciphers. List in order of probability. */
    static struct ecryptfs_cipher_code_str_map_elem
    ecryptfs_cipher_code_str_map[] = {
    	{"aes",RFC2440_CIPHER_AES_128 },
    	{"blowfish", RFC2440_CIPHER_BLOWFISH},
    	{"des3_ede", RFC2440_CIPHER_DES3_EDE},
    	{"cast5", RFC2440_CIPHER_CAST_5},
    	{"twofish", RFC2440_CIPHER_TWOFISH},
    	{"cast6", RFC2440_CIPHER_CAST_6},
    	{"aes", RFC2440_CIPHER_AES_192},
    	{"aes", RFC2440_CIPHER_AES_256}
    };
    
    /**
     * ecryptfs_code_for_cipher_string
    
     * @cipher_name: The string alias for the cipher
     * @key_bytes: Length of key in bytes; used for AES code selection
    
     *
     * Returns zero on no match, or the cipher code on match
     */
    
    u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes)
    
    	struct ecryptfs_cipher_code_str_map_elem *map =
    		ecryptfs_cipher_code_str_map;
    
    
    	if (strcmp(cipher_name, "aes") == 0) {
    		switch (key_bytes) {
    
    		case 16:
    			code = RFC2440_CIPHER_AES_128;
    			break;
    		case 24:
    			code = RFC2440_CIPHER_AES_192;
    			break;
    		case 32:
    			code = RFC2440_CIPHER_AES_256;
    		}
    	} else {
    		for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
    
    			if (strcmp(cipher_name, map[i].cipher_str) == 0) {
    
    				code = map[i].cipher_code;
    				break;
    			}
    	}
    	return code;
    }
    
    /**
     * ecryptfs_cipher_code_to_string
     * @str: Destination to write out the cipher name
     * @cipher_code: The code to convert to cipher name string
     *
     * Returns zero on success
     */
    
    int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)
    
    {
    	int rc = 0;
    	int i;
    
    	str[0] = '\0';
    	for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
    		if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
    			strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
    	if (str[0] == '\0') {
    		ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "
    				"[%d]\n", cipher_code);
    		rc = -EINVAL;
    	}
    	return rc;
    }
    
    
    int ecryptfs_read_and_validate_header_region(char *data,
    					     struct inode *ecryptfs_inode)
    
    	struct ecryptfs_crypt_stat *crypt_stat =
    		&(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);
    
    	rc = ecryptfs_read_lower(data, 0, crypt_stat->extent_size,
    				 ecryptfs_inode);
    	if (rc) {
    		printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",
    
    	}
    	if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {
    
    		ecryptfs_printk(KERN_DEBUG, "Valid marker not found\n");
    	}
    
    void
    ecryptfs_write_header_metadata(char *virt,
    			       struct ecryptfs_crypt_stat *crypt_stat,
    			       size_t *written)
    
    {
    	u32 header_extent_size;
    	u16 num_header_extents_at_front;
    
    
    	header_extent_size = (u32)crypt_stat->extent_size;
    
    	num_header_extents_at_front =
    
    		(u16)(crypt_stat->num_header_bytes_at_front
    		      / crypt_stat->extent_size);
    
    	put_unaligned_be32(header_extent_size, virt);
    
    	put_unaligned_be16(num_header_extents_at_front, virt);
    
    	(*written) = 6;
    }
    
    struct kmem_cache *ecryptfs_header_cache_1;
    struct kmem_cache *ecryptfs_header_cache_2;
    
    /**
     * ecryptfs_write_headers_virt
    
     * @page_virt: The virtual address to write the headers to
    
     * @max: The size of memory allocated at page_virt
    
     * @size: Set to the number of bytes written by this function
     * @crypt_stat: The cryptographic context
     * @ecryptfs_dentry: The eCryptfs dentry
    
     *
     * Format version: 1
     *
     *   Header Extent:
     *     Octets 0-7:        Unencrypted file size (big-endian)
     *     Octets 8-15:       eCryptfs special marker
     *     Octets 16-19:      Flags
     *      Octet 16:         File format version number (between 0 and 255)
     *      Octets 17-18:     Reserved
     *      Octet 19:         Bit 1 (lsb): Reserved
     *                        Bit 2: Encrypted?
     *                        Bits 3-8: Reserved
     *     Octets 20-23:      Header extent size (big-endian)
     *     Octets 24-25:      Number of header extents at front of file
     *                        (big-endian)
     *     Octet  26:         Begin RFC 2440 authentication token packet set
     *   Data Extent 0:
     *     Lower data (CBC encrypted)
     *   Data Extent 1:
     *     Lower data (CBC encrypted)
     *   ...
     *
     * Returns zero on success
     */
    
    static int ecryptfs_write_headers_virt(char *page_virt, size_t max,
    				       size_t *size,
    
    				       struct ecryptfs_crypt_stat *crypt_stat,
    				       struct dentry *ecryptfs_dentry)
    
    {
    	int rc;
    	size_t written;
    	size_t offset;
    
    	offset = ECRYPTFS_FILE_SIZE_BYTES;
    	write_ecryptfs_marker((page_virt + offset), &written);
    	offset += written;
    	write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
    	offset += written;
    
    	ecryptfs_write_header_metadata((page_virt + offset), crypt_stat,
    				       &written);
    
    	offset += written;
    	rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
    					      ecryptfs_dentry, &written,
    
    	if (rc)
    		ecryptfs_printk(KERN_WARNING, "Error generating key packet "
    				"set; rc = [%d]\n", rc);
    
    	if (size) {
    		offset += written;
    		*size = offset;
    	}
    	return rc;
    }
    
    
    static int
    ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
    
    				    struct dentry *ecryptfs_dentry,
    
    	rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,
    				  0, crypt_stat->num_header_bytes_at_front);
    	if (rc)
    
    		printk(KERN_ERR "%s: Error attempting to write header "
    
    		       "information to lower file; rc = [%d]\n", __func__,
    
    static int
    ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
    				 struct ecryptfs_crypt_stat *crypt_stat,
    				 char *page_virt, size_t size)
    
    {
    	int rc;
    
    	rc = ecryptfs_setxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, page_virt,
    			       size, 0);
    
     * ecryptfs_write_metadata
    
     * @ecryptfs_dentry: The eCryptfs dentry
    
     *
     * Write the file headers out.  This will likely involve a userspace
     * callout, in which the session key is encrypted with one or more
     * public keys and/or the passphrase necessary to do the encryption is
     * retrieved via a prompt.  Exactly what happens at this point should
     * be policy-dependent.
     *
     * Returns zero on success; non-zero on error
     */
    
    int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
    
    	struct ecryptfs_crypt_stat *crypt_stat =
    		&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
    
    	if (likely(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
    		if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
    
    			printk(KERN_ERR "Key is invalid; bailing out\n");
    
    			rc = -EINVAL;
    			goto out;
    		}
    	} else {
    
    		printk(KERN_WARNING "%s: Encrypted flag not set\n",
    
    		rc = -EINVAL;
    		goto out;
    	}
    	/* Released in this function */
    
    	virt = (char *)get_zeroed_page(GFP_KERNEL);
    
    		printk(KERN_ERR "%s: Out of memory\n", __func__);
    
    	rc = ecryptfs_write_headers_virt(virt, PAGE_CACHE_SIZE, &size,
    					 crypt_stat, ecryptfs_dentry);
    
    	if (unlikely(rc)) {
    
    		printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
    
    	if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
    		rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry,
    
    						      crypt_stat, virt, size);
    
    		rc = ecryptfs_write_metadata_to_contents(crypt_stat,
    
    							 ecryptfs_dentry, virt);
    
    		printk(KERN_ERR "%s: Error writing metadata out to lower file; "
    
    		       "rc = [%d]\n", __func__, rc);
    
    	free_page((unsigned long)virt);
    
    #define ECRYPTFS_DONT_VALIDATE_HEADER_SIZE 0
    #define ECRYPTFS_VALIDATE_HEADER_SIZE 1
    
    static 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;
    
    
    	header_extent_size = get_unaligned_be32(virt);
    	virt += sizeof(__be32);
    	num_header_extents_at_front = get_unaligned_be16(virt);
    
    	crypt_stat->num_header_bytes_at_front =
    		(((size_t)num_header_extents_at_front
    		  * (size_t)header_extent_size));
    
    	(*bytes_read) = (sizeof(__be32) + sizeof(__be16));
    
    	if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
    
    	    && (crypt_stat->num_header_bytes_at_front
    
    		< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
    
    		printk(KERN_WARNING "Invalid header size: [%zd]\n",
    		       crypt_stat->num_header_bytes_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_bytes_at_front =
    		ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
    
    }
    
    /**
     * 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;
    
    	size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,
    				       page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);
    
    		if (unlikely(ecryptfs_verbosity > 0))
    			printk(KERN_INFO "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",
    
    	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);
    
    		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
     */
    int
    ecryptfs_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
     */
    int
    ecryptfs_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.
     */
    
    ecryptfs_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;
    
    	*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);
    
    	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);
    
    	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;
    
    static 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;
    }
    
    
    /**
     * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list
     *
     * Called only at module unload time
     */
    
    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;
    }
    
    int
    ecryptfs_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;
    
    
    	BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
    
    
    	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;
    	}
    	list_add(&tmp_tfm->key_tfm_list, &key_tfm_list);
    out:
    	return rc;
    }
    
    
    /**
     * ecryptfs_tfm_exists - Search for existing tfm for cipher_name.
     * @cipher_name: the name of the cipher to search for
     * @key_tfm: set to corresponding tfm if found
     *
     * Searches for cached key_tfm matching @cipher_name
     * Must be called with &key_tfm_list_mutex held
     * Returns 1 if found, with @key_tfm set
     * Returns 0 if not found, with @key_tfm set to NULL
     */
    int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm)
    {
    	struct ecryptfs_key_tfm *tmp_key_tfm;
    
    	BUG_ON(!mutex_is_locked(&key_tfm_list_mutex));
    
    	list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) {
    		if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) {
    			if (key_tfm)
    				(*key_tfm) = tmp_key_tfm;
    			return 1;
    		}
    	}
    	if (key_tfm)
    		(*key_tfm) = NULL;
    	return 0;
    }
    
    /**
     * ecryptfs_get_tfm_and_mutex_for_cipher_name
     *
     * @tfm: set to cached tfm found, or new tfm created
     * @tfm_mutex: set to mutex for cached tfm found, or new tfm created
     * @cipher_name: the name of the cipher to search for and/or add
     *
     * Sets pointers to @tfm & @tfm_mutex matching @cipher_name.
     * Searches for cached item first, and creates new if not found.
     * Returns 0 on success, non-zero if adding new cipher failed
     */
    
    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);
    
    	if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) {
    		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:
    
    	mutex_unlock(&key_tfm_list_mutex);