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

📄 keystore.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * eCryptfs: Linux filesystem encryption layer * In-kernel key management code.  Includes functions to parse and * write authentication token-related packets with the underlying * file. * * Copyright (C) 2004-2006 International Business Machines Corp. *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> *              Michael C. Thompson <mcthomps@us.ibm.com> *              Trevor S. Highland <trevor.highland@gmail.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/string.h>#include <linux/syscalls.h>#include <linux/pagemap.h>#include <linux/key.h>#include <linux/random.h>#include <linux/crypto.h>#include <linux/scatterlist.h>#include "ecryptfs_kernel.h"/** * request_key returned an error instead of a valid key address; * determine the type of error, make appropriate log entries, and * return an error code. */static int process_request_key_err(long err_code){	int rc = 0;	switch (err_code) {	case ENOKEY:		ecryptfs_printk(KERN_WARNING, "No key\n");		rc = -ENOENT;		break;	case EKEYEXPIRED:		ecryptfs_printk(KERN_WARNING, "Key expired\n");		rc = -ETIME;		break;	case EKEYREVOKED:		ecryptfs_printk(KERN_WARNING, "Key revoked\n");		rc = -EINVAL;		break;	default:		ecryptfs_printk(KERN_WARNING, "Unknown error code: "				"[0x%.16x]\n", err_code);		rc = -EINVAL;	}	return rc;}/** * parse_packet_length * @data: Pointer to memory containing length at offset * @size: This function writes the decoded size to this memory *        address; zero on error * @length_size: The number of bytes occupied by the encoded length * * Returns zero on success; non-zero on error */static int parse_packet_length(unsigned char *data, size_t *size,			       size_t *length_size){	int rc = 0;	(*length_size) = 0;	(*size) = 0;	if (data[0] < 192) {		/* One-byte length */		(*size) = (unsigned char)data[0];		(*length_size) = 1;	} else if (data[0] < 224) {		/* Two-byte length */		(*size) = (((unsigned char)(data[0]) - 192) * 256);		(*size) += ((unsigned char)(data[1]) + 192);		(*length_size) = 2;	} else if (data[0] == 255) {		/* Five-byte length; we're not supposed to see this */		ecryptfs_printk(KERN_ERR, "Five-byte packet length not "				"supported\n");		rc = -EINVAL;		goto out;	} else {		ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");		rc = -EINVAL;		goto out;	}out:	return rc;}/** * write_packet_length * @dest: The byte array target into which to write the length. Must *        have at least 5 bytes allocated. * @size: The length to write. * @packet_size_length: The number of bytes used to encode the packet *                      length is written to this address. * * Returns zero on success; non-zero on error. */static int write_packet_length(char *dest, size_t size,			       size_t *packet_size_length){	int rc = 0;	if (size < 192) {		dest[0] = size;		(*packet_size_length) = 1;	} else if (size < 65536) {		dest[0] = (((size - 192) / 256) + 192);		dest[1] = ((size - 192) % 256);		(*packet_size_length) = 2;	} else {		rc = -EINVAL;		ecryptfs_printk(KERN_WARNING,				"Unsupported packet size: [%d]\n", size);	}	return rc;}static intwrite_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,		    char **packet, size_t *packet_len){	size_t i = 0;	size_t data_len;	size_t packet_size_len;	char *message;	int rc;	/*	 *              ***** TAG 64 Packet Format *****	 *    | Content Type                       | 1 byte       |	 *    | Key Identifier Size                | 1 or 2 bytes |	 *    | Key Identifier                     | arbitrary    |	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |	 *    | Encrypted File Encryption Key      | arbitrary    |	 */	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX		    + session_key->encrypted_key_size);	*packet = kmalloc(data_len, GFP_KERNEL);	message = *packet;	if (!message) {		ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");		rc = -ENOMEM;		goto out;	}	message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;	rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,				 &packet_size_len);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "				"header; cannot generate packet length\n");		goto out;	}	i += packet_size_len;	memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);	i += ECRYPTFS_SIG_SIZE_HEX;	rc = write_packet_length(&message[i], session_key->encrypted_key_size,				 &packet_size_len);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "				"header; cannot generate packet length\n");		goto out;	}	i += packet_size_len;	memcpy(&message[i], session_key->encrypted_key,	       session_key->encrypted_key_size);	i += session_key->encrypted_key_size;	*packet_len = i;out:	return rc;}static intparse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code,		    struct ecryptfs_message *msg){	size_t i = 0;	char *data;	size_t data_len;	size_t m_size;	size_t message_len;	u16 checksum = 0;	u16 expected_checksum = 0;	int rc;	/*	 *              ***** TAG 65 Packet Format *****	 *         | Content Type             | 1 byte       |	 *         | Status Indicator         | 1 byte       |	 *         | File Encryption Key Size | 1 or 2 bytes |	 *         | File Encryption Key      | arbitrary    |	 */	message_len = msg->data_len;	data = msg->data;	if (message_len < 4) {		rc = -EIO;		goto out;	}	if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) {		ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n");		rc = -EIO;		goto out;	}	if (data[i++]) {		ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value "				"[%d]\n", data[i-1]);		rc = -EIO;		goto out;	}	rc = parse_packet_length(&data[i], &m_size, &data_len);	if (rc) {		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "				"rc = [%d]\n", rc);		goto out;	}	i += data_len;	if (message_len < (i + m_size)) {		ecryptfs_printk(KERN_ERR, "The received netlink message is "				"shorter than expected\n");		rc = -EIO;		goto out;	}	if (m_size < 3) {		ecryptfs_printk(KERN_ERR,				"The decrypted key is not long enough to "				"include a cipher code and checksum\n");		rc = -EIO;		goto out;	}	*cipher_code = data[i++];	/* The decrypted key includes 1 byte cipher code and 2 byte checksum */	session_key->decrypted_key_size = m_size - 3;	if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) {		ecryptfs_printk(KERN_ERR, "key_size [%d] larger than "				"the maximum key size [%d]\n",				session_key->decrypted_key_size,				ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);		rc = -EIO;		goto out;	}	memcpy(session_key->decrypted_key, &data[i],	       session_key->decrypted_key_size);	i += session_key->decrypted_key_size;	expected_checksum += (unsigned char)(data[i++]) << 8;	expected_checksum += (unsigned char)(data[i++]);	for (i = 0; i < session_key->decrypted_key_size; i++)		checksum += session_key->decrypted_key[i];	if (expected_checksum != checksum) {		ecryptfs_printk(KERN_ERR, "Invalid checksum for file "				"encryption  key; expected [%x]; calculated "				"[%x]\n", expected_checksum, checksum);		rc = -EIO;	}out:	return rc;}static intwrite_tag_66_packet(char *signature, size_t cipher_code,		    struct ecryptfs_crypt_stat *crypt_stat, char **packet,		    size_t *packet_len){	size_t i = 0;	size_t j;	size_t data_len;	size_t checksum = 0;	size_t packet_size_len;	char *message;	int rc;	/*	 *              ***** TAG 66 Packet Format *****	 *         | Content Type             | 1 byte       |	 *         | Key Identifier Size      | 1 or 2 bytes |	 *         | Key Identifier           | arbitrary    |	 *         | File Encryption Key Size | 1 or 2 bytes |	 *         | File Encryption Key      | arbitrary    |	 */	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size);	*packet = kmalloc(data_len, GFP_KERNEL);	message = *packet;	if (!message) {		ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");		rc = -ENOMEM;		goto out;	}	message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;	rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,				 &packet_size_len);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "				"header; cannot generate packet length\n");		goto out;	}	i += packet_size_len;	memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);	i += ECRYPTFS_SIG_SIZE_HEX;	/* The encrypted key includes 1 byte cipher code and 2 byte checksum */	rc = write_packet_length(&message[i], crypt_stat->key_size + 3,				 &packet_size_len);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "				"header; cannot generate packet length\n");		goto out;	}	i += packet_size_len;	message[i++] = cipher_code;	memcpy(&message[i], crypt_stat->key, crypt_stat->key_size);	i += crypt_stat->key_size;	for (j = 0; j < crypt_stat->key_size; j++)		checksum += crypt_stat->key[j];	message[i++] = (checksum / 256) % 256;	message[i++] = (checksum % 256);	*packet_len = i;out:	return rc;}static intparse_tag_67_packet(struct ecryptfs_key_record *key_rec,		    struct ecryptfs_message *msg){	size_t i = 0;	char *data;	size_t data_len;	size_t message_len;	int rc;	/*	 *              ***** TAG 65 Packet Format *****	 *    | Content Type                       | 1 byte       |	 *    | Status Indicator                   | 1 byte       |	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |	 *    | Encrypted File Encryption Key      | arbitrary    |	 */	message_len = msg->data_len;	data = msg->data;	/* verify that everything through the encrypted FEK size is present */	if (message_len < 4) {		rc = -EIO;		goto out;	}	if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {		ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_67\n");		rc = -EIO;		goto out;	}	if (data[i++]) {		ecryptfs_printk(KERN_ERR, "Status indicator has non zero value"				" [%d]\n", data[i-1]);		rc = -EIO;		goto out;	}	rc = parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len);	if (rc) {		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "				"rc = [%d]\n", rc);		goto out;	}	i += data_len;	if (message_len < (i + key_rec->enc_key_size)) {		ecryptfs_printk(KERN_ERR, "message_len [%d]; max len is [%d]\n",				message_len, (i + key_rec->enc_key_size));		rc = -EIO;		goto out;	}	if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {		ecryptfs_printk(KERN_ERR, "Encrypted key_size [%d] larger than "				"the maximum key size [%d]\n",				key_rec->enc_key_size,				ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);		rc = -EIO;		goto out;	}	memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);out:	return rc;}static intecryptfs_get_auth_tok_sig(char **sig, struct ecryptfs_auth_tok *auth_tok){	int rc = 0;	(*sig) = NULL;	switch (auth_tok->token_type) {	case ECRYPTFS_PASSWORD:		(*sig) = auth_tok->token.password.signature;		break;	case ECRYPTFS_PRIVATE_KEY:		(*sig) = auth_tok->token.private_key.signature;		break;	default:		printk(KERN_ERR "Cannot get sig for auth_tok of type [%d]\n",		       auth_tok->token_type);		rc = -EINVAL;	}	return rc;}/** * decrypt_pki_encrypted_session_key - Decrypt the session key with the given auth_tok. * @auth_tok: The key authentication token used to decrypt the session key * @crypt_stat: The cryptographic context * * Returns zero on success; non-zero error otherwise. */static intdecrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,				  struct ecryptfs_crypt_stat *crypt_stat){	u16 cipher_code = 0;	struct ecryptfs_msg_ctx *msg_ctx;	struct ecryptfs_message *msg = NULL;	char *auth_tok_sig;	char *netlink_message;	size_t netlink_message_length;	int rc;	rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);	if (rc) {		printk(KERN_ERR "Unrecognized auth tok type: [%d]\n",		       auth_tok->token_type);		goto out;	}	rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),				 &netlink_message, &netlink_message_length);	if (rc) {		ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet");		goto out;	}	rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,				   netlink_message_length, &msg_ctx);	if (rc) {		ecryptfs_printk(KERN_ERR, "Error sending netlink message\n");		goto out;	}	rc = ecryptfs_wait_for_response(msg_ctx, &msg);	if (rc) {		ecryptfs_printk(KERN_ERR, "Failed to receive tag 65 packet "				"from the user space daemon\n");		rc = -EIO;		goto out;	}	rc = parse_tag_65_packet(&(auth_tok->session_key),				 &cipher_code, msg);	if (rc) {		printk(KERN_ERR "Failed to parse tag 65 packet; rc = [%d]\n",		       rc);		goto out;	}	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;

⌨️ 快捷键说明

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