Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
33
Добавлен:
16.04.2013
Размер:
38.55 Кб
Скачать
This library provides a (hopefully) universal interface to all kinds of
conventional- and public-key encryption and hash algorithms in an easy-to-use
manner. The library is divided into two parts:

1. Routines to query the library capabilities.
2. Routines to perform the en/decryption.

The library currently provides the following encryption algorithms and modes:

MDC/SHS CFB
DES ECB, CBC, CFB, OFB, PCBC
3DES ECB, CBC, CFB, OFB, PCBC
IDEA ECB, CBC, CFB, OFB, PCBC
RC2 ECB, CBC, CFB, OFB, PCBC
RC4
RC5 ECB, CBC, CFB, OFB, PCBC
SAFER ECB, CBC, CFB, OFB, PCBC
SAFER-SK ECB, CBC, CFB, OFB, PCBC
Blowfish ECB, CBC, CFB, OFB, PCBC
Blowfish-SK ECB, CBC, CFB, OFB, PCBC
RSA
DSS
MD4
MD5
SHA

Notes:

1. The Visual Basic interface hasn't been tested much. If someone could do
a Delphi interface and a VBX or OCX version that'd be nice.

2. A proper configure script with everything would be nice for Unix users.
Anyone want to create one of these?

3. Optimised asm implementations of some of the routines would be useful.
There are 80x86 and 68K asm routines included for IDEA and RC4, but I
haven't had time to tie them into the code yet. I have 386+ asm code for
SHA, but need to tie that in as well. Volunteers?

4. I have replaced the RSA/DSS code with stub functions because I haven't quite
finished the RSA code (it's mostly done, I just haven't had much time
recently). If anyone wants RSA/DSS functionality, let me know and I'll send
them the remaining code. I expect there's about a days work there getting
it all going.


Author Contact Information:

Peter Gutmann, pgut001@cs.auckland.ac.nz

There should eventually be a cryptlib home page, at the moment you can find
information about updates and the latest version at the bottom of the SFS
page, which is http://www.cs.auckland.ac.nz/~pgut001/sfs.html. The
cryptlib information is just before the "Related Information" section
towards the end of the page. Once the cryptlib page appears it'll be
reachable as http://www.cs.auckland.ac.nz/~pgut001/cryptlib.html


Requirements for a Standard Encryption Library
----------------------------------------------

- It should be idiot-proof.

It's quite difficult to implement insecure encryption using this code without
actually trying.

- It should provide extensive error checking.

Each parameter and function call is checked for errors before any actions are
performed, with error reporting down to the level of individual parameters.

- It should be portable.

The library is written entirely in ANSI C, with hooks for certain OS-specific
oddities such as Windows/OS/2 dynamic link libraries. The only external
routines used are ones from <string.h> and one call from <time.h>.

- It should be extendable.

The library provides the capability to add encryption capabilities at runtime
(currently only partially implemented, since the interface is somewhat messy
- you need to pass in about 15 parameters to do it).

- It should be free of silly restrictions.

See the usage conditions below.

- It should be buzzword-complete.

The library is written in C, but is basically laid out as a C++ class
library. It can work as a static library, a shared library, or a dynamic
link library. It'll even work with things like Visual Basic.


Usage Conditions
----------------

This software is distributed as copyrighted freeware, with copyrights on
individual encryption modules being held by the contributing authors. You are
free to use the code in any way you want, with the following restrictions:

- If you make any changes to the code, you should send a copy of the changes to
the author or authors to allow them to integrate the changes into the code.
This is to allow a central consistent version to be maintained.

- If you use the library as part of a product, you should offer a copy to the
authors of the library. This is to let the authors know that their work is
being usefully applied. You should also give the authors credit in your
software and/or documentation. This is to let others know that the authors
work is being usefully applied :-).

- Any commercial software you create with this code may not be merely a set or
subset of the encryption libraries, with or without minor added
functionality. In particular you can't sell the library (or any modified
form of it) as "your" encryption product. You can sell your own product
which utilizes the encryption library, but you can't charge for the library
itself or claim it as yours. This is to stop people adding their own
wrappers and selling it as "their" encryption product.

These terms are pretty much identical to the library GPL, which seem to be
about the least restrictive usage terms around apart from outright public
domain software.


Library Basics
--------------

Like the standard C file I/O libraries which work with FILE objects, this
library works with an opaque "encryption context" object of type CRYPT_CONTEXT.
To encrypt data, you create an encryption context, load a user key into it,
en/decrypt data, and destroy it when you've finished. This concept lends
itself to implementation either as a C++ class or as C routines. Throughout
this document all examples are given in C, translation to C++ is a simple step.

The overall library structure is as follows:

Library core Plug-in
modules
+---------------+------------+------------+
| | DES | Triple DES |
| +------------+------------+
| | MDC/SHS | IDEA |
| +------------+------------+
| | RC2 | RC4 |
| +------------+------------+
/ \ | Crypt | RC5 | SAFER |
User / ---- \ | +------------+------------+
Programs \ ---- / | Library | Blowfish |
\ / | +------------+------------+
| API | RSA | DSA |
| +------------+------------+
| | MD4 | MD5 |
| +------------+------------+
| | SHA |
| +------------+
| | Others |
+---------------+------------+

The library API serves as an interface to a range of plug-in encryption modules
which allow encryption algorithms to be added in a fairly transparent manner.
The standardised API allows any of the algorithms and modes supported by the
library to be used with a minimum of coding effort. As such the main function
of the library is to provide a standard, portable, easy-to-use interface
between the underlying encryption routines and the user software.


Portability
-----------

The library automatically takes care of endianness conversion to the form used
by the local system in a manner invisible to the end user. In the case of
public-key (PKC) algorithms which work with integers stored as multibyte
strings, the user can specify whether the strings are in big- or little-endian
order.

All code is plain ANSI C, with no machine or OS-specific functions or calls
being used.


Interfacing with the Library
----------------------------

All necessary constants, types, structures, and function prototypes are defined
in the crypt API header file capi.h. You need to include this file in each
module which uses the encryption library.

In addition in some environments you need to call the initLibrary() and
endLibrary() functions at the start and finish of your program. initLibrary()
initializes the library for use, and endLibrary() performs various cleanup
functions including automatic garbage collection of any encryption information
you may have forgotten to destroy. Where the encryption library is implemented
as a DLL, there is no need to call initLibrary() or endLibrary() as these are
called automatically by the operating system when the DLL is loaded and
unloaded (although if you do call them anyway you won't cause any harm).

To make the use of endLibrary() easier, you may want to use the C atexit()
function to have endLibrary() called automatically when your program exits.

Any use of the encryption library will then be as follows:

#include "capi.h"

initLibrary();

/* Use encryption library routines */

endLibrary();


Creating/Destroying Encryption Contexts
---------------------------------------

When you create an encryption context, you must specify the encryption
algorithm and mode you want to use for that context. The encryption algorithms
and modes are given in the library header file, and are updated along with the
library itself. For example, to create and destroy an encryption context for
DES in CBC mode, you would use the following code:

CRYPT_CONTEXT cryptContext;

initCryptContext( &cryptContext, CRYPT_ALGO_DES, CRYPT_MODE_CBC );

/* Perform en/decryption */

destroyCryptContext( cryptContext );

In the case of the public-key (PKC) algorithms the encryption mode is either
CRYPT_MODE_PUBKEY or CRYPT_MODE_PRIVKEY, depending on whether you want to
perform private-key or public-key operations within that encryption context.
For example to create and destroy an encryption context for checking an RSA
signature you would use the following code:

CRYPT_CONTEXT cryptContext;

initCryptContext( &cryptContext, CRYPT_ALGO_RSA, CRYPT_MODE_PUBKEY );

/* Perform signature check */

destroyCryptContext( cryptContext );

In the case of the hash algorithms the encryption mode is usually
CRYPT_MODE_NONE since the algorithms require no key, except for keyed hash
functions (MACs). For example to create and destroy an encryption context for
creating an MD5 hash of a message you would use the following code:

CRYPT_CONTEXT cryptContext;

initCryptContext( &cryptContext, CRYPT_ALGO_MD5, CRYPT_MODE_NONE );

/* Perform hash */

destroyCryptContext( cryptContext );

Note that the CRYPT_CONTEXT is passed to initCryptContext() by reference, as
initCryptContext() modifies it when it creates the encryption context. In all
other routines in the encryption library, CRYPT_CONTEXT is passed by value.

The initCryptContext() and destroyCryptContext() functions take care of issues
like initialization, memory management, and erasure of data after use.
Although you should try to call destroyCryptContext() for every
initCryptContext(), this is sometimes not possible, so the library performs
automatic garbage collection of any remaining encryption contexts when
endLibrary() is called.


Loading Keys into Encryption Contexts
-------------------------------------

Once an encryption context has been created, you need to load a key into it.
This is done with the loadCryptContext() function. For conventional-key
encryption, you would generally load the key directly into the context. For
example to load the key "Secret key" into the previously-created encryption
context you would use:

loadCryptContext( cryptContext, "Secret key", 10 );

Some hardware modules which enforce red/black separation will not allow
plaintext keys to pass across the library interface. In this case the key
parameter passed to loadCryptContext() will be a key selector or key encryption
key to be passed to the underlying hardware. For example to pass a key
selector to a key stored inside a DES hardware module you would use:

loadCryptContext( cryptContext, &keySelector, sizeof( keySelector ) );

For PKC encryption a key will typically have a number of components so you
can't load the key directly. Instead you load the key components into a
CRYPT_PKCINFO structure and then pass this to loadCryptContext():

loadCryptContext( cryptContext, &rsaKey, CRYPT_UNUSED );

More information on working with CRYPT_PKCINFO data structures is given below.

For conventional-key encryption contexts you can also load an IV into the
context, although for encryption you would usually leave this to the library to
perform automatically. To load an IV you would use:

loadIV( cryptContext, iv, ivSize );

To retrieve an IV which has been generated by the library you would use:

retrieveIV( cryptContext, iv );

loadIV() and retrieveIV() will return the error code CRYPT_NOTAVAIL for a PKC
encryption context to indicate that these operations are not available for
PKCs.

The hash algorithms usually don't require keys or IV's, and loadIV() and
retrieveIV() will return the error code CRYPT_NOTAVAIL for hash encryption
contexts.

The loadCryptContext(), loadIV(), and retrieveIV() functions take care of
issues like initialization, memory management, endianness conversion, and key
setup.

If you need to reserve space for conventional and PKC keys, IV's, and hash
values, you can use the CRYPT_MAX_KEYSIZE, CRYPT_MAX_PKCSIZE, CRYPT_MAX_IVSIZE,
and CRYPT_MAX_HASHSIZE defines to determine the mount of memory you need. No
key, IV, or hash value used by the library will ever need more storage than the
settings given in these defines.


Working with PKC Keys
---------------------

Since PKC keys have multiple components, you can't pass them directly to
loadCryptContext(). Instead, you load them into a CRYPT_PKCINFO structure and
then pass that to loadCryptContext(). There are several CRYPT_PKCINFO
structures, one for each type of PKC supported by the library. These have the
following members:

Structure CRYPT_PKCINFO_RSA (Rivest-Shamir-Adleman public-key encryption):

n Modulus
e Public exponent
d Private exponent
p Prime factor 1
q Prime factor 2
u Mult.inverse of q, mod p
e1 Private exponent 1 (PKCS)
e2 Private exponent 2 (PKCS)

Structure CRYPT_PKCINFO_DSS (Digital Signature Standard digital signatures):

p Prime modulus
q Prime divisor
x Public random integer
y Private random integer

The e1 and e2 components of CRYPT_PKCINFO_RSA may not be present in some keys.
The library will make use of them if they are present, but can also work
without them. Private-key operations may be marginally faster if these two
values are present.

The multibyte integer strings which make up PKC keys can be stored in either
big-endian or little-endian format. If the integer string is little-endian, it
will be stored in the format:

"xxxxxxxxxxxxxxx00000000000000000000000000000000000000"

(where "xxx" are the digits of the number). If the integer string is
big-endian, it will be stored in the format:

"00000000000000000000000000000000000000xxxxxxxxxxxxxxx"

For example the number "123456789" would be stored in little-endian format as:

"98765432100000000000000000000000000000000000000000000"

(with the least-significant digit stored first, going through to the
most-significant digit, and padded with zeroes to fill the number). In
big-endian format this is:

"00000000000000000000000000000000000000000000123456789"

Although the big-endian format makes more sense to humans, the little-endian
format is easier to work with for computers since a n-digit number will consist
of the first n bytes of the string, and operations on the number will usually
start from the least-significant digit and work up to the most significant
digit. In contrast working with big-endian numbers requires skipping an
arbitrary number of zero padding bytes and then working backwards from the
least-significant digit of the number.

Before you can use the CRYPT_PKCINFO structure, you need to initialise it with
initComponents(), which takes as parameter the endianness of the multibyte
integer strings which make up PKC keys, either CRYPT_COMPONENTS_LITTLENDIAN or
CRYPT_COMPONENTS_BIGENDIAN:

CRYPT_PKCINFO_RSA rsaKey;

initComponents( rsaKey, CRYPT_COMPONENTS_LITTLENDIAN );

Now you can initialise whatever parameters you need with the multibyte integer
strings used in PKC's by using setComponent(), specifying the integer length in
bits:

setComponent( rsaKey.n, modulus, 1024 );
setComponent( rsaKey.e, pubExponent, 17 );
setComponent( rsaKey.d, privExponent, 1024 );

You can now pass the result to loadCryptContext() as explained above. Once
you've finished working with the CRYPT_PKCINFO information, use
destroyComponents() to destroy the information:

destroyComponents( rsaKey );


Encrypting/Decrypting Data
--------------------------

Now that the encryption context and (if necessary) IV are set up, you're ready
to encrypt or decrypt data. To encrypt or decrypt a block of data you use:

encryptBuffer( cryptContext, buffer, length );

and:

decryptBuffer( cryptContext, buffer, length );

If a block encryption mode is being used, these functions will recognise a call
with length == 0 as a courtesy call to indicate that this is the last data
block and will take whatever special action is necessary for this case.

Hash algorithms don't actually encrypt the data being hashed and can be called
via encryptBuffer() or decryptBuffer(). They require a final call with length
== 0 as a courtesy call to indicate to the hash function that this is the last
data block and will take whatever special action is necessary for this case.
The hash value can be retrieved by calling queryContextInfo() to query the
encryption context information, as explained below. If you call
encryptBuffer() or decryptBuffer() after the final call with length == 0, the
fucntion will return CRYPT_COMPLETE to indicate that the hashing has completed
and cannot be continued.

If the encryption context doesn't support the operation you are trying to
perform (for example calling encryptBuffer() with a DSA public key), the
function will return CRYPT_NOTAVAIL to indicate that this functionality is not
available.

If the key loaded into an encryption context doesn't support the operation you
are trying to perform (for example calling decryptBuffer() with an encrypt-only
key), the function will return CRYPT_WRONGKEY to indicate that you can't
perform the requested operation with this type of key.


Extended Initialization
-----------------------

The initCryptContext() has a companion function initCryptContextEx() which may
be used to perform an extended, algorithm-specific initialisation. The second
parameter passed to the function is an algorithm-dependant structure used to
specify extra information to be used in the initalisation. Not all algorithms
will support extended initialisation parameters. If they are supported, the
structures have the name CRYPT_INFO_<algorithm_name>, and are laid out as
follows:

Structure CRYPT_INFO_MDCSHS:

/* The number of iterations used during the key setup process triggered
by a loadCryptContext() call. Using a high value (500 or more) will
greatly slow down password-guessing attacks by making the key setup
process painfully slow. Values in the range of 50-100 are recommended for
most systems */
int keySetupIterations;

Structure CRYPT_INFO_RC5:

/* The number of rounds of encryption. The default setting is 12 rounds */
int rounds;

Structure CRYPT_INFO_SAFER:

/* The number of rounds of encryption. The default settings are 6 rounds for
SAFER-K64, 8 rounds for SAFER-SK64, and 10 rounds for SAFER-K128 and
SAFER-SK128 */
int rounds;

/* Whether to use SAFER or SAFER-SK. The default is to use the original
algorithm SAFER. SAFER-SK is a version which improves the key schedule to
eliminate some possible weaknesses when SAFER is used as a keyed hash
function */
int useSaferSK;

Structure CRYPT_INFO_BLOWFISH:

/* The number of iterations used during the Blowfish-SK key setup process
triggered by a loadCryptContext() call. Using a high value (10 or more)
will greatly slow down password-guessing attacks by making the key setup
process painfully slow. Values in the range of 10-20 are recommended for
most systems */
int keySetupIterations;

/* Whether to use Blowfish or Blowfish-SK. The default is to use the
original algorithm Blowfish. Blowfish-SK is a version which improves the
key schedule to simplify the setup process, allow longer keys, and allow
the number of key setup iterations to be specified */
int useBlowfishSK;

You can specify that the default value for the algorithm and mode be loaded
into a field of the CRYPT_INFO_<algorithm_name> structure by setting it to the
constant CRYPT_USE_DEFAULT. The library will then set the field to the
appropriate value. For example to create a SAFER encryption context using the
improved SAFER-SK key schedule and with the standard number of rounds for
SAFER-SK, you would use:

CRYPT_INFO_SAFER cryptInfoEx;

cryptInfoEx.rounds = CRYPT_USE_DEFAULT;
cryptInfoEx.useSaferSK = TRUE;
initCryptContextEx( &cryptContext, cryptAlgo, cryptMode, &cryptInfoEx );


Error Checking
--------------

When the library is initialised, each of the built-in encryption algorithms
goes through a self-test procedure which checks the implementation using
standard test vectors and methods given with the algorithm specification
(typically FIPS publications, ANSI standards, or standard reference
implementations). This self-test is used to verify that each encryption
algorithm is performing as required.

Each function in the library performs extensive error checking (although
monitoring of error codes has been left out in the following code samples for
readability). The file TEST.C, included with the crypt library, includes
better error handling than the short examples below.

For functions which complete with no error, the library will return CRYPT_OK.
For functions which complete with some form of error internal to the library
itself, the library will return CRYPT_ERROR (this situation should never occur
and should be reported to the library authors).

Other errors are:

CRYPT_SELFTEST The encryption code or hardware has failed an internal
self-test. This code is returned if an attempt is made to
use the encryption module which failed the self-test.

CRYPT_BADPARM1... There is a problem with a parameter passed to a library
CRYPT_BADPARM15 function. The exact code depends on the parameter in
error. If the function cannot resolve the exact parameter
error type it will return CRYPT_BADPARM.

CRYPT_NOMEM There is not enough memory available to perform this
operation (generally the operation would be the creation of
an encryption context).

CRYPT_NOTINITED The encryption context you have tried to use hasn't been
initialised yet.

CRYPT_INITED The encryption context you have tried to initialise has
already been initialised previously.

CRYPT_NOALGO The requested encryption algorithm or mode is unavailable.
CRYPT_NOMODE

CRYPT_NOKEY The encryption key or IV hasn't been loaded into an
CRYPT_NOIV encryption context yet.

CRYPT_WRONGKEY The key used is of the wrong type for this operation (for
example an encrypt-only key being used for a decrypt
operation).
CRYPT_INCOMPLETE An operation which consists of multiple steps (such as a
message hash) is still in progress and requires further
steps before it can be regarded as having completed.

CRYPT_COMPLETE An operation which consists of multiple steps (such as a
message hash) is complete and cannot be continued.

CRYPT_ORPHAN There were were still encryption contexts allocated when
endLibrary() was called. This error type is not serious
since the library performs automatic garbage collection of
any orphaned encryption contexts, but may serve as a
warning that something is wrong in a user program.

The macros isStatusError() and isStatusOK() can be used to determine whether a
return value denotes an error condition, for example:

int status;

status = initCryptContext( &cryptInfo, CRYPT_ALGO_IDEA, CRYPT_MODE_CFB );
if( isStatusError( status ) )
/* Perform error processing */


Examples
--------

The following examples have had error checking removed for readability. See
the test code in TEST.C for an example with full error checking.

To encrypt a buffer using DES in CFB mode with the password 0x12345678ABCDEF
and an IV generated automatically by the library:

CRYPT_CONTEXT cryptContext;
BYTE key[] = { 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF };

/* Load the key, encrypt the buffer (the IV is automatically generated
if we don't specify one, it can be obtained with retrieveIV()), and
destroy the encryption context */
initCryptContext( &cryptContext, CRYPT_ALGO_DES, CRYPT_MODE_CFB );
loadCryptContext( cryptContext, key, sizeof( key ) );
encryptBuffer( cryptContext, buffer, length );
destroyCryptContext( cryptContext );

To hash an arbitrary-size passphrase down to the one used by a particular
cryptosystem (in this case triple DES) using MDC/SHS:

CRYPT_QUERY_INFO cryptQueryInfo;
CRYPT_CONTEXT cryptContext;
BYTE key[ CRYPT_MAX_KEYSIZE ];
int keySize, ivSize;

/* Find out how long we can make the key */
queryAlgoModeInformation( CRYPT_ALGO_3DES, CRYPT_MODE_CBC,
&cryptQueryInfo );
keySize = cryptQueryInfo->maxKeySize; /* Use all we can */
ivSize = cryptQueryInfo->ivSize;

/* Encrypt a null data block using a null IV with the passphrase as the
key. This works vaguely like the Unix password encryption except
that we don't have a salt (which would be the IV) */
memset( key, 0, keySize );
initCryptContext( &cryptContext, CRYPT_ALGO_MDCSHS, CRYPT_MODE_CFB );
loadCryptContext( cryptContext, passphrase, strlen( passphrase ) );
loadIV( cryptContext, key, ivSize );
encryptBuffer( cryptContext, key, keySize );
destroyCryptContext( cryptContext );

Note that this code uses the encryption library querying functions, which will
be explained in the next section of the documentation.

To hash an arbitrary-size passphrase down to the one used by a particular
cryptosystem (triple DES, as before) using MD5:

CRYPT_QUERY_INFO cryptQueryInfo;
CRYPT_CONTEXT cryptContext;
BYTE key[ CRYPT_MAX_KEYSIZE ];
int keySize;

/* Find out how long we can make the key */
queryAlgoModeInformation( CRYPT_ALGO_3DES, CRYPT_MODE_CBC,
&cryptQueryInfo );
keySize = cryptQueryInfo->maxKeySize; /* Use all we can */

/* Hash the user key with MD5 and query the encryption context to get the
final hash value */
initCryptContext( &cryptContext, CRYPT_ALGO_MD5, CRYPT_MODE_NONE );
encryptBuffer( cryptContext, passphrase, strlen( passphrase ) );
encryptBuffer( cryptContext, passphrase, 0 );
queryContextInformation( cryptContext, &cryptQueryInfo );
destroyCryptContext( cryptContext );

/* Use the hashed value of the passphrase as the key */
memcpy( key, cryptQueryInfo.hashValue, keySize );

Note that this code uses the encryption library querying functions, which will
be explained in the next section of the documentation.

To encrypt a file using triple DES in CBC mode with the key generated in the
previous example:

BOOLEAN firstTime = TRUE;

/* Load the previously-generated key */
initCryptContext( &cryptContext, CRYPT_ALGO_3DES, CRYPT_MODE_CBC );
loadCryptContext( cryptContext, key, keySize );

/* Copy the data across, encrypting as we go */
while( ( length = fread( buffer, 1, BUFSIZE, inFile ) ) != 0 )
{
/* Encrypt the data in the buffer */
encryptBuffer( cryptContext, buffer, length );

/* If it's the first block, retrieve the IV and prepend it to the
output data. Note the since we've let the library generate the
IV for us automatically, we can't retrieve it until after the first
encryptBuffer() call */
if( firstTime )
{
CRYPT_QUERY_INFO cryptQueryInfo;
BYTE iv[ CRYPT_MAX_IVSIZE ];
int ivSize;

/* Find out how long the IV we're using is */
queryContextInformation( cryptContext, &cryptQueryInfo );
ivSize = cryptQueryInfo->ivSize;

/* Retrieve the IV and write it to the output file */
retrieveIV( cryptContext, iv );
fwrite( iv, 1, ivSize, outFile );

firstTime = FALSE;
}

/* Write the encrypted data to the output file */
fwrite( buffer, 1, length, outFile );
}

/* Since CBC is a block cipher, we perform a courtesy close call to let
the encryption routines handle the last block */
encryptBuffer( cryptContext, buffer, 0 );

destroyCryptContext( cryptContext );

To decrypt the previously encrypted file with the key generated in the previous
example:

CRYPT_QUERY_INFO cryptQueryInfo;
BYTE iv[ CRYPT_MAX_IVSIZE ];
int ivSize;

/* Load the previously-generated key */
initCryptContext( &cryptContext, CRYPT_ALGO_3DES, CRYPT_MODE_CBC );
loadCryptContext( cryptContext, key, keySize );

/* Find out how long the IV we're using is */
queryContextInformation( &cryptContext, &cryptQueryInfo );
ivSize = cryptQueryInfo->ivSize;

/* Read the IV from the input file and load it into the encryption
context */
fread( iv, 1, ivSize, inFile );
loadIV( cryptContext, iv, ivSize );

/* Copy the data across, decrypting as we go */
while( ( length = fread( buffer, 1, BUFSIZE, inFile ) ) != 0 )
{
/* Encrypt the data in the buffer */
decryptBuffer( cryptContext, buffer, length );

/* Write the decrypted data to the output file */
fwrite( buffer, 1, length, outFile );
}

/* Since CBC mode implements a block cipher, we perform a courtesy close call
to let the encryption routines handle the last block */
decryptBuffer( cryptContext, buffer, 0 );

destroyCryptContext( cryptContext );

A longer usage example including proper error checking and with various other
test routines can be found in the file test.c included with the code.


Querying the Encryption Library Capabilities
--------------------------------------------

The previous examples showed the use of the queryAlgoModeInformation() and
queryContextInformation() calls to retrieve information about the
characteristics of a particular algorithm as implemented by the encryption
library. There are four such calls in total, of which two query the existence
of an implementation of an algorithm or an algorithm/mode combination, and two
return information about the implementation itself.

The library can be interrogated about the existence of a particular encryption
algorithm or algorithm and encryption mode combination with:

status = queryAlgoAvailability( algorithm );

or:

status = queryModeAvailability( algorithm, mode );

In addition to requesting information on the availability of an encryption
algorithm and mode, you can request extra information to be returned in a
CRYPT_QUERY_INFO structure with:

status = queryAlgoModeInformation( algorithm, mode, &cryptQueryInfo );

or

status = queryContextInformation( cryptContext, &cryptQueryInfo );

with the former being used to request information on a given algorithm/mode
combination and the latter being used to request information about the
current encryption context being used.

The CRYPT_QUERY_INFO structure contains the following fields:

/* The encryption algorithm, encryption mode, and general algorithm name
as an ASCII string */
CRYPT_ALGO cryptAlgo;
CRYPT_MODE cryptMode;
char *algoName;

/* The algorithm block size in bytes, the minimum, recommended, and
maximum key size in bytes, and the minimum, recommended, and maximum
IV size in bytes */
int blockSize;
int minKeySize;
int keySize;
int maxKeySize;
int minIVsize;
int ivSize;
int maxIVsize;

/* The algorithm speed relative to a block copy operation. This value
ranges from 1 ... CRYPT_MAX_SPEED, or CRYPT_ERROR if no speed rating is
available */
int speed;

/* The hash value (set to 0 if the encryption context isn't for a hash
algorithm) */
unsigned char *hashValue;


Algorithm-Specific Notes
------------------------

MDCSHS:

None

DES:
Triple DES:

loadCryptContext() will return a bad parameter code if the DES key parity is
wrong or if the key is a weak key (CRYPT_BADPARM2 in this case).

encryptBuffer() and decryptBuffer() will return a bad parameter code if the
encryption mode is ECB, CBC, or PCBC and the encrypted data length is not a
multiple of the block size (CRYPT_BADPARM3 in this case).

IDEA:

encryptBuffer() and decryptBuffer() will return a bad parameter code if the
encryption mode is ECB, CBC, or PCBC and the encrypted data length is not a
multiple of the block size (CRYPT_BADPARM3 in this case).

The IDEA algorithm is patented by Ascom Systec AG, CH-5506 Maegenwil,
Switzerland, ph. +41 64 56 59 45, email idea@ascom.ch, and cannot be used
commercially without a license. As of June 1995, the licensing terms were
120 SFr (about US$90) per user for 1-10 users, 80 Sfr (about US$60) per user
for 11-20 users, and 60 Sfr (about US$46) per user for 21-100 users.

RC2:
SAFER:
SAFER-SK:
Blowfish:
Blowfish-SK:

encryptBuffer() and decryptBuffer() will return a bad parameter code if the
encryption mode is ECB, CBC, or PCBC and the encrypted data length is not a
multiple of the block size (CRYPT_BADPARM3 in this case).

RC4:

None

RC5:

encryptBuffer() and decryptBuffer() will return a bad parameter code if the
encryption mode is ECB, CBC, or PCBC and the encrypted data length is not a
multiple of the block size (CRYPT_BADPARM3 in this case).

The RC5 algorithm is patented by RSA Data Security Inc. 100 Marine Parkway,
Redwoord City, California 94065, ph.+1 415 595-8782, fax +1 415 595-1873, and
cannot be used commercially without a license.


Plug-In Module Implementation
-----------------------------

These notes are rather brief since there is a lot of ground to cover, and the
easiest way to see what is required is to look at the crypt.c code and the way
it interfaces to the lib_XXX.c code, which may be regarded as standard
implementations of a plug-in module (the triple DES/IDEA/SAFER/Blowfish/RC2
modules are the best examples). Note that internally the library uses pointers
to CRYPT_INFO structures rather than the opaque CRYPT_CONTEXT cookies which
exist outside the libraries' security perimeter.

Basically, implementors must provide the following services in their plug-in
modules:

int selfTestFunction( void );

Perform a self-test on the encryption hardware/software module. This
function is called once before any other function is called.

int initFunction( CRYPT_INFO *cryptInfo );

Initialise the appropriate private CRYPT_INFO fields.

int initExFunction( CRYPT_INFO *cryptInfo, void *cryptInfoEx );

Initialiase the appropriate private CRYPT_INFO fields based on the extended
information given in the second parameter.

int endFunction( CRYPT_INFO *cryptInfo );

Clear the appropriate private CRYPT_INFO fields.

int initKeyFunction( CRYPT_INFO *cryptInfo );

Initialise the internal key based on the user key. Typically this might
perform one or more of the following:

Hash the user key down to the size of the key used by the algorithm

Perform some type of key schedule operation

Perform endianness conversion for the current operating environment

Load the key into external crypto hardware.

Perform a key selection in external hardware based on the specified key
selector.

For algorithms with asymmetric internal keys, both an encryption and a
decryption key will have to be generated, as a crypt context may be used for
encryption or decryption.

int initIVFunction( CRYPT_INFO *cryptInfo );

Initialise the IV. Typically this might perform one or more of the
following:

Perform endianness conversion for the current operating environment

Load the IV into external crypto hardware.

int encryptFunction( CRYPT_INFO *cryptInfo, void *buffer, int length );
int decryptFunction( CRYPT_INFO *cryptInfo, void *buffer, int length );

Encrypt/decrypt a block of data based on the algorithm and keying information
in CRYPT_INFO. Some algorithms may require special handling for the last
block (eg block truncation in CBC) so both routines should recognise a call
with length = 0 to indicate the end of the encrypted data block.


Acknowledgements
----------------

The DES and 3DES encryption code was contributed by Eric Young
<eay@psych.psy.uq.oz.au> and is part of his libdes package. The primary ftp
site for the full libdes is
ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/libdes-x.xx.tar.gz. libdes is now also
shipped with SSLeay. The primary site for this is
ftp://ftp.psy.uq.oz.au/pub/Crypto/SSL/SSLeay-x.xx.tar.gz.

The IDEA code was written by Colin Plumb.
Соседние файлы в папке cryptlib110