
DOCUMENTATION FOR THE LINUX SECURITY DEVICE DRIVER

First, a manual page for the user level API:

------------------------------------------------------------

SECDEV(4)	Linux Programmer's Manual	SECDEV(3)

NAME
	secdev - Brecis MSP security device driver

SYNOPSIS

	#include <brecis/msp_sec.h>

	int secfd = open(SECDEV,0) ;

	sec_ioctl sparm ;

	ioctl(secfd, MSP_SEC_CTL, (void *) &sparm) ;

DESCRIPTON

	This is the interface to the Brecis MSP security device.  The
	device is able to perform DES and triple DES encryption and
	decryption, and MD5 or SHA1 hash functions.  In addtion, the
	ability to perform the HMAC hash, using either MD5 or SHA1, is
	provided.

	The application needs to pass the driver a sec_ioctl
	structure.  This structure contains the following members:

	unsigned int type;         /* DES, HASH, or HMAC operation? */
	unsigned int options;      /* options for the operation */

	unsigned char *srcaddr;    /* source buffer for operation */
	unsigned char *dstaddr;    /* destination buffer for operation */
	unsigned int buflen;       /* length of source buffer */
	unsigned int id;           /* for user's use, not touched by driver */

	unsigned int mode;         /* specific mode of operation */

	unsigned int ivhigh;       /* inital vector for DES operations */
	unsigned int ivlow;

	unsigned int desc_key1high; /* first key for DES and 3DES operations */
	unsigned int desc_key1low;
	unsigned int desc_key2high; /* second key for 3DES operations */
	unsigned int desc_key2low;
	unsigned int desc_key3high; /* third key for 3des operations */
	unsigned int desc_key3low;

	unsigned int chainvar[5];  /* chain variables for HASH operations */

	struct sec_cbuf *cbuflist; /* list of continuation buffers */
	unsigned int cbufcount;    /* number of continuation buffers */

	unsigned int status;       /* result of operation */


	This structure must be filled in and passed to the driver for
	each operation.  The driver may change any of the fields in
	this structure when called; you should treat all fields except
	the status field and the id field as undefined after making
	the ioctl call.  Specifically, all fields of the structure
	should be re-set to proper values for the particular operation
	before another call to the driver is made.

	If the operation is to be performed across multiple buffers,
	use an array of struct sec_cbuf (discussed below) to describe
	the buffers after the first one.  Place a pointer to this
	array in cbuflist, and indicate the number of additional
	buffers in cbufcount.

	The srcaddr field should point to the (first) buffer of source
	data for the operation.  The buflen field should be set to its
	length.

	For the current version of the driver, buflen must be less
	than or equal to 4088.  Longer bufers of data must be split up
	using the sec_cbuf structures.

	The dstaddr field should be set to the (first) buffer to store
	results for the operation.  For DES operations, this buffer
	MUST be the same size as the source buffer, and MAY point to
	the same buffer as srcaddr.  For HASH operations, this must
	point to a buffer of apropriate size for the results of the
	HASH operation (16 bytes for MD5, 20 bytes for SHA1).

	The id field is untouched by the driver, and may be used by
	the application for its own purposes.

	The type field should be one of MSP_SEC_DES, MSP_SEC_HASH, or
	MSP_SEC_HMAC.  The use of the remaining fields depends upon
	the type field, and is discussed in the appropriate section
	below.

DES AND TRIPLE DES OPERATIONS

	For DES and triple DES operations, the type filed is set to
	MSP_SEC_DES.

	No options are currently available for DES, and the options
	field must be set to 0.

	For DES operations, the following bits are or'ed together to
	fill in the mode field:

		DMC_MOD_ECB, DMC_MOD_CBC, or DMC_MOD_CFB: selects
		Electronic Codebook, Cipher Block Chaining, or Cipher
		Feedback modes of the DES algorithm, respectively.

		DMC_MOD_ENC or DMC_MOD_DEC: selects encryption or
		decryption of the given data.

	For Triple DES operations, the following bits are or'ed
	together to fill in the mode field:

		DMC_3DES: selects Triple DES operation (MUST be set
		for Triple DES)

		DMC_MOD_ECB, DMC_MOD_CBC, or DMC_MOD_CFB: selects
		Electronic Codebook, Cipher Block Chaining, or Cipher
		Feedback modes of the DES algorithm, respectively.

		DMC_K1_ENC or DMC_K1_DEC: selects encoding or decoding
		with the first key

		DMC_K2_ENC or DMC_K2_DEC: selects encoding or decoding
		with the second key

		DMC_K3_ENC or DMC_K3_DEC: selects encoding or decoding
		with the third key

	The ivhigh and ivlow fields should be set to the high and low
	32 bits (respecitvely) to be used for the DES oeperation.

	For single DES operation, desc_key1high and desc_key1low
	should be set to the high and low 32 bits (respectively) for
	the key.

	For Triple DES operation, all 6 of desc_key1high,
	desc_key1low, desc_key2high, desc_key2low, desc_key3high,
	and desc_key3low should be set to the corresponding parts of
	each key.

	The DES keys use the same space in the structure as the
	chainvars for HASH operations, so do NOT try to set the
	apparently unused chainvar fields in the structure when doing
	DES operations.

MD5 OR SHA1 HASH OPERATIONS

	For HASH operations, the type field is set to MSP_SEC_HASH.

	Both MD5 and SHA1 operate on 64 byte blocks, and data for
	their operation must be a multiple of 64 bytes in length.  If
	you want the driver to apply the standard padding operation to
	your data before performing the HASH operation, set
	MSP_SEC_DO_PADDING in the options field.  If this option is
	not set, your data must be a multiple of 64 bytes in length.

	For HASH oeprations, the following bits are or'ed together to
	fill in the mode field:

		HMC_MD5 or HMC_SHA1: selects whether the MD5 or SHA1
		hash algorithm will be used.

		HMC_CHAIN_DEFAULT or HMC_CRV: if set to
		HMC_CHAIN_DEFAULT, the algorithm's default initial
		values are used; if set to HMC_CRV, then the algorithm
		will use the values in the chainvar fields as initial
		values.

	If HMC_CRV is set in the mode field, set the chainvar fields
	to the desired initial values.  Use chainvar[0] through
	chainvar[3] for MD5 and chainvar[0] through chainvar[4] for
	SHA1.

HMAC OPERATIONS

	For HMAC operations, the type field is set to MSP_SEC_HMAC.
	Either MD5 or SHA1 hash algorithms can be used for HMAC.

	For HMAC, the options field should be set to 0.

	For HMAC oeprations, the following bits are or'ed together to
	fill in the mode field:

		HMC_MD5 or HMC_SHA1: selects whether the MD5 or SHA1
		hash algorithm will be used.

	The Key for the HMAC operation should be pointed to by the
	srcaddr field in the ioctl structure, and the data for the
	hmac operation must be supplied with sec_cbuf structures.

SEC_CBUF CONTINUATION BUFFERS

	The cbuf structure contains three fields of interest to the
	user:

	unsigned char *srcaddr;   /* source buffer for operation */
	unsigned char *dstaddr;   /* destination buffer for operation */
	unsigned int buflen;      /* length of source buffer */

	Like the buffer variables in the base ioctl description, for a
	DES operation each destination buffer must be the same length
	as the corresponding source buffer, and srcaddr and dstaddr
	are allowed to point to the same address.

EXAMPLES

    To perform a DES operation:

	sec_ioctl secparm ;

	/* fill in the security ioctl structure */
	/* to do a DES encryption */
	secparm.type = MSP_SEC_DES ;
	secparm.options = 0 ;
	secparm.cbufcount = 0 ;
	secparm.cbuflist = NULL ;
	secparm.buflen = 512 ;
	secparm.srcaddr = buf ;
	secparm.dstaddr = buf ;

	secparm.mode = DMC_3DES | DMC_MOD_ENC | DMC_MOD_CBC ;
	secparm.mode |= DMC_K1_ENC | DMC_K2_DEC | DMC_K3_ENC ;
	
	secparm.ivhigh = 0x01020304 ;
	secparm.ivlow  = 0xFEFDFCFB ;

	secparm.desc_key1low  = 0xCCDDAABB ;
	secparm.desc_key1high = 0xEE11FF22 ;
	secparm.desc_key2low  = 0xBA98FEDC ;
	secparm.desc_key2high = 0x32107654 ;
	secparm.desc_key3low  = 0xCCDDAABB ;
	secparm.desc_key3high = 0xEE11FF22 ;

	ioctl(fd, MSP_SEC_CTL, &secparm) ;

    To perform a hash operation, this time showing the use of
    continuation buffers:

	sec_ioctl secparm ;
	sec_cbuf  contbuf[1] ;

	secparm.type = MSP_SEC_HASH ;
	secparm.options = 0 ;
	secparm.cbufcount = 1 ;
	secparm.cbuflist  = &contbuf[0] ;
	secparm.buflen = strlen(secret) ;
	secparm.srcaddr = secret ;
	secparm.dstaddr = hash ;

	secparm.mode = HMC_SHA1 | HMC_CHAIN_DEFAULT ;

	contbuf[0].buflen = 512 ;
	contbuf[0].srcaddr = buf ;
	contbuf[0].dstaddr = hash ;

	ioctl(fd, MSP_SEC_CTL, &secparm) ;

____________________________________________________________


And now, additioal info on access from kernel space:

Kernel use of the driver requires including both <brecis/msp_sec.h> and
<brecis/msp_sec_kern.h>.  

Each context that will call the security driver must allocate a
msp_sec_context structure, and initialize it to all zeroes before
calling the security driver.  

You must ensure that any existing calls to the securith driver with a
particualr context structure return before another call to the driver
is made with that structure.  

In other words, you generally should not call the security driver from
interrupt level and task level with the same context structure.
Instead, allocate a separate context structure for interrupt level
operations.

Yes, this implies the security driver is designed so you CAN call it
from interrupt level.

[ The context structure is currently unused, but use IS planned for
when the driver is optimized and tuned further. ]

Instead of sec_ioctl and sec_cbuf structures, each portion of the
operation is represented by a sec_desc structure; a linked list of
sec_desc structures (linked with the next field of the structure)
represents the ioctl and cbufs of user space put together.

The sec_desc structure contains a sec_ioctl structure named ioctl.  In
the first sec_desc structure of the linked list, the ioctl structure
should be filled in identically to the way it would be filled in in
user space, with the exception of the cbuflist and cbufcount which
need not be set.

In subsequent sec_desc structures (if any), the srcaddr, dstaddr, and
buflen fields of the ioctl structure should be filled in.

Then, you simply call 

	msp_sec_ioctl_kernel(context, MSP_SEC_CTL, desc)

with the context structure as the first parameter, and the first
sec_desc structure of the linked list as the third parameter.

You are responsible for all memory management of context and sec_desc
structures.  Nothing will be freed by the driver.  You can allocate
your structures on the stack if space is available, or statically.

Examples:

    To perform a DES operation:

	sec_desc desc ;
	static msp_sec_context context ;

	/* fill in the security ioctl structure */
	/* to do a DES encryption */
	desc.ioctl.type = MSP_SEC_DES ;
	desc.ioctl.options = 0 ;
	desc.ioctl.buflen = 512 ;
	desc.ioctl.srcaddr = buf ;
	desc.ioctl.dstaddr = buf ;

	desc.ioctl.mode = DMC_3DES | DMC_MOD_ENC | DMC_MOD_CBC ;
	desc.ioctl.mode |= DMC_K1_ENC | DMC_K2_DEC | DMC_K3_ENC ;
	
	desc.ioctl.ivhigh = 0x01020304 ;
	desc.ioctl.ivlow  = 0xFEFDFCFB ;

	desc.ioctl.desc_key1low  = 0xCCDDAABB ;
	desc.ioctl.desc_key1high = 0xEE11FF22 ;
	desc.ioctl.desc_key2low  = 0xBA98FEDC ;
	desc.ioctl.desc_key2high = 0x32107654 ;
	desc.ioctl.desc_key3low  = 0xCCDDAABB ;
	desc.ioctl.desc_key3high = 0xEE11FF22 ;

	desc.next = 0 ;

	msp_sec_ioctl_kernel(&context, MSP_SEC_CTL, &desc) ;

    To perform a hash operation, this time showing the use of
    continuation buffers:

	sec_desc d1, d2 ;

	d1.ioctl.type = MSP_SEC_HASH ;
	d1.ioctl.options = 0 ;
	d1.ioctl.cbufcount = 1 ;
	d1.ioctl.cbuflist  = &contbuf[0] ;
	d1.ioctl.buflen = strlen(secret) ;
	d1.ioctl.srcaddr = secret ;
	d1.ioctl.dstaddr = hash ;

	d1.ioctl.mode = HMC_SHA1 | HMC_CHAIN_DEFAULT ;

	d1.next = &d2 ;

	d2.ioctl.buflen = 512 ;
	d2.ioctl.srcaddr = buf ;
	d2.ioctl.dstaddr = hash ;

	d2.next = 0 ;

	msp_sec_ioctl_kernel(&context, MSP_SEC_CTL, &d1) ;

