📄 crypto.c
字号:
static void ecryptfs_set_default_crypt_stat_vals( struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_mount_crypt_stat *mount_crypt_stat){ ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, mount_crypt_stat); ecryptfs_set_default_sizes(crypt_stat); strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER); crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES; crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); crypt_stat->file_version = ECRYPTFS_FILE_VERSION; crypt_stat->mount_crypt_stat = mount_crypt_stat;}/** * ecryptfs_new_file_context * @ecryptfs_dentry: The eCryptfs dentry * * If the crypto context for the file has not yet been established, * this is where we do that. Establishing a new crypto context * involves the following decisions: * - What cipher to use? * - What set of authentication tokens to use? * Here we just worry about getting enough information into the * authentication tokens so that we know that they are available. * We associate the available authentication tokens with the new file * via the set of signatures in the crypt_stat struct. Later, when * the headers are actually written out, we may again defer to * userspace to perform the encryption of the session key; for the * foreseeable future, this will be the case with public key packets. * * Returns zero on success; non-zero otherwise */int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry){ struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; int cipher_name_len; int rc = 0; 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);out: 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){ u32 m_1, m_2; memcpy(&m_1, data, 4); m_1 = be32_to_cpu(m_1); memcpy(&m_2, (data + 4), 4); m_2 = be32_to_cpu(m_2); 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}};/** * ecryptfs_process_flags * @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; memcpy(&flags, page_virt, 4); flags = be32_to_cpu(flags); 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; } else 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); m_1 = cpu_to_be32(m_1); memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2)); m_2 = cpu_to_be32(m_2); memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2)); (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;}static voidwrite_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); flags = cpu_to_be32(flags); memcpy(page_virt, &flags, 4); (*written) = 4;}struct ecryptfs_cipher_code_str_map_elem { char cipher_str[16]; u16 cipher_code;};/* 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_elemecryptfs_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 * @crypt_stat: The cryptographic context * * Returns zero on no match, or the cipher code on match */u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat){ int i; u16 code = 0; struct ecryptfs_cipher_code_str_map_elem *map = ecryptfs_cipher_code_str_map; if (strcmp(crypt_stat->cipher, "aes") == 0) { switch (crypt_stat->key_size) { 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(crypt_stat->cipher, 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, u16 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); int rc; 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", __FUNCTION__, rc); goto out; } if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) { rc = -EINVAL; ecryptfs_printk(KERN_DEBUG, "Valid marker not found\n"); }out: return rc;}voidecryptfs_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_extents_at_front; header_extent_size = cpu_to_be32(header_extent_size); memcpy(virt, &header_extent_size, 4); virt += 4; num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front); memcpy(virt, &num_header_extents_at_front, 2); (*written) = 6;}struct kmem_cache *ecryptfs_header_cache_0;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 * @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 *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, PAGE_CACHE_SIZE - offset); if (rc) ecryptfs_printk(KERN_WARNING, "Error generating key packet " "set; rc = [%d]\n", rc); if (size) { offset += written; *size = offset; } return rc;}static intecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry, char *page_virt){ int current_header_page; int header_pages; int rc; rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, 0, PAGE_CACHE_SIZE); if (rc) { printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __FUNCTION__, rc); goto out; } header_pages = ((crypt_stat->extent_size * crypt_stat->num_header_extents_at_front) / PAGE_CACHE_SIZE); memset(page_virt, 0, PAGE_CACHE_SIZE); current_header_page = 1; while (current_header_page < header_pages) { loff_t offset; offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT); if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, offset, PAGE_CACHE_SIZE))) { printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __FUNCTION__, rc); goto out; } current_header_page++; }out: return rc;}static intecryptfs_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); return rc;}/** * 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. * * TODO: Support header information spanning multiple pages * * 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; char *page_virt; size_t size = 0; int rc = 0; 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 { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Called with crypt_stat->encrypted == 0\n"); goto out; } /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); if (!page_virt) { ecryptfs_printk(KERN_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, ecryptfs_dentry); if (unlikely(rc)) { ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); memset(page_virt, 0, PAGE_CACHE_SIZE); goto out_free; } if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, crypt_stat, page_virt, size); else rc = ecryptfs_write_metadata_to_contents(crypt_stat, ecryptfs_dentry, page_virt); if (rc) { printk(KERN_ERR "Error writing metadata out to lower file; " "rc = [%d]\n", rc); goto out_free; }out_free: kmem_cache_free(ecryptfs_header_cache_0, page_virt);out: return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -