crypto/data transformation registry in the kernel (was: DES code in the kernel)

Ian Goldberg (iang@cs.berkeley.edu)
Sat, 20 Jul 1996 09:54:35 -0700 (PDT)


-----BEGIN PGP SIGNED MESSAGE-----

>
> From: iang@cs.berkeley.edu (Ian Goldberg)
> Date: 17 Jul 1996 12:37:42 -0700
>
> I've made fixes to DES and IDEA so that they use CBC mode, with IV based on
> the block number.
>
> Could you make text descritpions of the encryption modes and IV
> generation algorithms available, so that people outside the U.S. can
> make these changes to the official kernel sources?
>
Good idea. I'll certainly put my changes up on an export-restricted site,
though.

This is what I have right now (possibly subject to change):

Key generation (this is done in losetup(8) and mount(8)):

DES:
get a pass phrase (with getpass()), feed it to SHA1
use the first 8 bytes as encryption-key, the next 8 as iv-key

IDEA:
get a pass phrase (with getpass()), feed it to SHA1
use the first 16 bytes as encryption-key
feed _all 20_ of the bytes you got from SHA1 back into SHA1
use the first 16 bytes as iv-key

Here's part of the comment in front of encryption:
/* Use DES CBC mode to transfer data between buffers, as follows:

If cmd == READ:
Decrypt the block pointed to by raw_buf (of size rawsize), and copy
size bytes, starting at byte offset, to loop_buf.
If cmd == WRITE:
Decrypt the block pointed to by raw_buf (of size rawsize), replace
size bytes, starting at byte offset, by the contents of loop_buf,
and encrypt the block, storing the result back in raw_buf.

These are actually implemented more efficiently than the above descriptions
would indicate. In the "usual" case of (offset == 0 && size == rawsize),
most of the code below is not executed.

The IV for the disk block is obtained by writing the block number as
an 8-byte big-endian value, and encrypting it with a constant key.
This prevents identical blocks from being encrypted indentically.

This routine should be independent of byte order, so encrypted files
and partitions should be readable across platforms.

This routine is identical to the corresponding one for IDEA, except
for the calls to the crypto itself. It is duplicated because the interface
to the crypto isn't the same (ugh).

This routine is the fault of Ian Goldberg <ian@cypherpunks.ca>.
Last update: 16 July 1996
*/
static int transfer_des(struct loop_device *lo, int cmd, char *raw_buf,
u32 rawsize, u32 offset, char *loop_buf, u32 size, u32 block)
{
/* blah blah blah */
}

That is,

o write the block number as an 8-byte big-endian value
o encrypt it using iv-key
o use the result as the IV for CBC encryption for the block

Blocks are 1K in size.

What I _want_ to do (maybe I'll start this afternoon...) is to have a general
data transformation facility in the kernel, for use by kernel routines and/or
modules. Each transformation would have an identifier (xform_id). A
"registry" would export

xform_register(xform_id, (*open_func)(), (*release_func)())
xform_unregister(xform_id)
xform_get_info(xform_id, &xform_info) (which would cause a call to open_func)
xform_release_info(&xform_info) (which would cause a call to release_func)

(do this so you can keep track of what xforms are in use, so you can unload
them, if they are modules)

Also have some way to enumerate the currently available xforms.

Part of xform_info would be:

struct {
u32 xform_id; /* Transformation ID */
char xform_name[XFORM_NAME_LEN];
/* A textual name for this transform, possibly to be
used by a /proc entry */
u32 in_bsize; /* Input block size; 0xffffffff if variable */
u32 out_bsize; /* Output block size; 0xffffffff if variable */
u32 (*create_param)(void *parambuf, u32 paramlen,
void *data, u32 datalen);
/* Use the data pointed to by "data" to create
parameters for the xform. This could be
strength of compression (gzip -9), or a key
for encryption, for example */
u32 (*xform[2])(void *parambuf, u32 paramlen, void *inblock, u32 inlen,
void *outblock, u32 outlen);
/* An array of two function pointers (is this systax
right?), one for transformation, one for
untransformation, which (un)transform inblock
to outblock. inlen must equal in_bsize if
in_bsize is not 0xffffffff, and similarly for
outlen. */
} xform_info;

Some sample xforms could be none, compression, stego, XOR, DES...
This should be a general data transformation registry, not just "hooks
to crypto".

You should be able to load a module which calls xform_register() upon
installation. When the registry does the callback on open_func, do
MOD_INC_USE_COUNT. When it calls back release_func, do MOD_DEC_USE_COUNT.

I haven't actually tried any of this yet, and would love to get suggestions.

- Ian

-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBMfEPGkZRiTErSPb1AQEHggQAv6TogI7acX7+ulaX1FNYAnf0rCdUINcY
cWeYi0jxrMILGyHMpafU7KCepLy7fLLL5aWMeXIzlnh6nYvw13DHow1oxhKPUM5s
5x4a2SP0ZiXx/Iinca06snSzIOTAvvCE1a7WmEWCtM0yr1UDEwIi8XGRzH2PXhul
PR57G4jcZaw=
=NlGl
-----END PGP SIGNATURE-----