OpenSolaris_b135/common/net/wanboot/crypt/cbc.c

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/sysmacros.h>
#if defined(_KERNEL) && !defined(_BOOT)
#include <sys/systm.h>
#else
#include <strings.h>
#endif
#include "cbc.h"

#define	CBC_MAX_BLOCK_SIZE	64

static void
cbc_xorblock(uint8_t *lastp, uint8_t *thisp, int blocksize)
{
	uint32_t *this32p;
	uint32_t *last32p;
	int i;

	if (IS_P2ALIGNED(thisp, sizeof (uint32_t)) &&
	    IS_P2ALIGNED(lastp, sizeof (uint32_t)) &&
	    IS_P2ALIGNED(blocksize, sizeof (uint32_t))) {
		/* LINTED */
		this32p = (uint32_t *)thisp;
		/* LINTED */
		last32p = (uint32_t *)lastp;
		for (i = 0; i < blocksize; i += 4) {
			*this32p ^= *last32p;
			this32p++;
			last32p++;
		}
	} else {
		for (i = 0; i < blocksize; i++) {
			thisp[i] ^= lastp[i];
		}
	}
}

boolean_t
cbc_encrypt(cbc_handle_t *ch, uint8_t *data, size_t datalen,
	uint8_t *IV)
{
	uint8_t *lastp;
	uint8_t *thisp;
	size_t i;

	if (!IS_P2ALIGNED(datalen, ch->blocklen)) {
		return (B_FALSE);
	}

	thisp = data;
	lastp = IV;

	for (i = 0; i < datalen; i += ch->blocklen) {
		cbc_xorblock(lastp, thisp, ch->blocklen);
		/* Encrypt the current block. */
		ch->encrypt(ch->ks, thisp);
		lastp = thisp;
		thisp += ch->blocklen;
	}

	bcopy(lastp, IV, ch->blocklen);
	return (B_TRUE);
}

boolean_t
cbc_decrypt(cbc_handle_t *ch, uint8_t *data, size_t datalen,
	uint8_t *IV)
{
	uint8_t cbcblock[CBC_MAX_BLOCK_SIZE];
	uint8_t *lastp;
	uint8_t *thisp;
	size_t i;

	if (!IS_P2ALIGNED(datalen, ch->blocklen)) {
		return (B_FALSE);
	}

	thisp = data;
	lastp = IV;

	for (i = 0; i < datalen; i += ch->blocklen) {

		/* Copy the current ciphertext block. */
		bcopy(thisp, cbcblock, ch->blocklen);

		/* Decrypt the current block. */
		ch->decrypt(ch->ks, thisp);

		cbc_xorblock(lastp, thisp, ch->blocklen);

		/* Save the last ciphertext block. */
		bcopy(cbcblock, lastp, ch->blocklen);
		thisp += ch->blocklen;
	}

	return (B_TRUE);
}

void
cbc_makehandle(cbc_handle_t *ch, void *cookie, uint32_t keysize,
	uint32_t blocksize, uint32_t ivsize,
	void (*encrypt)(void *, uint8_t *),
	void (*decrypt)(void *, uint8_t *))
{
	ch->ks = cookie;
	ch->keylen = keysize;
	ch->blocklen = blocksize;
	ch->ivlen = ivsize;
	ch->encrypt = encrypt;
	ch->decrypt = decrypt;
}