static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc,
			       struct scatterlist *sg, int blen, int sec)
{
	unsigned long start, end;
	int bcount;
	int ret;

	for (start = jiffies, end = start + sec * HZ, bcount = 0;
	     time_before(jiffies, end); bcount++) {
		if (enc)
			ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);
		else
			ret = crypto_blkcipher_decrypt(desc, sg, sg, blen);

		if (ret)
			return ret;
	}

	printk("%d operations in %d seconds (%ld bytes)\n",
	       bcount, sec, (long)bcount * blen);
	return 0;
}
Пример #2
0
/*
 * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
 * Well, not what's written there, but rather what they meant.
 */
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{
	struct scatterlist sg_in[1], sg_out[1];
	struct blkcipher_desc desc = { .tfm = state->arc4 };

	get_new_key_from_sha(state);
	if (!initial_key) {
		crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
					state->keylen);
		sg_init_table(sg_in, 1);
		sg_init_table(sg_out, 1);
		setup_sg(sg_in, state->sha1_digest, state->keylen);
		setup_sg(sg_out, state->session_key, state->keylen);
		if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
					     state->keylen) != 0) {
    		    printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
		}
	} else {
		memcpy(state->session_key, state->sha1_digest, state->keylen);
	}
	if (state->keylen == 8) {
		/* See RFC 3078 */
		state->session_key[0] = 0xd1;
		state->session_key[1] = 0x26;
		state->session_key[2] = 0x9e;
	}
	crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen);
}

/*
 * Allocate space for a (de)compressor.
 */
static void *mppe_alloc(unsigned char *options, int optlen)
{
	struct ppp_mppe_state *state;
	unsigned int digestsize;

	if (optlen != CILEN_MPPE + sizeof(state->master_key)
	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
		goto out;

	state = kzalloc(sizeof(*state), GFP_KERNEL);
	if (state == NULL)
		goto out;


	state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(state->arc4)) {
		state->arc4 = NULL;
		goto out_free;
	}

	state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(state->sha1)) {
		state->sha1 = NULL;
		goto out_free;
	}

	digestsize = crypto_hash_digestsize(state->sha1);
	if (digestsize < MPPE_MAX_KEY_LEN)
		goto out_free;

	state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
	if (!state->sha1_digest)
		goto out_free;

	/* Save keys. */
	memcpy(state->master_key, &options[CILEN_MPPE],
	       sizeof(state->master_key));
	memcpy(state->session_key, state->master_key,
	       sizeof(state->master_key));

	/*
	 * We defer initial key generation until mppe_init(), as mppe_alloc()
	 * is called frequently during negotiation.
	 */

	return (void *)state;

	out_free:
	    if (state->sha1_digest)
		kfree(state->sha1_digest);
	    if (state->sha1)
		crypto_free_hash(state->sha1);
	    if (state->arc4)
		crypto_free_blkcipher(state->arc4);
	    kfree(state);
	out:
	return NULL;
}

/*
 * Deallocate space for a (de)compressor.
 */
static void mppe_free(void *arg)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
	if (state) {
	    if (state->sha1_digest)
		kfree(state->sha1_digest);
	    if (state->sha1)
		crypto_free_hash(state->sha1);
	    if (state->arc4)
		crypto_free_blkcipher(state->arc4);
	    kfree(state);
	}
}

/*
 * Initialize (de)compressor state.
 */
static int
mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,
	  const char *debugstr)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
	unsigned char mppe_opts;

	if (optlen != CILEN_MPPE
	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
		return 0;

	MPPE_CI_TO_OPTS(&options[2], mppe_opts);
	if (mppe_opts & MPPE_OPT_128)
		state->keylen = 16;
	else if (mppe_opts & MPPE_OPT_40)
		state->keylen = 8;
	else {
		printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr,
		       unit);
		return 0;
	}
	if (mppe_opts & MPPE_OPT_STATEFUL)
		state->stateful = 1;

	/* Generate the initial session key. */
	mppe_rekey(state, 1);

	if (debug) {
		int i;
		char mkey[sizeof(state->master_key) * 2 + 1];
		char skey[sizeof(state->session_key) * 2 + 1];

		printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n",
		       debugstr, unit, (state->keylen == 16) ? 128 : 40,
		       (state->stateful) ? "stateful" : "stateless");

		for (i = 0; i < sizeof(state->master_key); i++)
			sprintf(mkey + i * 2, "%02x", state->master_key[i]);
		for (i = 0; i < sizeof(state->session_key); i++)
			sprintf(skey + i * 2, "%02x", state->session_key[i]);
		printk(KERN_DEBUG
		       "%s[%d]: keys: master: %s initial session: %s\n",
		       debugstr, unit, mkey, skey);
	}

	/*
	 * Initialize the coherency count.  The initial value is not specified
	 * in RFC 3078, but we can make a reasonable assumption that it will
	 * start at 0.  Setting it to the max here makes the comp/decomp code
	 * do the right thing (determined through experiment).
	 */
	state->ccount = MPPE_CCOUNT_SPACE - 1;

	/*
	 * Note that even though we have initialized the key table, we don't
	 * set the FLUSHED bit.  This is contrary to RFC 3078, sec. 3.1.
	 */
	state->bits = MPPE_BIT_ENCRYPTED;

	state->unit = unit;
	state->debug = debug;

	return 1;
}

static int
mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,
	       int hdrlen, int debug)
{
	/* ARGSUSED */
	return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");
}

/*
 * We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
 * tell the compressor to rekey.  Note that we MUST NOT rekey for
 * every CCP Reset-Request; we only rekey on the next xmit packet.
 * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
 * So, rekeying for every CCP Reset-Request is broken as the peer will not
 * know how many times we've rekeyed.  (If we rekey and THEN get another
 * CCP Reset-Request, we must rekey again.)
 */
static void mppe_comp_reset(void *arg)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;

	state->bits |= MPPE_BIT_FLUSHED;
}

/*
 * Compress (encrypt) a packet.
 * It's strange to call this a compressor, since the output is always
 * MPPE_OVHD + 2 bytes larger than the input.
 */
static int
mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
	      int isize, int osize)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
	struct blkcipher_desc desc = { .tfm = state->arc4 };
	int proto;
	struct scatterlist sg_in[1], sg_out[1];

	/*
	 * Check that the protocol is in the range we handle.
	 */
	proto = PPP_PROTOCOL(ibuf);
	if (proto < 0x0021 || proto > 0x00fa)
		return 0;

	/* Make sure we have enough room to generate an encrypted packet. */
	if (osize < isize + MPPE_OVHD + 2) {
		/* Drop the packet if we should encrypt it, but can't. */
		printk(KERN_DEBUG "mppe_compress[%d]: osize too small! "
		       "(have: %d need: %d)\n", state->unit,
		       osize, osize + MPPE_OVHD + 2);
		return -1;
	}

	osize = isize + MPPE_OVHD + 2;

	/*
	 * Copy over the PPP header and set control bits.
	 */
	obuf[0] = PPP_ADDRESS(ibuf);
	obuf[1] = PPP_CONTROL(ibuf);
	obuf[2] = PPP_COMP >> 8;	/* isize + MPPE_OVHD + 1 */
	obuf[3] = PPP_COMP;	/* isize + MPPE_OVHD + 2 */
	obuf += PPP_HDRLEN;

	state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
	if (state->debug >= 7)
		printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
		       state->ccount);
	obuf[0] = state->ccount >> 8;
	obuf[1] = state->ccount & 0xff;

	if (!state->stateful ||	/* stateless mode     */
	    ((state->ccount & 0xff) == 0xff) ||	/* "flag" packet      */
	    (state->bits & MPPE_BIT_FLUSHED)) {	/* CCP Reset-Request  */
		/* We must rekey */
		if (state->debug && state->stateful)
			printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n",
			       state->unit);
		mppe_rekey(state, 0);
		state->bits |= MPPE_BIT_FLUSHED;
	}
	obuf[0] |= state->bits;
	state->bits &= ~MPPE_BIT_FLUSHED;	/* reset for next xmit */

	obuf += MPPE_OVHD;
	ibuf += 2;		/* skip to proto field */
	isize -= 2;

	/* Encrypt packet */
	sg_init_table(sg_in, 1);
	sg_init_table(sg_out, 1);
	setup_sg(sg_in, ibuf, isize);
	setup_sg(sg_out, obuf, osize);
	if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) {
		printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
		return -1;
	}

	state->stats.unc_bytes += isize;
	state->stats.unc_packets++;
	state->stats.comp_bytes += osize;
	state->stats.comp_packets++;

	return osize;
}

/*
 * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going
 * to look bad ... and the longer the link is up the worse it will get.
 */
static void mppe_comp_stats(void *arg, struct compstat *stats)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;

	*stats = state->stats;
}

static int
mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit,
		 int hdrlen, int mru, int debug)
{
	/* ARGSUSED */
	return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init");
}

/*
 * We received a CCP Reset-Ack.  Just ignore it.
 */
static void mppe_decomp_reset(void *arg)
{
	/* ARGSUSED */
	return;
}

/*
 * Decompress (decrypt) an MPPE packet.
 */
static int
mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
		int osize)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
	struct blkcipher_desc desc = { .tfm = state->arc4 };
	unsigned ccount;
	int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
	int sanity = 0;
	struct scatterlist sg_in[1], sg_out[1];

	if (isize <= PPP_HDRLEN + MPPE_OVHD) {
		if (state->debug)
			printk(KERN_DEBUG
			       "mppe_decompress[%d]: short pkt (%d)\n",
			       state->unit, isize);
		return DECOMP_ERROR;
	}

	/*
	 * Make sure we have enough room to decrypt the packet.
	 * Note that for our test we only subtract 1 byte whereas in
	 * mppe_compress() we added 2 bytes (+MPPE_OVHD);
	 * this is to account for possible PFC.
	 */
	if (osize < isize - MPPE_OVHD - 1) {
		printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! "
		       "(have: %d need: %d)\n", state->unit,
		       osize, isize - MPPE_OVHD - 1);
		return DECOMP_ERROR;
	}
	osize = isize - MPPE_OVHD - 2;	/* assume no PFC */

	ccount = MPPE_CCOUNT(ibuf);
	if (state->debug >= 7)
		printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n",
		       state->unit, ccount);

	/* sanity checks -- terminate with extreme prejudice */
	if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
		printk(KERN_DEBUG
		       "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
		       state->unit);
		state->sanity_errors += 100;
		sanity = 1;
	}
	if (!state->stateful && !flushed) {
		printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
		       "stateless mode!\n", state->unit);
		state->sanity_errors += 100;
		sanity = 1;
	}
	if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
		printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
		       "flag packet!\n", state->unit);
		state->sanity_errors += 100;
		sanity = 1;
	}

	if (sanity) {
		if (state->sanity_errors < SANITY_MAX)
			return DECOMP_ERROR;
		else
			/*
			 * Take LCP down if the peer is sending too many bogons.
			 * We don't want to do this for a single or just a few
			 * instances since it could just be due to packet corruption.
			 */
			return DECOMP_FATALERROR;
	}

	/*
	 * Check the coherency count.
	 */

	if (!state->stateful) {
		/* RFC 3078, sec 8.1.  Rekey for every packet. */
		while (state->ccount != ccount) {
			mppe_rekey(state, 0);
			state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
		}
	} else {
		/* RFC 3078, sec 8.2. */
		if (!state->discard) {
			/* normal state */
			state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
			if (ccount != state->ccount) {
				/*
				 * (ccount > state->ccount)
				 * Packet loss detected, enter the discard state.
				 * Signal the peer to rekey (by sending a CCP Reset-Request).
				 */
				state->discard = 1;
				return DECOMP_ERROR;
			}
		} else {
			/* discard state */
			if (!flushed) {
				/* ccp.c will be silent (no additional CCP Reset-Requests). */
				return DECOMP_ERROR;
			} else {
				/* Rekey for every missed "flag" packet. */
				while ((ccount & ~0xff) !=
				       (state->ccount & ~0xff)) {
					mppe_rekey(state, 0);
					state->ccount =
					    (state->ccount +
					     256) % MPPE_CCOUNT_SPACE;
				}

				/* reset */
				state->discard = 0;
				state->ccount = ccount;
				/*
				 * Another problem with RFC 3078 here.  It implies that the
				 * peer need not send a Reset-Ack packet.  But RFC 1962
				 * requires it.  Hopefully, M$ does send a Reset-Ack; even
				 * though it isn't required for MPPE synchronization, it is
				 * required to reset CCP state.
				 */
			}
		}
		if (flushed)
			mppe_rekey(state, 0);
	}

	/*
	 * Fill in the first part of the PPP header.  The protocol field
	 * comes from the decrypted data.
	 */
	obuf[0] = PPP_ADDRESS(ibuf);	/* +1 */
	obuf[1] = PPP_CONTROL(ibuf);	/* +1 */
	obuf += 2;
	ibuf += PPP_HDRLEN + MPPE_OVHD;
	isize -= PPP_HDRLEN + MPPE_OVHD;	/* -6 */
	/* net osize: isize-4 */

	/*
	 * Decrypt the first byte in order to check if it is
	 * a compressed or uncompressed protocol field.
	 */
	sg_init_table(sg_in, 1);
	sg_init_table(sg_out, 1);
	setup_sg(sg_in, ibuf, 1);
	setup_sg(sg_out, obuf, 1);
	if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) {
		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
		return DECOMP_ERROR;
	}

	/*
	 * Do PFC decompression.
	 * This would be nicer if we were given the actual sk_buff
	 * instead of a char *.
	 */
	if ((obuf[0] & 0x01) != 0) {
		obuf[1] = obuf[0];
		obuf[0] = 0;
		obuf++;
		osize++;
	}

	/* And finally, decrypt the rest of the packet. */
	setup_sg(sg_in, ibuf + 1, isize - 1);
	setup_sg(sg_out, obuf + 1, osize - 1);
	if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) {
		printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
		return DECOMP_ERROR;
	}

	state->stats.unc_bytes += osize;
	state->stats.unc_packets++;
	state->stats.comp_bytes += isize;
	state->stats.comp_packets++;

	/* good packet credit */
	state->sanity_errors >>= 1;

	return osize;
}

/*
 * Incompressible data has arrived (this should never happen!).
 * We should probably drop the link if the protocol is in the range
 * of what should be encrypted.  At the least, we should drop this
 * packet.  (How to do this?)
 */
static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt)
{
	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;

	if (state->debug &&
	    (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa))
		printk(KERN_DEBUG
		       "mppe_incomp[%d]: incompressible (unencrypted) data! "
		       "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf));

	state->stats.inc_bytes += icnt;
	state->stats.inc_packets++;
	state->stats.unc_bytes += icnt;
	state->stats.unc_packets++;
}

/*************************************************************
 * Module interface table
 *************************************************************/

/*
 * Procedures exported to if_ppp.c.
 */
static struct compressor ppp_mppe = {
	.compress_proto = CI_MPPE,
	.comp_alloc     = mppe_alloc,
	.comp_free      = mppe_free,
	.comp_init      = mppe_comp_init,
	.comp_reset     = mppe_comp_reset,
	.compress       = mppe_compress,
	.comp_stat      = mppe_comp_stats,
	.decomp_alloc   = mppe_alloc,
	.decomp_free    = mppe_free,
	.decomp_init    = mppe_decomp_init,
	.decomp_reset   = mppe_decomp_reset,
	.decompress     = mppe_decompress,
	.incomp         = mppe_incomp,
	.decomp_stat    = mppe_comp_stats,
	.owner          = THIS_MODULE,
	.comp_extra     = MPPE_PAD,
};

/*
 * ppp_mppe_init()
 *
 * Prior to allowing load, try to load the arc4 and sha1 crypto
 * libraries.  The actual use will be allocated later, but
 * this way the module will fail to insmod if they aren't available.
 */

static int __init ppp_mppe_init(void)
{
	int answer;
	if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
	      crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC)))
		return -ENODEV;

	sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
	if (!sha_pad)
		return -ENOMEM;
	sha_pad_init(sha_pad);

	answer = ppp_register_compressor(&ppp_mppe);

	if (answer == 0)
		printk(KERN_INFO "PPP MPPE Compression module registered\n");
	else
		kfree(sha_pad);

	return answer;
}

static void __exit ppp_mppe_cleanup(void)
{
	ppp_unregister_compressor(&ppp_mppe);
	kfree(sha_pad);
}

module_init(ppp_mppe_init);
module_exit(ppp_mppe_cleanup);
Пример #3
0
/* Main encrypt function
 * referenced from ceph_aes_encrypt() function
 * returns length encrypted
 */
int encrypt_data(const void *key, int length_key, void *to_buffer, const void *from_buffer, size_t *to_length, 
    size_t from_length, char *algo_name){
    
    struct scatterlist scatter_list_src[2];
    struct scatterlist scatter_list_dest[1];
    struct crypto_blkcipher *tfm = crypto_alloc_blkcipher(algo_name, 0, CRYPTO_ALG_ASYNC);
    struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
    size_t null_padding = (0x10 - (from_length & 0x0f));
    int return_value = 0;
    char padding_array[48];
    
    printk("algo_name: %s\n", algo_name);
    /* check to see if the cipher struct is set properly */
    if(IS_ERR(tfm))
    {
        printk("Error in setting tfm\n");
        return PTR_ERR(tfm);
    }
    memset(padding_array, null_padding, null_padding);
    
    *to_length = from_length + null_padding;
    
    /* let's set the key for the cipher */
    crypto_blkcipher_setkey((void *)tfm, key, length_key);
	sg_init_table(scatter_list_src, 2);
	sg_set_buf(&scatter_list_src[0], from_buffer, from_length);
	sg_set_buf(&scatter_list_src[1], padding_array, null_padding);
	sg_init_table(scatter_list_dest, 1);
	sg_set_buf(scatter_list_dest, to_buffer,*to_length);
    
    /* let's start encrypting */
    return_value = crypto_blkcipher_encrypt(&desc, scatter_list_dest, scatter_list_src, from_length + null_padding);
    
    /* free up the blk cipher */
    crypto_free_blkcipher(tfm);
    
    if (return_value < 0)
    {
        printk(KERN_CRIT "crypto_blcipher encryption failed with errno %d.\n",return_value);
    }
    
    return return_value;
    
}

int decrypt_data(const void *key, int length_key, void *to_buffer, const void *from_buffer, 
    size_t *to_length, size_t from_length, char *algo_name)
{

	int return_value =0;
	int end_element;
	char padding_array[48];
	struct scatterlist scatter_list_src[1];
    struct scatterlist scatter_list_dest[2];
	struct crypto_blkcipher *tfm = crypto_alloc_blkcipher(algo_name, 0, CRYPTO_ALG_ASYNC);
	struct blkcipher_desc desc = { .tfm = tfm };
    
    printk("algo_name: %s\n", algo_name);
    
	/* check to see if the cipher struct is set properly */
    if(IS_ERR(tfm))
    {
        return PTR_ERR(tfm);
    }
    
	/* Setting the key for Block cipher */
	crypto_blkcipher_setkey((void *)tfm, key, length_key);
	sg_init_table(scatter_list_src, 1);
	sg_init_table(scatter_list_dest, 2);
	sg_set_buf(scatter_list_src, from_buffer, from_length);
	sg_set_buf(&scatter_list_dest[0], to_buffer, *to_length);
	sg_set_buf(&scatter_list_dest[1], padding_array, sizeof(padding_array));
    
	/* let's decrypt using crypto_blkcipher */
	return_value = crypto_blkcipher_decrypt(&desc, scatter_list_dest, scatter_list_src, from_length);
    /* Free up the blk cipher */
	crypto_free_blkcipher(tfm);
    
	if (return_value < 0) {
        printk(KERN_CRIT "crypto_blcipher decryption failed 1.\n");
		return return_value;
	}
    
	if (from_length <= *to_length)
		end_element = ((char *)to_buffer)[from_length - 1];
	else
		end_element = padding_array[from_length - *to_length - 1];
    
	if (end_element <= 16 && from_length >= end_element) {
        
		*to_length = from_length - end_element;
	}
	else 
    {
        printk(KERN_CRIT "crypto_blcipher decryption failed 2.\n");
        return -EPERM;  //bad padding
    }
    return return_value;
}
Пример #4
0
static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
{
	struct ipv6hdr *iph;
	struct ipv6_esp_hdr *esph;
	struct esp_data *esp = x->data;
	struct crypto_blkcipher *tfm = esp->conf.tfm;
	struct blkcipher_desc desc = { .tfm = tfm };
	struct sk_buff *trailer;
	int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
	int alen = esp->auth.icv_trunc_len;
	int elen = skb->len - sizeof(struct ipv6_esp_hdr) - esp->conf.ivlen - alen;

	int hdr_len = skb->h.raw - skb->nh.raw;
	int nfrags;
	int ret = 0;

	if (!pskb_may_pull(skb, sizeof(struct ipv6_esp_hdr))) {
		ret = -EINVAL;
		goto out;
	}

	if (elen <= 0 || (elen & (blksize-1))) {
		ret = -EINVAL;
		goto out;
	}

	/* If integrity check is required, do this. */
        if (esp->auth.icv_full_len) {
		u8 sum[alen];

		ret = esp_mac_digest(esp, skb, 0, skb->len - alen);
		if (ret)
			goto out;

		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
			BUG();

		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
			x->stats.integrity_failed++;
			ret = -EINVAL;
			goto out;
		}
	}

	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
		ret = -EINVAL;
		goto out;
	}

	skb->ip_summed = CHECKSUM_NONE;

	esph = (struct ipv6_esp_hdr*)skb->data;
	iph = skb->nh.ipv6h;

	/* Get ivec. This can be wrong, check against another impls. */
	if (esp->conf.ivlen)
		crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);

        {
		u8 nexthdr[2];
		struct scatterlist *sg = &esp->sgbuf[0];
		u8 padlen;

		if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
			if (!sg) {
				ret = -ENOMEM;
				goto out;
			}
		}
		skb_to_sgvec(skb, sg, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen, elen);
		ret = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
		if (unlikely(sg != &esp->sgbuf[0]))
			kfree(sg);
		if (unlikely(ret))
			goto out;

		if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
			BUG();

		padlen = nexthdr[0];
		if (padlen+2 >= elen) {
			LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage padlen=%d, elen=%d\n", padlen+2, elen);
			ret = -EINVAL;
			goto out;
		}
		/* ... check padding bits here. Silly. :-) */ 

		pskb_trim(skb, skb->len - alen - padlen - 2);
		ret = nexthdr[1];
	}

	skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - hdr_len;

out:
	return ret;
}
Пример #5
0
static int aml_keybox_aes_encrypt(const void *key, int key_len,
                                  const u8 *aes_iv, void *dst, size_t *dst_len,
                                  const void *src, size_t src_len)
{
    struct scatterlist sg_in[1], sg_out[1];
    struct crypto_blkcipher *tfm = aml_keybox_crypto_alloc_cipher();
    struct blkcipher_desc desc =
        { .tfm = tfm, .flags = 0 };
	int ret;
	void *iv;
	int ivsize;
	if(src_len & 0x0f){
		printk("%s:%d,src_len %d is not 16byte align",__func__,__LINE__,src_len);
		return -1;
	}

	if (IS_ERR(tfm)){
		printk("%s:%d,crypto_alloc fail\n",__func__,__LINE__);
		return PTR_ERR(tfm);
	}

	*dst_len = src_len ;

	crypto_blkcipher_setkey((void *) tfm, key, key_len);
	sg_init_table(sg_in, 1);
	sg_set_buf(&sg_in[0], src, src_len);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_out, dst, *dst_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	//printk("key_len:%d,ivsize:%d\n",key_len,ivsize);

	memcpy(iv, aes_iv, ivsize);

    ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,src_len);
    crypto_free_blkcipher(tfm);
    if (ret < 0){
        printk("%s:%d,ceph_aes_crypt failed %d\n", __func__,__LINE__,ret);
        return ret;
	}
    return 0;
}
static int aml_keybox_aes_decrypt(const void *key, int key_len,
                                      const u8 *aes_iv, void *dst,
                                      size_t *dst_len, const void *src,
                                      size_t src_len)
{
    struct scatterlist sg_in[1], sg_out[1];
    struct crypto_blkcipher *tfm = aml_keybox_crypto_alloc_cipher();
    struct blkcipher_desc desc =
        { .tfm = tfm };
    void *iv;
    int ivsize;
    int ret;
//    int last_byte;
	if(src_len &0x0f){
		printk("%s:%d,src_len %d is not 16byte align",__func__,__LINE__,src_len);
		return -1;
	}

	if (IS_ERR(tfm)){
		printk("%s:%d,crypto_alloc fail\n",__func__,__LINE__);
		return PTR_ERR(tfm);
	}

	crypto_blkcipher_setkey((void *) tfm, key, key_len);
	sg_init_table(sg_in, 1);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_in, src, src_len);
	sg_set_buf(&sg_out[0], dst, *dst_len);

	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	//printk("key_len:%d,ivsize:%d\n",key_len,ivsize);

	memcpy(iv, aes_iv, ivsize);

	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
	crypto_free_blkcipher(tfm);
	if (ret < 0){
		printk("%s:%d,ceph_aes_decrypt failed %d\n", __func__,__LINE__,ret);
		return ret;
	}
	*dst_len = src_len;
    return 0;
}

int aes_crypto_encrypt(void *dst,size_t *dst_len,const void *src,size_t src_len)
{
	int ret;
	unsigned char iv_aes[16];
	unsigned char key_aes[32];
	memcpy(iv_aes,&default_AESkey[0],16);
	memcpy(key_aes,&default_AESkey[16],32);

	ret = aml_keybox_aes_encrypt(key_aes,sizeof(key_aes),iv_aes,dst,dst_len,src,src_len);
	return ret;
}
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
 * the frame: IV (4 bytes), encrypted payload (including SNAP header),
 * ICV (4 bytes). len includes both IV and ICV.
 *
 * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
 * failure. If frame is OK, IV and ICV will be removed.
 */
static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
	struct prism2_wep_data *wep = priv;
	struct blkcipher_desc desc = { .tfm = wep->rx_tfm };
	u32 klen, plen;
	u8 key[WEP_KEY_LEN + 3];
	u8 keyidx, *pos;
	u32 crc;
	u8 icv[4];
	struct scatterlist sg;

	if (skb->len < hdr_len + 8)
		return -1;

	pos = skb->data + hdr_len;
	key[0] = *pos++;
	key[1] = *pos++;
	key[2] = *pos++;
	keyidx = *pos++ >> 6;
	if (keyidx != wep->key_idx)
		return -1;

	klen = 3 + wep->key_len;

	/* Copy rest of the WEP key (the secret part) */
	memcpy(key + 3, wep->key, wep->key_len);

	/* Apply RC4 to data and compute CRC32 over decrypted data */
	plen = skb->len - hdr_len - 8;

	crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
	sg_init_one(&sg, pos, plen + 4);

	if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
		return -7;

	crc = ~crc32_le(~0, pos, plen);
	icv[0] = crc;
	icv[1] = crc >> 8;
	icv[2] = crc >> 16;
	icv[3] = crc >> 24;

	if (memcmp(icv, pos + plen, 4) != 0) {
		/* ICV mismatch - drop frame */
		return -2;
	}

	/* Remove IV and ICV */
	memmove(skb->data + 4, skb->data, hdr_len);
	skb_pull(skb, 4);
	skb_trim(skb, skb->len - 4);
        return 0;
}


static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
{
	struct prism2_wep_data *wep = priv;

	if (len < 0 || len > WEP_KEY_LEN)
		return -1;

	memcpy(wep->key, key, len);
	wep->key_len = len;

	return 0;
}


static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
{
	struct prism2_wep_data *wep = priv;

	if (len < wep->key_len)
		return -1;

	memcpy(key, wep->key, wep->key_len);

	return wep->key_len;
}


static char * prism2_wep_print_stats(char *p, void *priv)
{
	struct prism2_wep_data *wep = priv;
	p += sprintf(p, "key[%d] alg=WEP len=%d\n",
		     wep->key_idx, wep->key_len);
	return p;
}


static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
	.name			= "WEP",
	.init			= prism2_wep_init,
	.deinit			= prism2_wep_deinit,
	.encrypt_mpdu		= prism2_wep_encrypt,
	.decrypt_mpdu		= prism2_wep_decrypt,
	.encrypt_msdu		= NULL,
	.decrypt_msdu		= NULL,
	.set_key		= prism2_wep_set_key,
	.get_key		= prism2_wep_get_key,
	.print_stats		= prism2_wep_print_stats,
	.extra_prefix_len	= 4, /* IV */
	.extra_postfix_len	= 4, /* ICV */
	.owner			= THIS_MODULE,
};


int ieee80211_crypto_wep_init(void)
{
	return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
}


void ieee80211_crypto_wep_exit(void)
{
	ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
}


void ieee80211_wep_null(void)
{
//	printk("============>%s()\n", __func__);
        return;
}
Пример #7
0
static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc,
			      struct scatterlist *dst,
			      struct scatterlist *src, unsigned int nbytes)
{
	int ret;
	struct blkcipher_walk walk;
	struct p8_aes_cbc_ctx *ctx =
		crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
	struct blkcipher_desc fallback_desc = {
		.tfm = ctx->fallback,
		.info = desc->info,
		.flags = desc->flags
	};

	if (in_interrupt()) {
		ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src,
					       nbytes);
	} else {
		preempt_disable();
		pagefault_disable();
		enable_kernel_vsx();

		blkcipher_walk_init(&walk, dst, src, nbytes);
		ret = blkcipher_walk_virt(desc, &walk);
		while ((nbytes = walk.nbytes)) {
			aes_p8_cbc_encrypt(walk.src.virt.addr,
					   walk.dst.virt.addr,
					   nbytes & AES_BLOCK_MASK,
					   &ctx->enc_key, walk.iv, 1);
			nbytes &= AES_BLOCK_SIZE - 1;
			ret = blkcipher_walk_done(desc, &walk, nbytes);
		}

		disable_kernel_vsx();
		pagefault_enable();
		preempt_enable();
	}

	return ret;
}

static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc,
			      struct scatterlist *dst,
			      struct scatterlist *src, unsigned int nbytes)
{
	int ret;
	struct blkcipher_walk walk;
	struct p8_aes_cbc_ctx *ctx =
		crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm));
	struct blkcipher_desc fallback_desc = {
		.tfm = ctx->fallback,
		.info = desc->info,
		.flags = desc->flags
	};

	if (in_interrupt()) {
		ret = crypto_blkcipher_decrypt(&fallback_desc, dst, src,
					       nbytes);
	} else {
		preempt_disable();
		pagefault_disable();
		enable_kernel_vsx();

		blkcipher_walk_init(&walk, dst, src, nbytes);
		ret = blkcipher_walk_virt(desc, &walk);
		while ((nbytes = walk.nbytes)) {
			aes_p8_cbc_encrypt(walk.src.virt.addr,
					   walk.dst.virt.addr,
					   nbytes & AES_BLOCK_MASK,
					   &ctx->dec_key, walk.iv, 0);
			nbytes &= AES_BLOCK_SIZE - 1;
			ret = blkcipher_walk_done(desc, &walk, nbytes);
		}

		disable_kernel_vsx();
		pagefault_enable();
		preempt_enable();
	}

	return ret;
}


struct crypto_alg p8_aes_cbc_alg = {
	.cra_name = "cbc(aes)",
	.cra_driver_name = "p8_aes_cbc",
	.cra_module = THIS_MODULE,
	.cra_priority = 1000,
	.cra_type = &crypto_blkcipher_type,
	.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_NEED_FALLBACK,
	.cra_alignmask = 0,
	.cra_blocksize = AES_BLOCK_SIZE,
	.cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
	.cra_init = p8_aes_cbc_init,
	.cra_exit = p8_aes_cbc_exit,
	.cra_blkcipher = {
			  .ivsize = AES_BLOCK_SIZE,
			  .min_keysize = AES_MIN_KEY_SIZE,
			  .max_keysize = AES_MAX_KEY_SIZE,
			  .setkey = p8_aes_cbc_setkey,
			  .encrypt = p8_aes_cbc_encrypt,
			  .decrypt = p8_aes_cbc_decrypt,
	},
};
Пример #8
0
static int ceph_aes_encrypt(const void *key, int key_len,
			    void *dst, size_t *dst_len,
			    const void *src, size_t src_len)
{
	struct scatterlist sg_in[2], sg_out[1];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
	int ret;
	void *iv;
	int ivsize;
	size_t zero_padding = (0x10 - (src_len & 0x0f));
	char pad[16];

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	memset(pad, zero_padding, zero_padding);

	*dst_len = src_len + zero_padding;

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 2);
	sg_set_buf(&sg_in[0], src, src_len);
	sg_set_buf(&sg_in[1], pad, zero_padding);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_out, dst, *dst_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);
	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
				     src_len + zero_padding);
	crypto_free_blkcipher(tfm);
	if (ret < 0)
		pr_err("ceph_aes_crypt failed %d\n", ret);
	return 0;
}

static int ceph_aes_encrypt2(const void *key, int key_len, void *dst,
			     size_t *dst_len,
			     const void *src1, size_t src1_len,
			     const void *src2, size_t src2_len)
{
	struct scatterlist sg_in[3], sg_out[1];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
	int ret;
	void *iv;
	int ivsize;
	size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
	char pad[16];

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	memset(pad, zero_padding, zero_padding);

	*dst_len = src1_len + src2_len + zero_padding;

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 3);
	sg_set_buf(&sg_in[0], src1, src1_len);
	sg_set_buf(&sg_in[1], src2, src2_len);
	sg_set_buf(&sg_in[2], pad, zero_padding);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_out, dst, *dst_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);
	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
				     src1_len + src2_len + zero_padding);
	crypto_free_blkcipher(tfm);
	if (ret < 0)
		pr_err("ceph_aes_crypt2 failed %d\n", ret);
	return 0;
}

static int ceph_aes_decrypt(const void *key, int key_len,
			    void *dst, size_t *dst_len,
			    const void *src, size_t src_len)
{
	struct scatterlist sg_in[1], sg_out[2];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm };
	char pad[16];
	void *iv;
	int ivsize;
	int ret;
	int last_byte;

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 1);
	sg_init_table(sg_out, 2);
	sg_set_buf(sg_in, src, src_len);
	sg_set_buf(&sg_out[0], dst, *dst_len);
	sg_set_buf(&sg_out[1], pad, sizeof(pad));

	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);


	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
	crypto_free_blkcipher(tfm);
	if (ret < 0) {
		pr_err("ceph_aes_decrypt failed %d\n", ret);
		return ret;
	}

	if (src_len <= *dst_len)
		last_byte = ((char *)dst)[src_len - 1];
	else
		last_byte = pad[src_len - *dst_len - 1];
	if (last_byte <= 16 && src_len >= last_byte) {
		*dst_len = src_len - last_byte;
	} else {
		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
		       last_byte, (int)src_len);
		return -EPERM;  
	}
	return 0;
}

static int ceph_aes_decrypt2(const void *key, int key_len,
			     void *dst1, size_t *dst1_len,
			     void *dst2, size_t *dst2_len,
			     const void *src, size_t src_len)
{
	struct scatterlist sg_in[1], sg_out[3];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm };
	char pad[16];
	void *iv;
	int ivsize;
	int ret;
	int last_byte;

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	sg_init_table(sg_in, 1);
	sg_set_buf(sg_in, src, src_len);
	sg_init_table(sg_out, 3);
	sg_set_buf(&sg_out[0], dst1, *dst1_len);
	sg_set_buf(&sg_out[1], dst2, *dst2_len);
	sg_set_buf(&sg_out[2], pad, sizeof(pad));

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);


	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
	crypto_free_blkcipher(tfm);
	if (ret < 0) {
		pr_err("ceph_aes_decrypt failed %d\n", ret);
		return ret;
	}

	if (src_len <= *dst1_len)
		last_byte = ((char *)dst1)[src_len - 1];
	else if (src_len <= *dst1_len + *dst2_len)
		last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
	else
		last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
	if (last_byte <= 16 && src_len >= last_byte) {
		src_len -= last_byte;
	} else {
		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
		       last_byte, (int)src_len);
		return -EPERM;  
	}

	if (src_len < *dst1_len) {
		*dst1_len = src_len;
		*dst2_len = 0;
	} else {
		*dst2_len = src_len - *dst1_len;
	}

	return 0;
}


int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		 const void *src, size_t src_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src_len)
			return -ERANGE;
		memcpy(dst, src, src_len);
		*dst_len = src_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_decrypt(secret->key, secret->len, dst,
					dst_len, src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_decrypt2(struct ceph_crypto_key *secret,
			void *dst1, size_t *dst1_len,
			void *dst2, size_t *dst2_len,
			const void *src, size_t src_len)
{
	size_t t;

	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst1_len + *dst2_len < src_len)
			return -ERANGE;
		t = min(*dst1_len, src_len);
		memcpy(dst1, src, t);
		*dst1_len = t;
		src += t;
		src_len -= t;
		if (src_len) {
			t = min(*dst2_len, src_len);
			memcpy(dst2, src, t);
			*dst2_len = t;
		}
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_decrypt2(secret->key, secret->len,
					 dst1, dst1_len, dst2, dst2_len,
					 src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		 const void *src, size_t src_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src_len)
			return -ERANGE;
		memcpy(dst, src, src_len);
		*dst_len = src_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_encrypt(secret->key, secret->len, dst,
					dst_len, src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		  const void *src1, size_t src1_len,
		  const void *src2, size_t src2_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src1_len + src2_len)
			return -ERANGE;
		memcpy(dst, src1, src1_len);
		memcpy(dst + src1_len, src2, src2_len);
		*dst_len = src1_len + src2_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
					 src1, src1_len, src2, src2_len);

	default:
		return -EINVAL;
	}
}

int ceph_key_instantiate(struct key *key, const void *data, size_t datalen)
{
	struct ceph_crypto_key *ckey;
	int ret;
	void *p;

	ret = -EINVAL;
	if (datalen <= 0 || datalen > 32767 || !data)
		goto err;

	ret = key_payload_reserve(key, datalen);
	if (ret < 0)
		goto err;

	ret = -ENOMEM;
	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
	if (!ckey)
		goto err;

	
	p = (void *)data;
	ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen);
	if (ret < 0)
		goto err_ckey;

	key->payload.data = ckey;
	return 0;

err_ckey:
	kfree(ckey);
err:
	return ret;
}

int ceph_key_match(const struct key *key, const void *description)
{
	return strcmp(key->description, description) == 0;
}

void ceph_key_destroy(struct key *key) {
	struct ceph_crypto_key *ckey = key->payload.data;

	ceph_crypto_key_destroy(ckey);
	kfree(ckey);
}

struct key_type key_type_ceph = {
	.name		= "ceph",
	.instantiate	= ceph_key_instantiate,
	.match		= ceph_key_match,
	.destroy	= ceph_key_destroy,
};

int ceph_crypto_init(void) {
	return register_key_type(&key_type_ceph);
}

void ceph_crypto_shutdown(void) {
	unregister_key_type(&key_type_ceph);
}
/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of
 * the frame: IV (4 bytes), encrypted payload (including SNAP header),
 * ICV (4 bytes). len includes both IV and ICV.
 *
 * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
 * failure. If frame is OK, IV and ICV will be removed.
 */
static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
	struct prism2_wep_data *wep = priv;
        #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
        struct blkcipher_desc desc = {.tfm = wep->rx_tfm};
        #endif
	u32 klen, plen;
	u8 key[WEP_KEY_LEN + 3];
	u8 keyidx, *pos;
#ifndef JOHN_HWSEC
	u32 crc;
	u8 icv[4];	
	struct scatterlist sg;
#endif	
	if (skb->len < hdr_len + 8)
		return -1;

	pos = skb->data + hdr_len;
	key[0] = *pos++;
	key[1] = *pos++;
	key[2] = *pos++;
	keyidx = *pos++ >> 6;
	if (keyidx != wep->key_idx)
		return -1;

	klen = 3 + wep->key_len;

	/* Copy rest of the WEP key (the secret part) */
	memcpy(key + 3, wep->key, wep->key_len);

	/* Apply RC4 to data and compute CRC32 over decrypted data */
	plen = skb->len - hdr_len - 8;
#ifndef JOHN_HWSEC
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21))
	crypto_cipher_setkey(wep->tfm, key, klen);
	sg.page = virt_to_page(pos);
	sg.offset = offset_in_page(pos);
	sg.length = plen + 4;
	crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
#else
	crypto_blkcipher_setkey(wep->rx_tfm, key, klen);
	#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
	sg.page = virt_to_page(pos);
	sg.offset = offset_in_page(pos);
	sg.length = plen + 4;	
	#else
	sg_init_one(&sg, pos, plen + 4);
	#endif	
	if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4))
		return -7;
#endif 

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
	crc = ~crc32_le(~0, pos, plen);
#else
	crc = ~ether_crc_le(plen, pos);
#endif
	icv[0] = crc;
	icv[1] = crc >> 8;
	icv[2] = crc >> 16;
	icv[3] = crc >> 24;

	if (memcmp(icv, pos + plen, 4) != 0) {
		/* ICV mismatch - drop frame */
		return -2;
	}
#endif 	/* JOHN_HWSEC */

	/* Remove IV and ICV */
	memmove(skb->data + 4, skb->data, hdr_len);
	skb_pull(skb, 4);
	skb_trim(skb, skb->len - 4);
        return 0;
}


static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv)
{
	struct prism2_wep_data *wep = priv;

	if (len < 0 || len > WEP_KEY_LEN)
		return -1;

	memcpy(wep->key, key, len);
	wep->key_len = len;

	return 0;
}


static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv)
{
	struct prism2_wep_data *wep = priv;

	if (len < wep->key_len)
		return -1;

	memcpy(key, wep->key, wep->key_len);

	return wep->key_len;
}


static char * prism2_wep_print_stats(char *p, void *priv)
{
	struct prism2_wep_data *wep = priv;
	p += sprintf(p, "key[%d] alg=WEP len=%d\n",
		     wep->key_idx, wep->key_len);
	return p;
}


static struct ieee80211_crypto_ops ieee80211_crypt_wep = {
	.name			= "WEP",
	.init			= prism2_wep_init,
	.deinit			= prism2_wep_deinit,
	.encrypt_mpdu		= prism2_wep_encrypt,
	.decrypt_mpdu		= prism2_wep_decrypt,
	.encrypt_msdu		= NULL,
	.decrypt_msdu		= NULL,
	.set_key		= prism2_wep_set_key,
	.get_key		= prism2_wep_get_key,
	.print_stats		= prism2_wep_print_stats,
	.extra_prefix_len	= 4, /* IV */
	.extra_postfix_len	= 4, /* ICV */
	.owner			= THIS_MODULE,
};


int __init ieee80211_crypto_wep_init(void)
{
	return ieee80211_register_crypto_ops(&ieee80211_crypt_wep);
}


void __exit ieee80211_crypto_wep_exit(void)
{
	ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep);
}


void ieee80211_wep_null(void)
{
//	printk("============>%s()\n", __FUNCTION__);
        return;
}
#if 0
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
EXPORT_SYMBOL(ieee80211_wep_null);
#else
EXPORT_SYMBOL_NOVERS(ieee80211_wep_null);
#endif

module_init(ieee80211_crypto_wep_init);
module_exit(ieee80211_crypto_wep_exit);
Пример #10
0
/*
 * Note: detecting truncated vs. non-truncated authentication data is very
 * expensive, so we only support truncated data, which is the recommended
 * and common case.
 */
static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
{
	struct iphdr *iph;
	struct ip_esp_hdr *esph;
	struct esp_data *esp = x->data;
	struct crypto_blkcipher *tfm = esp->conf.tfm;
	struct blkcipher_desc desc = { .tfm = tfm };
	struct sk_buff *trailer;
	int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
	int alen = esp->auth.icv_trunc_len;
	int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;
	int nfrags;
	int ihl;
	u8 nexthdr[2];
	struct scatterlist *sg;
	int padlen;
	int err;

	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
		goto out;

	if (elen <= 0 || (elen & (blksize-1)))
		goto out;

	/* If integrity check is required, do this. */
	if (esp->auth.icv_full_len) {
		u8 sum[alen];

		err = esp_mac_digest(esp, skb, 0, skb->len - alen);
		if (err)
			goto out;

		if (skb_copy_bits(skb, skb->len - alen, sum, alen))
			BUG();

		if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
			x->stats.integrity_failed++;
			goto out;
		}
	}

	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
		goto out;

	skb->ip_summed = CHECKSUM_NONE;

	esph = (struct ip_esp_hdr*)skb->data;

	/* Get ivec. This can be wrong, check against another impls. */
	if (esp->conf.ivlen)
		crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);

	sg = &esp->sgbuf[0];

	if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
		sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
		if (!sg)
			goto out;
	}
	skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen);
	err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
	if (unlikely(sg != &esp->sgbuf[0]))
		kfree(sg);
	if (unlikely(err))
		return err;

	if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))
		BUG();

	padlen = nexthdr[0];
	if (padlen+2 >= elen)
		goto out;

	/* ... check padding bits here. Silly. :-) */ 

	iph = skb->nh.iph;
	ihl = iph->ihl * 4;

	if (x->encap) {
		struct xfrm_encap_tmpl *encap = x->encap;
		struct udphdr *uh = (void *)(skb->nh.raw + ihl);

		/*
		 * 1) if the NAT-T peer's IP or port changed then
		 *    advertize the change to the keying daemon.
		 *    This is an inbound SA, so just compare
		 *    SRC ports.
		 */
		if (iph->saddr != x->props.saddr.a4 ||
		    uh->source != encap->encap_sport) {
			xfrm_address_t ipaddr;

			ipaddr.a4 = iph->saddr;
			km_new_mapping(x, &ipaddr, uh->source);
				
			/* XXX: perhaps add an extra
			 * policy check here, to see
			 * if we should allow or
			 * reject a packet from a
			 * different source
			 * address/port.
			 */
		}
	
		/*
		 * 2) ignore UDP/TCP checksums in case
		 *    of NAT-T in Transport Mode, or
		 *    perform other post-processing fixes
		 *    as per draft-ietf-ipsec-udp-encaps-06,
		 *    section 3.1.2
		 */
		if (x->props.mode == XFRM_MODE_TRANSPORT ||
		    x->props.mode == XFRM_MODE_BEET)
			skb->ip_summed = CHECKSUM_UNNECESSARY;
	}

	iph->protocol = nexthdr[1];
	pskb_trim(skb, skb->len - alen - padlen - 2);
	skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl;

	return 0;

out:
	return -EINVAL;
}
Пример #11
0
void test_aes(void)
{
	struct crypto_blkcipher *tfm;
	struct blkcipher_desc desc;
	u32 bs;
	int i,j;
	u32 npages;
	
	struct scatterlist *src;
	struct scatterlist *dst;
	char *buf;
	char **ins, **outs;
	
	unsigned int ret;
	
	u8 key[] = {0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0F, 0x10, 0x11, 0x12};
	
	npages = MAX_BLK_SIZE/PAGE_SIZE;
	
	src = kmalloc(npages*sizeof(struct scatterlist), __GFP_ZERO|GFP_KERNEL);
	if (!src) {
		printk("taes ERROR: failed to alloc src\n");		
		return;
	}
	dst = kmalloc(npages*sizeof(struct scatterlist), __GFP_ZERO|GFP_KERNEL);
	if (!dst) {
		printk("taes ERROR: failed to alloc dst\n");
		kfree(src);		
		return;
	}
	ins = kmalloc(npages*sizeof(char*), __GFP_ZERO|GFP_KERNEL);
	if (!ins) {
		printk("taes ERROR: failed to alloc ins\n");
		kfree(src);
		kfree(dst);
		return;
	}
	outs = kmalloc(npages*sizeof(char*), __GFP_ZERO|GFP_KERNEL);
	if (!outs) {
		printk("taes ERROR: failed to alloc outs\n");
		kfree(src);
		kfree(dst);
		kfree(ins);		
		return;
	}
	
	tfm = crypto_alloc_blkcipher(CIPHER, 0, 0);
	
	if (IS_ERR(tfm)) {
		printk("failed to load transform for %s: %ld\n", CIPHER,
			PTR_ERR(tfm));
		goto out;
	}
	desc.tfm = tfm;
	desc.flags = 0;
	
	ret = crypto_blkcipher_setkey(tfm, key, sizeof(key));
	if (ret) {
		printk("setkey() failed flags=%x\n",
				crypto_blkcipher_get_flags(tfm));
	 	goto out;
	}
	
	sg_init_table(src, npages);
	for (i=0; i<npages; i++) {
		buf = (void *)__get_free_page(GFP_KERNEL);
		if (!buf) {
			printk("taes ERROR: alloc free page error\n");
			goto free_err_pages;
		}
		ins[i] = buf;
		strcpy(buf, "this is a plain text!");
		sg_set_buf(src+i, buf, PAGE_SIZE);
		buf = (void *)__get_free_page(GFP_KERNEL);
		if (!buf) {
			printk("taes ERROR: alloc free page error\n");
			goto free_err_pages;
		}
		outs[i] = buf;
		sg_set_buf(dst+i, buf, PAGE_SIZE);
	}
	
	for (bs = MAX_BLK_SIZE; bs >= MIN_BLK_SIZE; bs>>=1) {
		struct timeval t0, t1;
		long int enc, dec;

		do_gettimeofday(&t0);
		for (j=0; j<TEST_TIMES; j++) {
			ret = crypto_blkcipher_encrypt(&desc, dst, src, bs);
			if (ret) {
				printk("taes ERROR: enc error\n");
				goto free_err_pages;
			}
		}
		do_gettimeofday(&t1);
		enc = 1000000*(t1.tv_sec-t0.tv_sec) + 
			((int)(t1.tv_usec) - (int)(t0.tv_usec));

		do_gettimeofday(&t0);
		for (j=0; j<TEST_TIMES; j++) {
			ret = crypto_blkcipher_decrypt(&desc, src, dst, bs);
			if (ret) {
				printk("taes ERROR: dec error\n");
				goto free_err_pages;
			}
		}
		do_gettimeofday(&t1);
		dec = 1000000*(t1.tv_sec-t0.tv_sec) + 
			((int)(t1.tv_usec) - (int)(t0.tv_usec));
		
		printk("Size %u, enc %ld, dec %ld\n",
			bs, enc, dec);
	}
	
	
free_err_pages:
	for (i=0; i<npages && ins[i]; i++){		
		free_page((unsigned long)ins[i]);
	}
	for (i=0; i<npages && outs[i]; i++){
		free_page((unsigned long)outs[i]);
	}
out:
	kfree(src);
	kfree(dst);
	kfree(ins);
	kfree(outs);
	crypto_free_blkcipher(tfm);	
}
Пример #12
0
/**
 * handle_enc_dec
 * @f: pointer to file_struct struct which has all the information about input, temporary and output files
 * @buf: data which has to be encrypted or decrypted
 * @n_bytes: number of bytes to be encrypted or decrypted
 * @key: key used for encryption or decryption
 * @flags: encrypt or decrypt to indicate the desired operation
 *
 * Encrypts or decrypts the data as per the flags parameter. Resultant encrypted or decrypted data is stored in buf.This data is written
 * to temporary file. For encryption, the encrypted data is written to temporary file. For decryption, the decrypted data is written to
 * temporary file.
 *
 * Returns zero on success; non-zero otherwise;
 */
int handle_enc_dec(struct file_struct *f, unsigned char *buf, int n_bytes, char *key, int flags)
{

	int err = 0, i, temp;
	struct crypto_blkcipher *blkcipher = NULL;
	unsigned char aes_key[AES_KEY_SIZE];

	unsigned char iv[AES_KEY_SIZE] = "\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11";

	struct scatterlist sg;
	struct blkcipher_desc desc;

	if (n_bytes%AES_KEY_SIZE != 0) {
		printk(KERN_ALERT"size not multiple of 16 for encryption\n");
		err = -EINVAL;
		goto ERR;
	}
	for (i = 0 ; i < AES_KEY_SIZE ; i++)
		aes_key[i] = key[i];
	blkcipher = crypto_alloc_blkcipher("cbc(aes)",  0, 0);
	if (IS_ERR(blkcipher)) {
		printk(KERN_ALERT"could not allocate blkcipher handle for %s\n", "cbsaes");
		err = PTR_ERR(blkcipher);
		goto ERR;
	}

	if (crypto_blkcipher_setkey(blkcipher, aes_key, AES_KEY_SIZE)) {
		printk(KERN_ALERT"key could not be set\n");
		err = -EAGAIN;
		goto ERR;
	}

	crypto_blkcipher_set_iv(blkcipher, iv, AES_KEY_SIZE);

	desc.flags = 0;
	desc.tfm = blkcipher;
	sg_init_one(&sg, buf, n_bytes);
	printk(KERN_ALERT"sg iinited\n");
	/* encrypt data in place */
	if (flags == 1) {
		crypto_blkcipher_encrypt(&desc, &sg, &sg, n_bytes);

		printk(KERN_ALERT"encryption done\n");
	} else {
		crypto_blkcipher_decrypt(&desc, &sg, &sg, n_bytes);
		printk(KERN_ALERT"Decryption done\n");
	}

	printk(KERN_ALERT"printing enc/dec data\n");
	printk(KERN_ALERT"Cipher operation completed\n");

	temp = write_to_file(f->filp_temp, buf, n_bytes);

	if (blkcipher)
		crypto_free_blkcipher(blkcipher);

	err = 0;

ERR:
	return err;
}
Пример #13
0
static int ceph_aes_encrypt(const void *key, int key_len,
			    void *dst, size_t *dst_len,
			    const void *src, size_t src_len)
{
	struct scatterlist sg_in[2], sg_out[1];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
	int ret;
	void *iv;
	int ivsize;
	size_t zero_padding = (0x10 - (src_len & 0x0f));
	char pad[16];

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	memset(pad, zero_padding, zero_padding);

	*dst_len = src_len + zero_padding;

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 2);
	sg_set_buf(&sg_in[0], src, src_len);
	sg_set_buf(&sg_in[1], pad, zero_padding);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_out, dst, *dst_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);
	/*
	print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
		       key, key_len, 1);
	print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
			src, src_len, 1);
	print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
			pad, zero_padding, 1);
	*/
	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
				     src_len + zero_padding);
	crypto_free_blkcipher(tfm);
	if (ret < 0)
		pr_err("ceph_aes_crypt failed %d\n", ret);
	/*
	print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
		       dst, *dst_len, 1);
	*/
	return 0;
}

static int ceph_aes_encrypt2(const void *key, int key_len, void *dst,
			     size_t *dst_len,
			     const void *src1, size_t src1_len,
			     const void *src2, size_t src2_len)
{
	struct scatterlist sg_in[3], sg_out[1];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
	int ret;
	void *iv;
	int ivsize;
	size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
	char pad[16];

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	memset(pad, zero_padding, zero_padding);

	*dst_len = src1_len + src2_len + zero_padding;

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 3);
	sg_set_buf(&sg_in[0], src1, src1_len);
	sg_set_buf(&sg_in[1], src2, src2_len);
	sg_set_buf(&sg_in[2], pad, zero_padding);
	sg_init_table(sg_out, 1);
	sg_set_buf(sg_out, dst, *dst_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);
	/*
	print_hex_dump(KERN_ERR, "enc  key: ", DUMP_PREFIX_NONE, 16, 1,
		       key, key_len, 1);
	print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
			src1, src1_len, 1);
	print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
			src2, src2_len, 1);
	print_hex_dump(KERN_ERR, "enc  pad: ", DUMP_PREFIX_NONE, 16, 1,
			pad, zero_padding, 1);
	*/
	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
				     src1_len + src2_len + zero_padding);
	crypto_free_blkcipher(tfm);
	if (ret < 0)
		pr_err("ceph_aes_crypt2 failed %d\n", ret);
	/*
	print_hex_dump(KERN_ERR, "enc  out: ", DUMP_PREFIX_NONE, 16, 1,
		       dst, *dst_len, 1);
	*/
	return 0;
}

static int ceph_aes_decrypt(const void *key, int key_len,
			    void *dst, size_t *dst_len,
			    const void *src, size_t src_len)
{
	struct scatterlist sg_in[1], sg_out[2];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm };
	char pad[16];
	void *iv;
	int ivsize;
	int ret;
	int last_byte;

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	sg_init_table(sg_in, 1);
	sg_init_table(sg_out, 2);
	sg_set_buf(sg_in, src, src_len);
	sg_set_buf(&sg_out[0], dst, *dst_len);
	sg_set_buf(&sg_out[1], pad, sizeof(pad));

	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);

	/*
	print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
		       key, key_len, 1);
	print_hex_dump(KERN_ERR, "dec  in: ", DUMP_PREFIX_NONE, 16, 1,
		       src, src_len, 1);
	*/

	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
	crypto_free_blkcipher(tfm);
	if (ret < 0) {
		pr_err("ceph_aes_decrypt failed %d\n", ret);
		return ret;
	}

	if (src_len <= *dst_len)
		last_byte = ((char *)dst)[src_len - 1];
	else
		last_byte = pad[src_len - *dst_len - 1];
	if (last_byte <= 16 && src_len >= last_byte) {
		*dst_len = src_len - last_byte;
	} else {
		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
		       last_byte, (int)src_len);
		return -EPERM;  /* bad padding */
	}
	/*
	print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
		       dst, *dst_len, 1);
	*/
	return 0;
}

static int ceph_aes_decrypt2(const void *key, int key_len,
			     void *dst1, size_t *dst1_len,
			     void *dst2, size_t *dst2_len,
			     const void *src, size_t src_len)
{
	struct scatterlist sg_in[1], sg_out[3];
	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
	struct blkcipher_desc desc = { .tfm = tfm };
	char pad[16];
	void *iv;
	int ivsize;
	int ret;
	int last_byte;

	if (IS_ERR(tfm))
		return PTR_ERR(tfm);

	sg_init_table(sg_in, 1);
	sg_set_buf(sg_in, src, src_len);
	sg_init_table(sg_out, 3);
	sg_set_buf(&sg_out[0], dst1, *dst1_len);
	sg_set_buf(&sg_out[1], dst2, *dst2_len);
	sg_set_buf(&sg_out[2], pad, sizeof(pad));

	crypto_blkcipher_setkey((void *)tfm, key, key_len);
	iv = crypto_blkcipher_crt(tfm)->iv;
	ivsize = crypto_blkcipher_ivsize(tfm);

	memcpy(iv, aes_iv, ivsize);

	/*
	print_hex_dump(KERN_ERR, "dec  key: ", DUMP_PREFIX_NONE, 16, 1,
		       key, key_len, 1);
	print_hex_dump(KERN_ERR, "dec   in: ", DUMP_PREFIX_NONE, 16, 1,
		       src, src_len, 1);
	*/

	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
	crypto_free_blkcipher(tfm);
	if (ret < 0) {
		pr_err("ceph_aes_decrypt failed %d\n", ret);
		return ret;
	}

	if (src_len <= *dst1_len)
		last_byte = ((char *)dst1)[src_len - 1];
	else if (src_len <= *dst1_len + *dst2_len)
		last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
	else
		last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
	if (last_byte <= 16 && src_len >= last_byte) {
		src_len -= last_byte;
	} else {
		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
		       last_byte, (int)src_len);
		return -EPERM;  /* bad padding */
	}

	if (src_len < *dst1_len) {
		*dst1_len = src_len;
		*dst2_len = 0;
	} else {
		*dst2_len = src_len - *dst1_len;
	}
	/*
	print_hex_dump(KERN_ERR, "dec  out1: ", DUMP_PREFIX_NONE, 16, 1,
		       dst1, *dst1_len, 1);
	print_hex_dump(KERN_ERR, "dec  out2: ", DUMP_PREFIX_NONE, 16, 1,
		       dst2, *dst2_len, 1);
	*/

	return 0;
}


int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		 const void *src, size_t src_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src_len)
			return -ERANGE;
		memcpy(dst, src, src_len);
		*dst_len = src_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_decrypt(secret->key, secret->len, dst,
					dst_len, src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_decrypt2(struct ceph_crypto_key *secret,
			void *dst1, size_t *dst1_len,
			void *dst2, size_t *dst2_len,
			const void *src, size_t src_len)
{
	size_t t;

	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst1_len + *dst2_len < src_len)
			return -ERANGE;
		t = min(*dst1_len, src_len);
		memcpy(dst1, src, t);
		*dst1_len = t;
		src += t;
		src_len -= t;
		if (src_len) {
			t = min(*dst2_len, src_len);
			memcpy(dst2, src, t);
			*dst2_len = t;
		}
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_decrypt2(secret->key, secret->len,
					 dst1, dst1_len, dst2, dst2_len,
					 src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		 const void *src, size_t src_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src_len)
			return -ERANGE;
		memcpy(dst, src, src_len);
		*dst_len = src_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_encrypt(secret->key, secret->len, dst,
					dst_len, src, src_len);

	default:
		return -EINVAL;
	}
}

int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
		  const void *src1, size_t src1_len,
		  const void *src2, size_t src2_len)
{
	switch (secret->type) {
	case CEPH_CRYPTO_NONE:
		if (*dst_len < src1_len + src2_len)
			return -ERANGE;
		memcpy(dst, src1, src1_len);
		memcpy(dst + src1_len, src2, src2_len);
		*dst_len = src1_len + src2_len;
		return 0;

	case CEPH_CRYPTO_AES:
		return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
					 src1, src1_len, src2, src2_len);

	default:
		return -EINVAL;
	}
}
Пример #14
0
/* 	
 *	Function definition for sys_xcrypt.
 *	This function encrypts/decrypts files using AES Block Cipher algorithm using CBC mode.
 */
asmlinkage int sys_xcrypt( const char * const infile, const char * const opfile, const char * const keybuf, const int keylen, const short int flags ) {
	const char algo[] = "cbc(aes)";
	char *ipBuf = NULL, *opBuf = NULL, *iv = NULL, *inFile = NULL, *opFile = NULL, *keyBuf = NULL;
	int errno = 0, ret = 0;
	int actReadLen = 0, actWriteLen = 0, padLen = 0, blkSiz = 0, ipFileLen = 0, opFileLen = 0, keyLen = 0;
	int delOpFile = 0, prmbLen = 0, idx = 0;
	unsigned int fileSize = 0, factor = 1;
	struct file *inFilePtr = NULL, *opFilePtr = NULL;
	struct crypto_blkcipher *tfm = NULL;
	struct blkcipher_desc desc;
	struct scatterlist sg[2];
	struct dentry *tmpDentry;
	struct inode *tmpInode = NULL;
	mm_segment_t oldfs;

	/* Check for NULL pointers or invalid values */
	if( ( NULL == infile ) || ( NULL == opfile ) || ( NULL == keybuf ) || ( ( _FLAG_ENCRYPT_ != flags ) && ( _FLAG_DECRYPT_ != flags ) ) ) {
		printk( KERN_ALERT "Invalid I/P" );
		errno = -EINVAL;
		goto OUT_OK;
	}

	/* Verify if all the pointers belong to the user's own address space */
	ret = access_ok( VERIFY_READ, infile, 0 );
	if( !ret ) {
		printk( KERN_ALERT "Invalid pointer to I/P file passed as argument" );
		errno = -EFAULT;
		goto OUT_OK;
	}

	ret = access_ok( VERIFY_READ, opfile, 0 );
	if( !ret ) {
		printk( KERN_ALERT "Invalid pointer to O/P file passed as argument" );
		errno = -EFAULT;
		goto OUT_OK;
	}

	ret = access_ok( VERIFY_READ, keybuf, 0 );
	if( !ret ) {
		printk( KERN_ALERT "Invalid pointer to Password passed as argument" );
		errno = -EFAULT;
		goto OUT_OK;
	}

	/* Find out the length of the i/p buffers */
	ipFileLen = strlen_user( infile );
	opFileLen = strlen_user( opfile );
	keyLen = strlen_user( keybuf );

	/* Allocate buffers to copy i/p arguments from user space to kernel space */
	inFile = kmalloc( ipFileLen, GFP_KERNEL );
	if( NULL == inFile ) {
		errno = -ENOMEM;
		goto OUT_OK;
	}
	else {
		ret = strncpy_from_user( inFile, infile, ipFileLen );
		if( ret < 0 ) {
			errno = ret;
			goto OUT_IP;
		}
	}
		
	opFile = kmalloc( opFileLen, GFP_KERNEL );
	if( NULL == opFile ) {
		errno = -ENOMEM;
		goto OUT_IP;
	}
	else {
		ret = strncpy_from_user( opFile, opfile, opFileLen );
		if( ret < 0 ) {
			errno = ret;
			goto OUT_IP;
		}
	}
		
	keyBuf = kmalloc( keyLen, GFP_KERNEL );
	if( NULL == keyBuf ) {
		errno = -ENOMEM;
		goto OUT_IP;
	}
	else {
		ret = strncpy_from_user( keyBuf, keybuf, keyLen );
		if( ret < 0 ) {
			errno = ret;
			goto OUT_IP;
		}
	}

	/* Open I/P file. It will report error in case of non-existing file and bad permissions but not bad owner */
	inFilePtr = filp_open( inFile, O_RDONLY, 0 );
	if ( !inFilePtr || IS_ERR( inFilePtr ) ) {
		errno = (int)PTR_ERR( inFilePtr );
		printk( KERN_ALERT "Error opening i/p file: %d\n", errno );
		inFilePtr = NULL;
		goto OUT_IP;
    	}

	/* Check if the file is a regular file or not */
	if( !S_ISREG( inFilePtr->f_path.dentry->d_inode->i_mode ) ) {
		printk( KERN_ALERT "Error as file is not a regular one" );
		errno = -EBADF;
		goto OUT_FILE;
	}

	/* Check if the I/p file and the process owner match */
	if( ( current->real_cred->uid != inFilePtr->f_path.dentry->d_inode->i_uid ) && ( current->real_cred->uid != 0 ) ) {
		printk( KERN_ALERT "Error as owner of file and process does not match" );
		errno = -EACCES;
		goto OUT_FILE;
	}

	/* Open O/P file with error handling */
	opFilePtr = filp_open( opFile, O_WRONLY | O_CREAT | O_EXCL, 0 );
	if ( !opFilePtr || IS_ERR( opFilePtr ) ) {
		errno = (int)PTR_ERR( opFilePtr );
		printk( KERN_ALERT "Error opening o/p file: %d\n", errno );
		opFilePtr = NULL;
		goto OUT_FILE;
	}

	/* 
	 * Check if the infile and opfile point to the same file
	 * If they reside on the different file partition and have same name then it should be allowed else not
	 */
	if( 	( inFilePtr->f_path.dentry->d_inode->i_sb == opFilePtr->f_path.dentry->d_inode->i_sb ) && 
		( inFilePtr->f_path.dentry->d_inode->i_ino ==  opFilePtr->f_path.dentry->d_inode->i_ino ) ) {
		printk( KERN_ALERT "I/p and O/p file cannot be same" );
		errno = -EINVAL;
		goto OUT_FILE;
	}

	/* Set the o/p file permission to i/p file */
	opFilePtr->f_path.dentry->d_inode->i_mode =  inFilePtr->f_path.dentry->d_inode->i_mode;
	
	/* Set the file position to the beginning of the file */
	inFilePtr->f_pos = 0;
	opFilePtr->f_pos = 0;

	/* Allocate buffer to read data into and to write data to. For performance reasons, set its size equal to PAGE_SIZE */
	ipBuf = kmalloc( PAGE_SIZE, GFP_KERNEL );
	if( NULL == ipBuf ) {
		errno = -ENOMEM;
		goto OUT_FILE;
	}
		
	memset( ipBuf, _NULL_CHAR_, PAGE_SIZE );

	opBuf = kmalloc( PAGE_SIZE, GFP_KERNEL );
	if( NULL == opBuf ) {
		errno = -ENOMEM;
		goto OUT_DATA_PAGE;
	}
		
	memset( opBuf, _NULL_CHAR_, PAGE_SIZE );

	/* Allocate tfm */
	tfm = crypto_alloc_blkcipher( algo, 0, CRYPTO_ALG_ASYNC );
	if ( NULL == tfm  ) {
		printk( KERN_ALERT "Failed to load transform for %s: %ld\n", algo, PTR_ERR( tfm ) );
		errno = -EINVAL;
		goto OUT_DATA_PAGE;
	}

	/* Initialize desc */
	desc.tfm = tfm;
	desc.flags = 0;

	ret = crypto_blkcipher_setkey( tfm, keybuf, keylen );
	if( ret ) {
		printk( "Setkey() failed. Flags=%x\n", crypto_blkcipher_get_flags( tfm ) );
		errno = -EINVAL;
		goto OUT_CIPHER;
	}

	/* Initialize sg structure */
	FILL_SG( &sg[0], ipBuf, PAGE_SIZE );
	FILL_SG( &sg[1], opBuf, PAGE_SIZE );

	/* Get the block size */
	blkSiz = ((tfm->base).__crt_alg)->cra_blocksize;

	/* Initialize IV */
	iv = kmalloc( blkSiz, GFP_KERNEL );
	if( NULL == iv ) {
		errno = -ENOMEM;
		goto OUT_CIPHER;
	}
		
	memset( iv, _NULL_CHAR_, blkSiz );
	crypto_blkcipher_set_iv( tfm, iv, crypto_blkcipher_ivsize( tfm ) );

	/* Store the key and file size in encrypted form in the preamble */
	switch( flags ) {
		case _FLAG_ENCRYPT_:
			memcpy( ipBuf, keybuf, keylen );
			prmbLen = keylen;
			fileSize = (unsigned int)inFilePtr->f_path.dentry->d_inode->i_size;

			while( fileSize ) {
				ipBuf[ prmbLen + idx ] = fileSize % 10;
				fileSize /= 10;
				++idx;
			}

			prmbLen += idx;

			#ifdef _DEBUG_
				printk( KERN_ALERT "idx=%d prmbLen=%d\n", idx, prmbLen );
			#endif

			memset( ipBuf + prmbLen, _ETX_, _UL_MAX_SIZE_ - idx );
			prmbLen += ( _UL_MAX_SIZE_ - idx );

			#ifdef _DEBUG_
				printk( KERN_ALERT "prmbLen=%d\n", prmbLen );
			#endif

			padLen = blkSiz - ( prmbLen % blkSiz );
			memset( ipBuf + prmbLen, _ETX_, padLen );
			prmbLen += padLen;
  
			#ifdef _DEBUG_
				printk( KERN_ALERT "padLen=%d prmbLen=%d\n", padLen, prmbLen );
			#endif

			ret = crypto_blkcipher_encrypt( &desc, &sg[1], &sg[0], prmbLen );
			if (ret) {
				printk( KERN_ALERT "Encryption failed. Flags=0x%x\n", tfm->base.crt_flags );
				delOpFile = 1;
				goto OUT_IV;
			}

			oldfs = get_fs();
			set_fs( KERNEL_DS );

			opFilePtr->f_op->write( opFilePtr, opBuf, prmbLen, &opFilePtr->f_pos );

			/* Reset the address space to user one */
			set_fs( oldfs );

			break;

		case _FLAG_DECRYPT_:
			/* Set the address space to kernel one */
			oldfs = get_fs();
			set_fs( KERNEL_DS );

			prmbLen = keylen + _UL_MAX_SIZE_;
			padLen = blkSiz - ( prmbLen % blkSiz );
			prmbLen += padLen;

			#ifdef _DEBUG_
				printk( KERN_ALERT "padLen=%d prmbLen=%d\n", padLen, prmbLen );
			#endif

			actReadLen = inFilePtr->f_op->read( inFilePtr, ipBuf, prmbLen, &inFilePtr->f_pos );
			if( actReadLen != prmbLen ) {
				printk( KERN_ALERT "Requested number of bytes for preamble are lesser" );
				delOpFile = 1;
				goto OUT_IV;
			}

			#ifdef _DEBUG_
				printk( KERN_ALERT "actReadLen=%d\n", actReadLen );
			#endif

			/* Reset the address space to user one */
			set_fs( oldfs );

			ret = crypto_blkcipher_decrypt( &desc, &sg[1], &sg[0], prmbLen );
			if (ret) {
				printk( KERN_ALERT "Decryption failed. Flags=0x%x\n", tfm->base.crt_flags );
				delOpFile = 1;
				goto OUT_IV;
			}

			ret = memcmp( keybuf, opBuf, keylen );
			if( ret ) {
				printk( "Wrong password entered." );
				errno = -EKEYREJECTED;
				goto OUT_IV;
			}

			idx = 0;
			fileSize = 0;

			while( opBuf[ keylen + idx ] != _ETX_ ) {
				fileSize += opBuf[ keylen + idx ] * factor;
				factor *= 10;
				++idx;
			}

			#ifdef _DEBUG_
				printk( KERN_ALERT "idx=%d fileSize=%u\n", idx, fileSize );
			#endif

			break;
	}

	/* Read file till the file pointer reaches to the EOF */
	while( inFilePtr->f_pos < inFilePtr->f_path.dentry->d_inode->i_size ) {
		/* Initialize it to NULL char */
		memset( ipBuf, _NULL_CHAR_, PAGE_SIZE );
		memset( opBuf, _NULL_CHAR_, PAGE_SIZE );

		/* Set the address space to kernel one */
		oldfs = get_fs();
		set_fs( KERNEL_DS );

		actReadLen = inFilePtr->f_op->read( inFilePtr, ipBuf, PAGE_SIZE, &inFilePtr->f_pos );

		/* Reset the address space to user one */
		set_fs( oldfs );

		/* As per the i/p flag, do encryption/decryption */
		switch( flags ) {
			case _FLAG_ENCRYPT_:
				/* For encryption ensure padding as per the block size */
				#ifdef _DEBUG_
					printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen );
				#endif

				if( actReadLen % blkSiz ) {
					padLen = blkSiz - ( actReadLen % blkSiz );
					memset( ipBuf + actReadLen, _ETX_, padLen );
					actReadLen += padLen;
				}

				#ifdef _DEBUG_
					printk( KERN_ALERT "Pad Length ::%d::\n", padLen );
					printk( KERN_ALERT "Data read from I/P file ::%s::\n", ipBuf );
				#endif

				/* Encrypt the data */
				ret = crypto_blkcipher_encrypt( &desc, &sg[1], &sg[0], PAGE_SIZE );
				if (ret) {
					printk( KERN_ALERT "Encryption failed. Flags=0x%x\n", tfm->base.crt_flags );
					delOpFile = 1;
					goto OUT_IV;
				}

				break;

			case _FLAG_DECRYPT_:
				/* Decrypt the data */
				ret = crypto_blkcipher_decrypt( &desc, &sg[1], &sg[0], PAGE_SIZE );
				if (ret) {
					printk( KERN_ALERT "Decryption failed. Flags=0x%x\n", tfm->base.crt_flags );
					delOpFile = 1;
					goto OUT_IV;
				}

				#ifdef _DEBUG_
					printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen );
				#endif

				while( _ETX_ == opBuf[ actReadLen - 1 ] ) {
					opBuf[ actReadLen - 1 ] = _NULL_CHAR_;
					--actReadLen;
				}

				#ifdef _DEBUG_
					printk( KERN_ALERT "Bytes read from I/P file ::%d::\n", actReadLen );
					printk( KERN_ALERT "Data read from I/P file ::%s::\n", opBuf );
				#endif


				break;
		}

		/*
		 * Start writing to the o/p file
		 * Set the address space to kernel one
		 */
		oldfs = get_fs();
		set_fs( KERNEL_DS );

		actWriteLen = opFilePtr->f_op->write( opFilePtr, opBuf, actReadLen, &opFilePtr->f_pos );

		/* Reset the address space to user one */
		set_fs( oldfs );

		#ifdef _DEBUG_
			printk( KERN_ALERT "Bytes written to O/P file ::%d::\n", actWriteLen );
		#endif
	}

	/* Free iv */
	OUT_IV:
		kfree( iv );
		iv = NULL;
		printk( KERN_ALERT "Memory for IV freed ..." );

	/* Free tfm */
	OUT_CIPHER:
		crypto_free_blkcipher( tfm );
		printk( KERN_ALERT "Encryption Transform freed ..." );

	/* Free i/p and o/p buffers */
	OUT_DATA_PAGE:
		if( ipBuf ) {
			kfree( ipBuf );
			ipBuf = NULL;
		}

		if( opBuf ) {
			kfree( opBuf );
			opBuf = NULL;
		}

		printk( KERN_ALERT "Memory for encrption/decryption freed ..." );

	/* Close any open files */
	OUT_FILE:
		if( inFilePtr ) {
			filp_close( inFilePtr, NULL );
			inFilePtr = NULL;
			printk( KERN_ALERT "I/p file closed ..." );
		}

		if( opFilePtr ) {
			filp_close( opFilePtr, NULL );
			opFilePtr = NULL;
			printk( KERN_ALERT "O/p file closed ..." );
		}

		if( delOpFile ) {
			opFilePtr = filp_open( opFile, O_WRONLY , 0 );
			if ( !opFilePtr || IS_ERR( opFilePtr ) ) {
				opFilePtr = NULL;
				goto OUT_IP;
			}

			tmpDentry = opFilePtr->f_path.dentry;
			tmpInode = tmpDentry->d_parent->d_inode;

			filp_close( opFilePtr, NULL );
			vfs_unlink( tmpInode, tmpDentry );
			printk( KERN_ALERT "O/p file deleted ..." );
		}

	OUT_IP:
		if( inFile ) {
			kfree( inFile );
			inFile = NULL;
		}

		if( opFile ) {
			kfree( opFile );
			opFile = NULL;
		}

		if( keyBuf ) {
			kfree( keyBuf );
			keyBuf = NULL;
		}

		printk( KERN_ALERT "Memory for I/P parameters freed ..." );

	/* Return final status */
	OUT_OK:
		printk( KERN_ALERT "Exiting function sys_xcrypt ..." );
		return errno;
}