A while back, I reported that while I had been quite happy with Crypto++ 4.2, it didn't work on AMD64, and while I was able to convert to 5.2.1, the increase in module interdependencies pushed up the size of my product rpm by factor of three or four, which was unacceptable.  A number of people contacted me off list and asked to hear when I found a solution.

I'm a database guy with both a commercial product and an involvement in an open source database project.  Database systems often need DES for password managers, SHA for password encoding and manifests, PKCS for digital signatures and key exchange, and eventually AES for link encryption.

At the beginning of the crypto library audition process, I decided I needed a generic crypto API to mask the differences between the various library APIs.  The scheme I came up with is probably more interesting (and potentially important) than the library search itself, so I thought I would report it here.  At the end, I'll get back to the search results.

The API revolves around of the idea of a "transformation" that transforms data from one form to another.  The transform library is a set of polymorphic C++ classes that implement the abstract base class:
class Transform 
{
public:
    virtual unsigned int get (unsigned int bufferLength, UCHAR *buffer) = 0;
    virtual unsigned int getLength() = 0;
    virtual void reset() = 0;
};
The semantics are simple.  The method "getLength" returns a reliable upper bound of the final length.  The method "get" must return all available bytes up to the size of the given buffer, returning zero when no bytes are remaining.  The method "reset" prepares for another data cycle, resetting transient state but retaining keys and modes.

Each transformation is independent -- none knows the implementation of any other.  Transforms are designed to be daisy chained, each calling another transform for input data.  While all transforms export the same base API, they can be loosely grouped into source transforms (StringTransform, FileTransform, BlobTransform), encoders (Base64Transform, HexTransform, DESKeyTransform), and encrypting transforms (DESTransform, RSATransform, SHATransform, etc).  The main difference between the types are in their constructors, where source transforms get a character string or byte array, encoders get a source transform and an encode/decode flag, while encrypting transforms get a source transform and an encryption type or mode.  There are also a number of template transforms to aid the process of forming daisy chains.  The EncryptTransform, for sample, takes as template parameters the name of a source class, an encryption class, and an encoding class and is, in essence, a composite transform.  Encryption transforms general export ad hoc methods for key specification, usually as transforms.  These methods are necessarily outside of the base class.

A couple of examples:

StringTransform source ("Hello, world");
SHATransform hash(&source, 0);                  // no mode on SHA
HexTransform encode(&hash, true);
UCHAR asciiDigest [40];
int length = encode.get(sizeof(asciiDigest), asciiDigest);
or, the equivalent
EncryptTransform<StringTransform,SHATransform,HexTransform> trans ("Hello, world");
UCHAR asciiDigest [40];
int length = trans.get(sizeof(asciiDigest), asciiDigest);
A more complex example:
EncodeTransform<FileTransform,DESKeyTransform> key ("secret.key");
EncryptTransform<StringTransform,DESTransform,Base64Transform> encrypt (aString);
encrypt.encrypt.setKey(&key);
UCHAR buffer [512];
for (int len; len = encrypt.get(sizeof(buffer), buffer);)
    fwrite(buffer, 1, len, buffer, outputFile);
During the process of library implementation, I cut all of the crypto code in my commercial system over to transforms.  Among the benefits:
  1. Transform chains can be built at compile time with templates or at run time with procedural code.
  2. A transform chain has the same semantics as a single transform.
  3. Transforms hide data alignment and blocking size issues
  4. Transforms hide the granularity of the underlaying library
  5. The transform API is independent of the underlaying library API, so changing libraries should be a trivial task.
  6. Transforms are modular, so only ones required need be linked.
  7. The transform implementations are generally simple, modulo library complexity.
I'm not quite sure where to take the Transform library concept, but after a few more eyes and opinions have worked it over, it would sure make a nice de facto standard to crypto consumers.

As for the library search, there are a surprising number of crypto libraries out there.  Some were ruled by license, since I need a library embeddable in a commercial product.  Others were rules out by language (C or C++ is a requirements; Delphi need not apply).  The libraries I looked at in depth were:
  • Crypto++ (actually started here).  Upside: it works.  Downside: gigantic footprint, code is inscrutable, and documentation non-existent.
  • SSLeay.  Very low level API.  Written in "historical" C, so conversion to C++ would be a major problem as would taming it dynamic memory allocation for embedded use.  It also requires attribution in product documentation.  This isn't a disqualifier, but is a nuisance.
  • Netscape Security Services (NSS).  The download has 3,133 files.  I opened the box, looked in, closed the box, and ran.
  • LibTomCrypt.  Written in C with C++ conditionals.  Extremely modular.  Controlled by an explicit customization header and designed for embedding.  A couple of trivial problems converting to C++ porting to AMD64.  Superb documentation *and* internal comments.  And no templates.
For the time being, I've settled LibTomCrypt.  Performance isn't an issue for my usage, so I haven't compared performance.  His license is "The library is free for all purposes without any express guarantee it works.",Tom St Denis, [EMAIL PROTECTED], http://libtomcrypt.org.

If anyone is interesting in chatting about the Transform Library, please contact me here or off list.  If there is significant interest, I'll set up a list server.

Reply via email to